Init
This commit is contained in:
316
DependentExtensions/speex-1.1.12/libspeex/jitter.c
Normal file
316
DependentExtensions/speex-1.1.12/libspeex/jitter.c
Normal file
@ -0,0 +1,316 @@
|
||||
/* 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#include "misc.h"
|
||||
#include <speex/speex.h>
|
||||
#include <speex/speex_bits.h>
|
||||
#include <speex/speex_jitter.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define LATE_BINS 4
|
||||
|
||||
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 = jitter->frame_size;
|
||||
|
||||
speex_bits_init(&jitter->current_packet);
|
||||
jitter->valid_bits = 0;
|
||||
|
||||
jitter->buffer_size = 4;
|
||||
|
||||
jitter->pointer_timestamp = -jitter->frame_time * jitter->buffer_size;
|
||||
jitter->reset_state = 1;
|
||||
jitter->lost_count = 0;
|
||||
jitter->loss_rate = 0;
|
||||
}
|
||||
|
||||
void speex_jitter_destroy(SpeexJitter *jitter)
|
||||
{
|
||||
speex_bits_destroy(&jitter->current_packet);
|
||||
}
|
||||
|
||||
|
||||
void speex_jitter_put(SpeexJitter *jitter, char *packet, int len, int timestamp)
|
||||
{
|
||||
int i,j;
|
||||
int arrival_margin;
|
||||
|
||||
if (jitter->reset_state)
|
||||
{
|
||||
jitter->reset_state=0;
|
||||
jitter->pointer_timestamp = timestamp-jitter->frame_time * jitter->buffer_size;
|
||||
for (i=0;i<MAX_MARGIN;i++)
|
||||
{
|
||||
jitter->shortterm_margin[i] = 0;
|
||||
jitter->longterm_margin[i] = 0;
|
||||
}
|
||||
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
|
||||
{
|
||||
jitter->len[i]=-1;
|
||||
jitter->timestamp[i]=-1;
|
||||
}
|
||||
fprintf(stderr, "reset to %d\n", timestamp);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
/*if (jitter->timestamp[i] != -1)
|
||||
fprintf (stderr, "discarding %d %d\n", jitter->timestamp[i], jitter->pointer_timestamp);*/
|
||||
}
|
||||
}
|
||||
|
||||
/*Find an empty slot in the buffer*/
|
||||
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
|
||||
{
|
||||
if (jitter->len[i]==-1)
|
||||
break;
|
||||
}
|
||||
|
||||
/*fprintf(stderr, "%d %d %f\n", timestamp, jitter->pointer_timestamp, jitter->drift_average);*/
|
||||
if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
|
||||
{
|
||||
int earliest=jitter->timestamp[0];
|
||||
i=0;
|
||||
for (j=1;j<SPEEX_JITTER_MAX_BUFFER_SIZE;j++)
|
||||
{
|
||||
if (jitter->timestamp[j]<earliest)
|
||||
{
|
||||
earliest = jitter->timestamp[j];
|
||||
i=j;
|
||||
}
|
||||
}
|
||||
/*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/
|
||||
/*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/BYTES_PER_CHAR;j++)
|
||||
jitter->buf[i][j]=packet[j];
|
||||
jitter->timestamp[i]=timestamp;
|
||||
jitter->len[i]=len;
|
||||
|
||||
/* Don't count late packets when adjusting the synchro (we're taking care of them elsewhere) */
|
||||
/*if (timestamp <= jitter->pointer_timestamp)
|
||||
{
|
||||
fprintf (stderr, "frame for timestamp %d arrived too late (at time %d)\n", timestamp, jitter->pointer_timestamp);
|
||||
}*/
|
||||
|
||||
/* Adjust the buffer size depending on network conditions */
|
||||
arrival_margin = (timestamp - jitter->pointer_timestamp - jitter->frame_time);
|
||||
|
||||
if (arrival_margin >= -LATE_BINS*jitter->frame_time)
|
||||
{
|
||||
int int_margin;
|
||||
for (i=0;i<MAX_MARGIN;i++)
|
||||
{
|
||||
jitter->shortterm_margin[i] *= .98;
|
||||
jitter->longterm_margin[i] *= .995;
|
||||
}
|
||||
int_margin = (arrival_margin + LATE_BINS*jitter->frame_time)/jitter->frame_time;
|
||||
if (int_margin>MAX_MARGIN-1)
|
||||
int_margin = MAX_MARGIN-1;
|
||||
if (int_margin>=0)
|
||||
{
|
||||
jitter->shortterm_margin[int_margin] += .02;
|
||||
jitter->longterm_margin[int_margin] += .005;
|
||||
}
|
||||
}
|
||||
|
||||
/*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);*/
|
||||
}
|
||||
|
||||
void speex_jitter_get(SpeexJitter *jitter, short *out, int *current_timestamp)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
float late_ratio_short;
|
||||
float late_ratio_long;
|
||||
float ontime_ratio_short;
|
||||
float ontime_ratio_long;
|
||||
float early_ratio_short;
|
||||
float early_ratio_long;
|
||||
|
||||
late_ratio_short = 0;
|
||||
late_ratio_long = 0;
|
||||
for (i=0;i<LATE_BINS;i++)
|
||||
{
|
||||
late_ratio_short += jitter->shortterm_margin[i];
|
||||
late_ratio_long += jitter->longterm_margin[i];
|
||||
}
|
||||
ontime_ratio_short = jitter->shortterm_margin[LATE_BINS];
|
||||
ontime_ratio_long = jitter->longterm_margin[LATE_BINS];
|
||||
early_ratio_short = early_ratio_long = 0;
|
||||
for (i=LATE_BINS+1;i<MAX_MARGIN;i++)
|
||||
{
|
||||
early_ratio_short += jitter->shortterm_margin[i];
|
||||
early_ratio_long += jitter->longterm_margin[i];
|
||||
}
|
||||
if (0&&jitter->pointer_timestamp%1000==0)
|
||||
{
|
||||
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);
|
||||
/*fprintf (stderr, "%f %f\n", early_ratio_short + ontime_ratio_short + late_ratio_short, early_ratio_long + ontime_ratio_long + late_ratio_long);*/
|
||||
}
|
||||
|
||||
if (late_ratio_short > .1 || late_ratio_long > .03)
|
||||
{
|
||||
jitter->shortterm_margin[MAX_MARGIN-1] += jitter->shortterm_margin[MAX_MARGIN-2];
|
||||
jitter->longterm_margin[MAX_MARGIN-1] += jitter->longterm_margin[MAX_MARGIN-2];
|
||||
for (i=MAX_MARGIN-3;i>=0;i--)
|
||||
{
|
||||
jitter->shortterm_margin[i+1] = jitter->shortterm_margin[i];
|
||||
jitter->longterm_margin[i+1] = jitter->longterm_margin[i];
|
||||
}
|
||||
jitter->shortterm_margin[0] = 0;
|
||||
jitter->longterm_margin[0] = 0;
|
||||
/*fprintf (stderr, "interpolate frame\n");*/
|
||||
speex_decode_int(jitter->dec, NULL, out);
|
||||
if (current_timestamp)
|
||||
*current_timestamp = jitter->pointer_timestamp;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Increment timestamp */
|
||||
jitter->pointer_timestamp += jitter->frame_time;
|
||||
|
||||
if (late_ratio_short + ontime_ratio_short < .005 && late_ratio_long + ontime_ratio_long < .01 && early_ratio_short > .8)
|
||||
{
|
||||
jitter->shortterm_margin[0] += jitter->shortterm_margin[1];
|
||||
jitter->longterm_margin[0] += jitter->longterm_margin[1];
|
||||
for (i=1;i<MAX_MARGIN-1;i++)
|
||||
{
|
||||
jitter->shortterm_margin[i] = jitter->shortterm_margin[i+1];
|
||||
jitter->longterm_margin[i] = jitter->longterm_margin[i+1];
|
||||
}
|
||||
jitter->shortterm_margin[MAX_MARGIN-1] = 0;
|
||||
jitter->longterm_margin[MAX_MARGIN-1] = 0;
|
||||
/*fprintf (stderr, "drop frame\n");*/
|
||||
jitter->pointer_timestamp += jitter->frame_time;
|
||||
}
|
||||
|
||||
if (current_timestamp)
|
||||
*current_timestamp = jitter->pointer_timestamp;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Search the buffer for a packet with the right timestamp */
|
||||
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
|
||||
{
|
||||
if (jitter->len[i]!=-1 && jitter->timestamp[i]==jitter->pointer_timestamp)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
|
||||
{
|
||||
/* No packet found */
|
||||
if (jitter->valid_bits)
|
||||
{
|
||||
/* Try decoding last received packet */
|
||||
ret = speex_decode_int(jitter->dec, &jitter->current_packet, out);
|
||||
if (ret == 0)
|
||||
{
|
||||
jitter->lost_count = 0;
|
||||
return;
|
||||
} else {
|
||||
jitter->valid_bits = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*fprintf (stderr, "lost/late frame %d\n", jitter->pointer_timestamp);*/
|
||||
/*Packet is late or lost*/
|
||||
speex_decode_int(jitter->dec, NULL, out);
|
||||
jitter->lost_count++;
|
||||
if (jitter->lost_count>=25)
|
||||
{
|
||||
jitter->lost_count = 0;
|
||||
jitter->reset_state = 1;
|
||||
speex_decoder_ctl(jitter->dec, SPEEX_RESET_STATE, NULL);
|
||||
}
|
||||
jitter->loss_rate = .999*jitter->loss_rate + .001;
|
||||
} else {
|
||||
jitter->lost_count = 0;
|
||||
/* 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_int(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;
|
||||
}
|
||||
jitter->loss_rate = .999*jitter->loss_rate;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
int speex_jitter_get_pointer_timestamp(SpeexJitter *jitter)
|
||||
{
|
||||
return jitter->pointer_timestamp;
|
||||
}
|
||||
Reference in New Issue
Block a user