Adaptive (though not yet) jitter buffer.
git-svn-id: http://svn.xiph.org/trunk/speex@5191 0101bb08-14d6-0310-b084-bc0e0c8e3800
diff --git a/libspeex/jitter.c b/libspeex/jitter.c
new file mode 100644
index 0000000..7d21d1c
--- /dev/null
+++ b/libspeex/jitter.c
@@ -0,0 +1,201 @@
+/* Copyright (C) 2002 Jean-Marc Valin
+ File: speex_jitter.h
+
+ Adaptive jitter buffer for Speex
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ - Neither the name of the Xiph.org Foundation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include <stdlib.h>
+#include "speex.h"
+#include "speex_bits.h"
+#include "speex_jitter.h"
+
+#include <stdio.h>
+
+void speex_jitter_init(SpeexJitter *jitter, void *decoder, int sampling_rate)
+{
+ int i;
+ for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
+ {
+ jitter->len[i]=-1;
+ jitter->timestamp[i]=-1;
+ }
+
+ jitter->dec = decoder;
+ speex_decoder_ctl(decoder, SPEEX_GET_FRAME_SIZE, &jitter->frame_size);
+ jitter->frame_time = 1000*jitter->frame_size / sampling_rate;
+
+ speex_bits_init(&jitter->current_packet);
+ jitter->valid_bits = 0;
+
+ jitter->buffer_size = 10;
+
+ jitter->pointer_timestamp = -jitter->frame_time * jitter->buffer_size;
+
+ jitter->underflow_count = 0;
+ jitter->drop_frame = 0;
+ jitter->interp_frame = 0;
+}
+
+void speex_jitter_destroy(SpeexJitter *jitter)
+{
+}
+
+
+void speex_jitter_put(SpeexJitter *jitter, char *packet, int len, int timestamp)
+{
+ int i,j;
+
+ fprintf (stderr, "in\n");
+ /* Cleanup buffer (remove old packets that weren't played) */
+ for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
+ {
+ if (jitter->timestamp[i]<jitter->pointer_timestamp)
+ jitter->len[i]=-1;
+ }
+
+ /*Find an empty slot in the buffer*/
+ for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
+ {
+ if (jitter->len[i]==-1)
+ break;
+ }
+
+ if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
+ {
+ /*No place left in the buffer*/
+
+ /*skip some frame(s) */
+ return;
+ }
+
+ /* Copy packet in buffer */
+ if (len>SPEEX_JITTER_MAX_PACKET_SIZE)
+ len=SPEEX_JITTER_MAX_PACKET_SIZE;
+ for (j=0;j<len;j++)
+ jitter->buf[i][j]=packet[j];
+ jitter->timestamp[i]=timestamp;
+ jitter->len[i]=len;
+
+ /* Detect when it's time to drop frames (too much stuff in buffer) */
+ if (timestamp-jitter->pointer_timestamp > (jitter->buffer_size+3)*jitter->frame_time)
+ jitter->drop_frame = 1;
+
+ /*Detect when it's time to interpolate a frame (not wnough stuff in buffer) */
+ if (timestamp-jitter->pointer_timestamp < (jitter->buffer_size-3)*jitter->frame_time)
+ jitter->underflow_count++;
+ else
+ jitter->underflow_count=0;
+ if (jitter->underflow_count > 10)
+ {
+ jitter->underflow_count=0;
+ jitter->interp_frame = 1;
+ }
+
+ /* Adjust the buffer size depending on network conditions */
+}
+
+void speex_jitter_get(SpeexJitter *jitter, float *out)
+{
+ int i;
+ int ret;
+
+ /* Handle frame interpolation (receiving too fast) */
+ if (jitter->interp_frame)
+ {
+ fprintf (stderr, "interp\n");
+ speex_decode(jitter->dec, NULL, out);
+ jitter->interp_frame = 0;
+ return;
+ }
+
+ /* Increment timestamp */
+ jitter->pointer_timestamp += jitter->frame_time;
+
+ /* Handle frame dropping (receiving too fast) */
+ if (jitter->drop_frame)
+ {
+ jitter->pointer_timestamp += jitter->frame_time;
+ jitter->drop_frame = 0;
+ }
+
+ /* Send zeros while we fill in the buffer */
+ if (jitter->pointer_timestamp<0)
+ {
+ for (i=0;i<jitter->frame_size;i++)
+ out[i]=0;
+ return;
+ }
+
+ fprintf (stderr, "%d ", jitter->pointer_timestamp);
+ /* Search the buffer for a packet with the right timestamp */
+ for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
+ {
+ fprintf (stderr, "%d ", jitter->timestamp[i]);
+ if (jitter->len[i]!=-1 && jitter->timestamp[i]==jitter->pointer_timestamp)
+ break;
+ }
+ fprintf (stderr, "\n");
+
+ if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
+ {
+ /* No packet found */
+ if (jitter->valid_bits)
+ {
+ /* Try decoding last received packet */
+ ret = speex_decode(jitter->dec, &jitter->current_packet, out);
+ if (ret == 0)
+ return;
+ else
+ jitter->valid_bits = 0;
+ }
+
+ /*Packet is late or lost*/
+ speex_decode(jitter->dec, NULL, out);
+ fprintf (stderr, "lost packet\n");
+ } else {
+ /* Found the right packet */
+ speex_bits_read_from(&jitter->current_packet, jitter->buf[i], jitter->len[i]);
+ jitter->len[i]=-1;
+ /* Decode packet */
+ ret = speex_decode(jitter->dec, &jitter->current_packet, out);
+ if (ret == 0)
+ {
+ jitter->valid_bits = 1;
+ } else {
+ /* Error while decoding */
+ for (i=0;i<jitter->frame_size;i++)
+ out[i]=0;
+ }
+ }
+
+
+}
+
diff --git a/libspeex/speex_jitter.h b/libspeex/speex_jitter.h
new file mode 100644
index 0000000..ca9f7f2
--- /dev/null
+++ b/libspeex/speex_jitter.h
@@ -0,0 +1,74 @@
+/* Copyright (C) 2002 Jean-Marc Valin
+ File: speex_jitter.h
+
+ Adaptive jitter buffer for Speex
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ - Neither the name of the Xiph.org Foundation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "speex.h"
+#include "speex_bits.h"
+
+#ifndef SPEEX_JITTER_H
+#define SPEEX_JITTER_H
+
+#define SPEEX_JITTER_MAX_PACKET_SIZE 2000
+#define SPEEX_JITTER_MAX_BUFFER_SIZE 20
+
+typedef struct SpeexJitter {
+ int buffer_size;
+ int pointer_timestamp;
+
+ SpeexBits current_packet;
+ int valid_bits;
+
+ char buf[SPEEX_JITTER_MAX_BUFFER_SIZE][SPEEX_JITTER_MAX_PACKET_SIZE];
+ int timestamp[SPEEX_JITTER_MAX_BUFFER_SIZE];
+ int len[SPEEX_JITTER_MAX_BUFFER_SIZE];
+
+ void *dec;
+ int frame_size;
+ int frame_time;
+
+ int underflow_count;
+ int drop_frame;
+ int interp_frame;
+
+} SpeexJitter;
+
+void speex_jitter_init(SpeexJitter *jitter, void *decoder, int sampling_rate);
+
+void speex_jitter_destroy(SpeexJitter *jitter);
+
+void speex_jitter_put(SpeexJitter *jitter, char *packet, int len, int time);
+
+void speex_jitter_get(SpeexJitter *jitter, float *out);
+
+
+#endif