Benny Prijono | eb30bf5 | 2006-03-04 20:43:52 +0000 | [diff] [blame^] | 1 | /* Copyright (C) 2002 Jean-Marc Valin |
| 2 | File: speex_jitter.h |
| 3 | |
| 4 | Adaptive jitter buffer for Speex |
| 5 | |
| 6 | Redistribution and use in source and binary forms, with or without |
| 7 | modification, are permitted provided that the following conditions |
| 8 | are met: |
| 9 | |
| 10 | - Redistributions of source code must retain the above copyright |
| 11 | notice, this list of conditions and the following disclaimer. |
| 12 | |
| 13 | - Redistributions in binary form must reproduce the above copyright |
| 14 | notice, this list of conditions and the following disclaimer in the |
| 15 | documentation and/or other materials provided with the distribution. |
| 16 | |
| 17 | - Neither the name of the Xiph.org Foundation nor the names of its |
| 18 | contributors may be used to endorse or promote products derived from |
| 19 | this software without specific prior written permission. |
| 20 | |
| 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 22 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 24 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR |
| 25 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 26 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 27 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| 28 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| 29 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| 30 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 31 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 32 | |
| 33 | */ |
| 34 | |
| 35 | #ifdef HAVE_CONFIG_H |
| 36 | #include "config.h" |
| 37 | #endif |
| 38 | |
| 39 | #ifndef NULL |
| 40 | #define NULL 0 |
| 41 | #endif |
| 42 | |
| 43 | #include "misc.h" |
| 44 | #include <speex/speex.h> |
| 45 | #include <speex/speex_bits.h> |
| 46 | #include <speex/speex_jitter.h> |
| 47 | #include <stdio.h> |
| 48 | |
| 49 | #define LATE_BINS 4 |
| 50 | |
| 51 | void speex_jitter_init(SpeexJitter *jitter, void *decoder, int sampling_rate) |
| 52 | { |
| 53 | int i; |
| 54 | for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) |
| 55 | { |
| 56 | jitter->len[i]=-1; |
| 57 | jitter->timestamp[i]=-1; |
| 58 | } |
| 59 | |
| 60 | jitter->dec = decoder; |
| 61 | speex_decoder_ctl(decoder, SPEEX_GET_FRAME_SIZE, &jitter->frame_size); |
| 62 | jitter->frame_time = jitter->frame_size; |
| 63 | |
| 64 | speex_bits_init(&jitter->current_packet); |
| 65 | jitter->valid_bits = 0; |
| 66 | |
| 67 | jitter->buffer_size = 4; |
| 68 | |
| 69 | jitter->pointer_timestamp = -jitter->frame_time * jitter->buffer_size; |
| 70 | jitter->reset_state = 1; |
| 71 | jitter->lost_count = 0; |
| 72 | jitter->loss_rate = 0; |
| 73 | } |
| 74 | |
| 75 | void speex_jitter_destroy(SpeexJitter *jitter) |
| 76 | { |
| 77 | speex_bits_destroy(&jitter->current_packet); |
| 78 | } |
| 79 | |
| 80 | |
| 81 | void speex_jitter_put(SpeexJitter *jitter, char *packet, int len, int timestamp) |
| 82 | { |
| 83 | int i,j; |
| 84 | int arrival_margin; |
| 85 | |
| 86 | if (jitter->reset_state) |
| 87 | { |
| 88 | jitter->reset_state=0; |
| 89 | jitter->pointer_timestamp = timestamp-jitter->frame_time * jitter->buffer_size; |
| 90 | for (i=0;i<MAX_MARGIN;i++) |
| 91 | { |
| 92 | jitter->shortterm_margin[i] = 0; |
| 93 | jitter->longterm_margin[i] = 0; |
| 94 | } |
| 95 | for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) |
| 96 | { |
| 97 | jitter->len[i]=-1; |
| 98 | jitter->timestamp[i]=-1; |
| 99 | } |
| 100 | fprintf(stderr, "reset to %d\n", timestamp); |
| 101 | } |
| 102 | |
| 103 | /* Cleanup buffer (remove old packets that weren't played) */ |
| 104 | for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) |
| 105 | { |
| 106 | if (jitter->timestamp[i]<jitter->pointer_timestamp) |
| 107 | { |
| 108 | jitter->len[i]=-1; |
| 109 | /*if (jitter->timestamp[i] != -1) |
| 110 | fprintf (stderr, "discarding %d %d\n", jitter->timestamp[i], jitter->pointer_timestamp);*/ |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | /*Find an empty slot in the buffer*/ |
| 115 | for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) |
| 116 | { |
| 117 | if (jitter->len[i]==-1) |
| 118 | break; |
| 119 | } |
| 120 | |
| 121 | /*fprintf(stderr, "%d %d %f\n", timestamp, jitter->pointer_timestamp, jitter->drift_average);*/ |
| 122 | if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) |
| 123 | { |
| 124 | int earliest=jitter->timestamp[0]; |
| 125 | i=0; |
| 126 | for (j=1;j<SPEEX_JITTER_MAX_BUFFER_SIZE;j++) |
| 127 | { |
| 128 | if (jitter->timestamp[j]<earliest) |
| 129 | { |
| 130 | earliest = jitter->timestamp[j]; |
| 131 | i=j; |
| 132 | } |
| 133 | } |
| 134 | /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/ |
| 135 | /*No place left in the buffer*/ |
| 136 | |
| 137 | /*skip some frame(s) */ |
| 138 | /*return;*/ |
| 139 | } |
| 140 | |
| 141 | /* Copy packet in buffer */ |
| 142 | if (len>SPEEX_JITTER_MAX_PACKET_SIZE) |
| 143 | len=SPEEX_JITTER_MAX_PACKET_SIZE; |
| 144 | for (j=0;j<len/BYTES_PER_CHAR;j++) |
| 145 | jitter->buf[i][j]=packet[j]; |
| 146 | jitter->timestamp[i]=timestamp; |
| 147 | jitter->len[i]=len; |
| 148 | |
| 149 | /* Don't count late packets when adjusting the synchro (we're taking care of them elsewhere) */ |
| 150 | /*if (timestamp <= jitter->pointer_timestamp) |
| 151 | { |
| 152 | fprintf (stderr, "frame for timestamp %d arrived too late (at time %d)\n", timestamp, jitter->pointer_timestamp); |
| 153 | }*/ |
| 154 | |
| 155 | /* Adjust the buffer size depending on network conditions */ |
| 156 | arrival_margin = (timestamp - jitter->pointer_timestamp - jitter->frame_time); |
| 157 | |
| 158 | if (arrival_margin >= -LATE_BINS*jitter->frame_time) |
| 159 | { |
| 160 | int int_margin; |
| 161 | for (i=0;i<MAX_MARGIN;i++) |
| 162 | { |
| 163 | jitter->shortterm_margin[i] *= .98; |
| 164 | jitter->longterm_margin[i] *= .995; |
| 165 | } |
| 166 | int_margin = (arrival_margin + LATE_BINS*jitter->frame_time)/jitter->frame_time; |
| 167 | if (int_margin>MAX_MARGIN-1) |
| 168 | int_margin = MAX_MARGIN-1; |
| 169 | if (int_margin>=0) |
| 170 | { |
| 171 | jitter->shortterm_margin[int_margin] += .02; |
| 172 | jitter->longterm_margin[int_margin] += .005; |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | /*fprintf (stderr, "margin : %d %d %f %f %f %f\n", arrival_margin, jitter->buffer_size, 100*jitter->loss_rate, 100*jitter->late_ratio, 100*jitter->ontime_ratio, 100*jitter->early_ratio);*/ |
| 177 | } |
| 178 | |
| 179 | void speex_jitter_get(SpeexJitter *jitter, short *out, int *current_timestamp) |
| 180 | { |
| 181 | int i; |
| 182 | int ret; |
| 183 | float late_ratio_short; |
| 184 | float late_ratio_long; |
| 185 | float ontime_ratio_short; |
| 186 | float ontime_ratio_long; |
| 187 | float early_ratio_short; |
| 188 | float early_ratio_long; |
| 189 | |
| 190 | late_ratio_short = 0; |
| 191 | late_ratio_long = 0; |
| 192 | for (i=0;i<LATE_BINS;i++) |
| 193 | { |
| 194 | late_ratio_short += jitter->shortterm_margin[i]; |
| 195 | late_ratio_long += jitter->longterm_margin[i]; |
| 196 | } |
| 197 | ontime_ratio_short = jitter->shortterm_margin[LATE_BINS]; |
| 198 | ontime_ratio_long = jitter->longterm_margin[LATE_BINS]; |
| 199 | early_ratio_short = early_ratio_long = 0; |
| 200 | for (i=LATE_BINS+1;i<MAX_MARGIN;i++) |
| 201 | { |
| 202 | early_ratio_short += jitter->shortterm_margin[i]; |
| 203 | early_ratio_long += jitter->longterm_margin[i]; |
| 204 | } |
| 205 | if (0&&jitter->pointer_timestamp%1000==0) |
| 206 | { |
| 207 | fprintf (stderr, "%f %f %f %f %f %f\n", early_ratio_short, early_ratio_long, ontime_ratio_short, ontime_ratio_long, late_ratio_short, late_ratio_long); |
| 208 | /*fprintf (stderr, "%f %f\n", early_ratio_short + ontime_ratio_short + late_ratio_short, early_ratio_long + ontime_ratio_long + late_ratio_long);*/ |
| 209 | } |
| 210 | |
| 211 | if (late_ratio_short > .1 || late_ratio_long > .03) |
| 212 | { |
| 213 | jitter->shortterm_margin[MAX_MARGIN-1] += jitter->shortterm_margin[MAX_MARGIN-2]; |
| 214 | jitter->longterm_margin[MAX_MARGIN-1] += jitter->longterm_margin[MAX_MARGIN-2]; |
| 215 | for (i=MAX_MARGIN-3;i>=0;i--) |
| 216 | { |
| 217 | jitter->shortterm_margin[i+1] = jitter->shortterm_margin[i]; |
| 218 | jitter->longterm_margin[i+1] = jitter->longterm_margin[i]; |
| 219 | } |
| 220 | jitter->shortterm_margin[0] = 0; |
| 221 | jitter->longterm_margin[0] = 0; |
| 222 | /*fprintf (stderr, "interpolate frame\n");*/ |
| 223 | speex_decode_int(jitter->dec, NULL, out); |
| 224 | if (current_timestamp) |
| 225 | *current_timestamp = jitter->pointer_timestamp; |
| 226 | return; |
| 227 | } |
| 228 | |
| 229 | /* Increment timestamp */ |
| 230 | jitter->pointer_timestamp += jitter->frame_time; |
| 231 | |
| 232 | if (late_ratio_short + ontime_ratio_short < .005 && late_ratio_long + ontime_ratio_long < .01 && early_ratio_short > .8) |
| 233 | { |
| 234 | jitter->shortterm_margin[0] += jitter->shortterm_margin[1]; |
| 235 | jitter->longterm_margin[0] += jitter->longterm_margin[1]; |
| 236 | for (i=1;i<MAX_MARGIN-1;i++) |
| 237 | { |
| 238 | jitter->shortterm_margin[i] = jitter->shortterm_margin[i+1]; |
| 239 | jitter->longterm_margin[i] = jitter->longterm_margin[i+1]; |
| 240 | } |
| 241 | jitter->shortterm_margin[MAX_MARGIN-1] = 0; |
| 242 | jitter->longterm_margin[MAX_MARGIN-1] = 0; |
| 243 | /*fprintf (stderr, "drop frame\n");*/ |
| 244 | jitter->pointer_timestamp += jitter->frame_time; |
| 245 | } |
| 246 | |
| 247 | if (current_timestamp) |
| 248 | *current_timestamp = jitter->pointer_timestamp; |
| 249 | |
| 250 | /* Send zeros while we fill in the buffer */ |
| 251 | if (jitter->pointer_timestamp<0) |
| 252 | { |
| 253 | for (i=0;i<jitter->frame_size;i++) |
| 254 | out[i]=0; |
| 255 | return; |
| 256 | } |
| 257 | |
| 258 | /* Search the buffer for a packet with the right timestamp */ |
| 259 | for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) |
| 260 | { |
| 261 | if (jitter->len[i]!=-1 && jitter->timestamp[i]==jitter->pointer_timestamp) |
| 262 | break; |
| 263 | } |
| 264 | |
| 265 | if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) |
| 266 | { |
| 267 | /* No packet found */ |
| 268 | if (jitter->valid_bits) |
| 269 | { |
| 270 | /* Try decoding last received packet */ |
| 271 | ret = speex_decode_int(jitter->dec, &jitter->current_packet, out); |
| 272 | if (ret == 0) |
| 273 | { |
| 274 | jitter->lost_count = 0; |
| 275 | return; |
| 276 | } else { |
| 277 | jitter->valid_bits = 0; |
| 278 | } |
| 279 | } |
| 280 | |
| 281 | /*fprintf (stderr, "lost/late frame %d\n", jitter->pointer_timestamp);*/ |
| 282 | /*Packet is late or lost*/ |
| 283 | speex_decode_int(jitter->dec, NULL, out); |
| 284 | jitter->lost_count++; |
| 285 | if (jitter->lost_count>=25) |
| 286 | { |
| 287 | jitter->lost_count = 0; |
| 288 | jitter->reset_state = 1; |
| 289 | speex_decoder_ctl(jitter->dec, SPEEX_RESET_STATE, NULL); |
| 290 | } |
| 291 | jitter->loss_rate = .999*jitter->loss_rate + .001; |
| 292 | } else { |
| 293 | jitter->lost_count = 0; |
| 294 | /* Found the right packet */ |
| 295 | speex_bits_read_from(&jitter->current_packet, jitter->buf[i], jitter->len[i]); |
| 296 | jitter->len[i]=-1; |
| 297 | /* Decode packet */ |
| 298 | ret = speex_decode_int(jitter->dec, &jitter->current_packet, out); |
| 299 | if (ret == 0) |
| 300 | { |
| 301 | jitter->valid_bits = 1; |
| 302 | } else { |
| 303 | /* Error while decoding */ |
| 304 | for (i=0;i<jitter->frame_size;i++) |
| 305 | out[i]=0; |
| 306 | } |
| 307 | jitter->loss_rate = .999*jitter->loss_rate; |
| 308 | } |
| 309 | |
| 310 | |
| 311 | } |
| 312 | |
| 313 | int speex_jitter_get_pointer_timestamp(SpeexJitter *jitter) |
| 314 | { |
| 315 | return jitter->pointer_timestamp; |
| 316 | } |