From a3c0ed9df6f46d7dfcc4fff64641d18f2a1c1a8a Mon Sep 17 00:00:00 2001 From: Nanang Izzuddin Date: Thu, 10 Jul 2008 14:59:57 +0000 Subject: Updated WSOLA to use circular buffer and configurable hanning window size (which affecting number of delay produced by WSOLA) git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2115 74dad513-b988-da41-8d7b-12977e46ad98 --- pjmedia/include/pjmedia/wsola.h | 8 +- pjmedia/src/pjmedia/wsola.c | 527 +++++++++++++++++++++------------------- 2 files changed, 281 insertions(+), 254 deletions(-) (limited to 'pjmedia') diff --git a/pjmedia/include/pjmedia/wsola.h b/pjmedia/include/pjmedia/wsola.h index 8d616b86..9832096b 100644 --- a/pjmedia/include/pjmedia/wsola.h +++ b/pjmedia/include/pjmedia/wsola.h @@ -136,7 +136,7 @@ PJ_DECL(pj_status_t) pjmedia_wsola_reset(pjmedia_wsola *wsola, * @return PJ_SUCCESS normally. */ PJ_DECL(pj_status_t) pjmedia_wsola_save(pjmedia_wsola *wsola, - short frm[], + pj_int16_t frm[], pj_bool_t prev_lost); /** @@ -148,7 +148,7 @@ PJ_DECL(pj_status_t) pjmedia_wsola_save(pjmedia_wsola *wsola, * @return PJ_SUCCESS normally. */ PJ_DECL(pj_status_t) pjmedia_wsola_generate(pjmedia_wsola *wsola, - short frm[]); + pj_int16_t frm[]); /** @@ -174,9 +174,9 @@ PJ_DECL(pj_status_t) pjmedia_wsola_generate(pjmedia_wsola *wsola, * of the parameters are not valid. */ PJ_DECL(pj_status_t) pjmedia_wsola_discard(pjmedia_wsola *wsola, - short buf1[], + pj_int16_t buf1[], unsigned buf1_cnt, - short buf2[], + pj_int16_t buf2[], unsigned buf2_cnt, unsigned *erase_cnt); diff --git a/pjmedia/src/pjmedia/wsola.c b/pjmedia/src/pjmedia/wsola.c index 42cb02b6..1a07ed61 100644 --- a/pjmedia/src/pjmedia/wsola.c +++ b/pjmedia/src/pjmedia/wsola.c @@ -17,9 +17,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include +#include #include #include #include +#include #include /* @@ -28,6 +30,7 @@ */ #define THIS_FILE "wsola.c" + #if (PJMEDIA_WSOLA_IMP==PJMEDIA_WSOLA_IMP_WSOLA) || \ (PJMEDIA_WSOLA_IMP==PJMEDIA_WSOLA_IMP_WSOLA_LITE) @@ -35,83 +38,89 @@ * WSOLA implementation using WSOLA */ -/* History size, in percentage of samples_per_frame */ -#define HISTSZ (1.5) +/* Buffer size including history, in frames */ +#define FRAME_CNT 5 -/* Number of frames in buffer (excluding history) */ -#define FRAME_CNT 4 +/* Number of history frames in buffer */ +#define HIST_CNT 1.5 -/* Template size in msec */ -#define TEMPLATE_PTIME (5) +/* Template size, in msec */ +#define TEMPLATE_PTIME 5 -/* Generate extra samples, in msec */ -#define GEN_EXTRA_PTIME (1) +/* Hanning window size, in msec */ +#define HANNING_PTIME 5 /* Number of frames in erase buffer */ #define ERASE_CNT ((unsigned)3) -#ifndef M_PI -# define M_PI 3.14159265358979323846 -#endif - #if 0 # define TRACE_(x) PJ_LOG(4,x) #else # define TRACE_(x) #endif +#if 0 +# define CHECK_(x) pj_assert(x) +#else +# define CHECK_(x) +#endif /* Buffer content: * - * t0 time tn - * ----------------> + * +---------+-----------+--------------------+ + * | history | min_extra | more extra / empty | + * +---------+-----------+--------------------+ + * ^ ^ ^ ^ + * buf hist_size min_extra buf_size + * + * History size (hist_size) is a constant value, initialized upon creation. + * + * min_extra size is equal to HANNING_PTIME, this samples is useful for + * smoothening samples transition between generated frame & history + * (when PLC is invoked), or between generated samples & normal frame + * (after lost/PLC). Since min_extra samples need to be available at + * any time, this will introduce delay of HANNING_PTIME ms. * - * +---------+-------+-------+--- --+ - * | history | frame | extra | ...empty... | - * +---------+-------+-------+---- ---+ - * ^ ^ ^ ^ - * buf hist_cnt cur_cnt buf_cnt - * or - * frm pointer + * More extra is excess samples produced by PLC (PLC frame generation may + * produce more than exact one frame). * - * History count (hist_cnt) is a constant value, initialized upon - * creation. + * At any particular time, the buffer will contain at least (hist_size + + * min_extra) samples. * - * At any particular time, the buffer will contain at least - * (hist_cnt+samples_per_frame) samples. + * A "save" operation will append the new frame to the end of the buffer, + * return the frame from samples right after history and shift the buffer + * by one frame. * - * A "save" operation will append the frame to the end of the - * buffer, return the samples right after history (the frm pointer), - * and shift the buffer by one frame. */ /* WSOLA structure */ struct pjmedia_wsola { - unsigned clock_rate; /* Sampling rate. */ - pj_uint16_t samples_per_frame;/* Samples per frame (const) */ - pj_uint16_t channel_count; /* Samples per frame (const) */ - pj_uint16_t options; /* Options. */ - pj_uint16_t hist_cnt; /* # of history samples (const) */ - pj_uint16_t buf_cnt; /* Total buffer capacity (const) */ - pj_uint16_t cur_cnt; /* Cur # of samples, inc. history */ - pj_uint16_t template_size; /* Template size (const) */ - pj_uint16_t min_extra; /* Min extra samples for merging (const)*/ - pj_uint16_t gen_extra; /* Generate extra samples (const) */ - pj_uint16_t expand_cnt; /* Number of expansion currently done */ - - short *buf; /* The buffer. */ - short *frm; /* Pointer to next frame to play in buf */ - short *mergebuf; /* Temporary merge buffer. */ - short *erasebuf; /* Temporary erase buffer. */ + unsigned clock_rate; /* Sampling rate. */ + pj_uint16_t samples_per_frame; /* Samples per frame (const) */ + pj_uint16_t channel_count; /* Channel countt (const) */ + pj_uint16_t options; /* Options. */ + + pjmedia_circ_buf *buf; /* The buffer. */ + pj_int16_t *erase_buf; /* Temporary erase buffer. */ + pj_int16_t *merge_buf; /* Temporary merge buffer. */ + + pj_uint16_t buf_size; /* Total buffer size (const) */ + pj_uint16_t hanning_size; /* Hanning window size (const) */ + pj_uint16_t templ_size; /* Template size (const) */ + pj_uint16_t hist_size; /* History size (const) */ + + pj_uint16_t min_extra; /* Minimum extra (const) */ + pj_uint16_t expand_cnt; /* Consecutive expansion count */ + #if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT!=0 - float *hanning; /* Hanning window. */ + float *hanning; /* Hanning window. */ #else - pj_uint16_t *hanning; /* Hanning window. */ + pj_uint16_t *hanning; /* Hanning window. */ #endif - pj_timestamp ts; /* Running timestamp. */ + pj_timestamp ts; /* Running timestamp. */ }; #if (PJMEDIA_WSOLA_IMP==PJMEDIA_WSOLA_IMP_WSOLA_LITE) @@ -124,10 +133,10 @@ struct pjmedia_wsola * * diff level = (template[1]+..+template[n]) - (target[1]+..+target[n]) */ -static short *find_pitch(short *frm, short *beg, short *end, +static pj_int16_t *find_pitch(pj_int16_t *frm, pj_int16_t *beg, pj_int16_t *end, unsigned template_cnt, int first) { - short *sr, *best=beg; + pj_int16_t *sr, *best=beg; int best_corr = 0x7FFFFFFF; int frm_sum = 0; unsigned i; @@ -185,14 +194,13 @@ static short *find_pitch(short *frm, short *beg, short *end, /* * Floating point version. */ -#include #if (PJMEDIA_WSOLA_IMP==PJMEDIA_WSOLA_IMP_WSOLA) -static short *find_pitch(short *frm, short *beg, short *end, +static pj_int16_t *find_pitch(pj_int16_t *frm, pj_int16_t *beg, pj_int16_t *end, unsigned template_cnt, int first) { - short *sr, *best=beg; + pj_int16_t *sr, *best=beg; double best_corr = 0; for (sr=beg; sr!=end; ++sr) { @@ -240,25 +248,25 @@ static short *find_pitch(short *frm, short *beg, short *end, #endif -static void overlapp_add(short dst[], unsigned count, - short l[], short r[], +static void overlapp_add(pj_int16_t dst[], unsigned count, + pj_int16_t l[], pj_int16_t r[], float w[]) { unsigned i; for (i=0; i> WINDOW_BITS); } } -static void overlapp_add_simple(short dst[], unsigned count, - short l[], short r[]) +static void overlapp_add_simple(pj_int16_t dst[], unsigned count, + pj_int16_t l[], pj_int16_t r[]) { int step = ((WINDOW_MAX_VAL+1) / count), stepdown = WINDOW_MAX_VAL; unsigned i; for (i=0; i> WINDOW_BITS); + dst[i]=(pj_int16_t)((l[i] * stepdown + r[i] * (1-stepdown)) >> WINDOW_BITS); stepdown -= step; } } @@ -398,7 +406,7 @@ static void create_win(pj_pool_t *pool, pj_uint16_t **pw, unsigned count) pj_uint32_t phase; pj_uint64_t cos_val; - /* w[i] = (float)(0.5 - 0.5 * cos(2.0 * M_PI * i / (count*2-1)) ); */ + /* w[i] = (float)(0.5 - 0.5 * cos(2.0 * PJ_PI * i / (count*2-1)) ); */ phase = (pj_uint32_t)(PJ_INT64(0xFFFFFFFF) * i / (count*2-1)); cos_val = approx_cos(phase); @@ -423,6 +431,7 @@ PJ_DEF(pj_status_t) pjmedia_wsola_create( pj_pool_t *pool, pjmedia_wsola **p_wsola) { pjmedia_wsola *wsola; + pj_status_t status; PJ_ASSERT_RETURN(pool && clock_rate && samples_per_frame && p_wsola, PJ_EINVAL); @@ -430,51 +439,63 @@ PJ_DEF(pj_status_t) pjmedia_wsola_create( pj_pool_t *pool, PJ_ASSERT_RETURN(samples_per_frame < clock_rate, PJ_EINVAL); PJ_ASSERT_RETURN(channel_count > 0, PJ_EINVAL); + /* Allocate wsola and initialize vars */ wsola = PJ_POOL_ZALLOC_T(pool, pjmedia_wsola); - wsola->clock_rate= (pj_uint16_t) clock_rate; wsola->samples_per_frame = (pj_uint16_t) samples_per_frame; wsola->channel_count = (pj_uint16_t) channel_count; - wsola->options = (pj_uint16_t) options; - wsola->hist_cnt = (pj_uint16_t)(samples_per_frame * HISTSZ); - wsola->buf_cnt = (pj_uint16_t)(wsola->hist_cnt + - (samples_per_frame * FRAME_CNT)); - - wsola->cur_cnt = (pj_uint16_t)(wsola->hist_cnt + - wsola->samples_per_frame); - wsola->min_extra = 0; - - if ((options & PJMEDIA_WSOLA_NO_PLC) == 0) - wsola->gen_extra = (pj_uint16_t)(GEN_EXTRA_PTIME * clock_rate / 1000); - - wsola->template_size = (pj_uint16_t) (clock_rate * TEMPLATE_PTIME / 1000); - if (wsola->template_size > samples_per_frame) - wsola->template_size = wsola->samples_per_frame; - - /* Make sure minimal template size is 8, this is required by waveform - * similarity calculation (find_pitch()). Moreover, smaller template size - * will reduce accuracy. - */ - if (wsola->template_size < 8) - wsola->template_size = 8; - - wsola->buf = (short*)pj_pool_calloc(pool, wsola->buf_cnt, - sizeof(short)); - wsola->frm = wsola->buf + wsola->hist_cnt; - - wsola->mergebuf = (short*)pj_pool_calloc(pool, samples_per_frame, - sizeof(short)); + wsola->options = (pj_uint16_t) options; + + /* Create circular buffer */ + wsola->buf_size = (pj_uint16_t) (samples_per_frame * FRAME_CNT); + status = pjmedia_circ_buf_create(pool, wsola->buf_size, &wsola->buf); + if (status != PJ_SUCCESS) { + PJ_LOG(3, (THIS_FILE, "Failed to create circular buf")); + return status; + } + + /* Calculate history size */ + wsola->hist_size = (pj_uint16_t)(HIST_CNT * samples_per_frame); + + /* Calculate template size */ + wsola->templ_size = (pj_uint16_t)(TEMPLATE_PTIME * clock_rate * + channel_count / 1000); + if (wsola->templ_size > samples_per_frame) + wsola->templ_size = wsola->samples_per_frame; + + /* Calculate hanning window size */ + wsola->hanning_size = (pj_uint16_t)(HANNING_PTIME * clock_rate * + channel_count / 1000); + if (wsola->hanning_size > wsola->samples_per_frame) + wsola->hanning_size = wsola->samples_per_frame; + pj_assert(wsola->templ_size <= wsola->hanning_size); + + /* Create merge buffer */ + wsola->merge_buf = (pj_int16_t*) pj_pool_calloc(pool, + wsola->hanning_size, + sizeof(pj_int16_t)); + + /* Setup with PLC */ + if ((options & PJMEDIA_WSOLA_NO_PLC) == 0) { + wsola->min_extra = wsola->hanning_size; + } + + /* Setup with hanning */ if ((options & PJMEDIA_WSOLA_NO_HANNING) == 0) { - create_win(pool, &wsola->hanning, wsola->samples_per_frame); + create_win(pool, &wsola->hanning, wsola->hanning_size); } + /* Setup with discard */ if ((options & PJMEDIA_WSOLA_NO_DISCARD) == 0) { - wsola->erasebuf = (short*)pj_pool_calloc(pool, samples_per_frame * + wsola->erase_buf = (pj_int16_t*)pj_pool_calloc(pool, samples_per_frame * ERASE_CNT, - sizeof(short)); + sizeof(pj_int16_t)); } + /* Generate dummy extra */ + pjmedia_circ_buf_set_len(wsola->buf, wsola->hist_size + wsola->min_extra); + *p_wsola = wsola; return PJ_SUCCESS; @@ -495,9 +516,9 @@ PJ_DEF(pj_status_t) pjmedia_wsola_reset( pjmedia_wsola *wsola, PJ_ASSERT_RETURN(wsola && options==0, PJ_EINVAL); PJ_UNUSED_ARG(options); - wsola->cur_cnt = (pj_uint16_t)(wsola->hist_cnt + - wsola->samples_per_frame); - pjmedia_zero_samples(wsola->buf, wsola->cur_cnt); + pjmedia_circ_buf_reset(wsola->buf); + pjmedia_circ_buf_set_len(wsola->buf, wsola->hist_size + wsola->min_extra); + return PJ_SUCCESS; } @@ -505,21 +526,28 @@ PJ_DEF(pj_status_t) pjmedia_wsola_reset( pjmedia_wsola *wsola, static void expand(pjmedia_wsola *wsola, unsigned needed) { unsigned generated = 0; - unsigned frmsz = wsola->samples_per_frame; unsigned rep; + pj_int16_t *reg1, *reg2; + unsigned reg1_len, reg2_len; + + pjmedia_circ_buf_pack_buffer(wsola->buf); + pjmedia_circ_buf_get_read_regions(wsola->buf, ®1, ®1_len, + ®2, ®2_len); + CHECK_(reg2_len == 0); + for (rep=1;; ++rep) { - short *start, *frm; + pj_int16_t *start, *templ; unsigned min_dist, max_dist, dist; - frm = wsola->buf + wsola->cur_cnt - frmsz; - pj_assert(frm - wsola->buf >= wsola->hist_cnt); + templ = reg1 + reg1_len - wsola->hanning_size; + CHECK_(templ - reg1 >= wsola->hist_size); - max_dist = wsola->hist_cnt; - min_dist = frmsz >> 1; + max_dist = wsola->hist_size; + min_dist = wsola->hanning_size >> 1; - start = find_pitch(frm, frm - max_dist, frm - min_dist, - wsola->template_size, 1); + start = find_pitch(templ, templ - max_dist, templ - min_dist, + wsola->templ_size, 1); /* Should we make sure that "start" is really aligned to * channel #0, in case of stereo? Probably not necessary, as @@ -527,25 +555,31 @@ static void expand(pjmedia_wsola *wsola, unsigned needed) */ if (wsola->options & PJMEDIA_WSOLA_NO_HANNING) { - overlapp_add_simple(wsola->mergebuf, frmsz,frm, start); + overlapp_add_simple(wsola->merge_buf, wsola->hanning_size, + templ, start); } else { - overlapp_add(wsola->mergebuf, frmsz, frm, start, wsola->hanning); + overlapp_add(wsola->merge_buf, wsola->hanning_size, templ, + start, wsola->hanning); } /* How many new samples do we have */ - dist = frm - start; + dist = templ - start; + + /* Not enough buffer to hold the result */ + if (reg1_len + dist > wsola->buf_size) + break; /* Copy the "tail" (excess frame) to the end */ - pjmedia_move_samples(frm + frmsz, start + frmsz, - wsola->buf+wsola->cur_cnt - (start+frmsz)); + pjmedia_move_samples(templ + wsola->hanning_size, + start + wsola->hanning_size, + dist); /* Copy the merged frame */ - pjmedia_copy_samples(frm, wsola->mergebuf, frmsz); + pjmedia_copy_samples(templ, wsola->merge_buf, wsola->hanning_size); /* We have new samples */ - wsola->cur_cnt = (pj_uint16_t)(wsola->cur_cnt + dist); - - pj_assert(wsola->cur_cnt <= wsola->buf_cnt); + reg1_len += dist; + pjmedia_circ_buf_set_len(wsola->buf, reg1_len); generated += dist; @@ -558,43 +592,44 @@ static void expand(pjmedia_wsola *wsola, unsigned needed) } -static unsigned compress(pjmedia_wsola *wsola, short *buf, unsigned count, +static unsigned compress(pjmedia_wsola *wsola, pj_int16_t *buf, unsigned count, unsigned del_cnt) { unsigned samples_del = 0, rep; for (rep=1; ; ++rep) { - short *start, *end; - unsigned frmsz = wsola->samples_per_frame; + pj_int16_t *start, *end; unsigned dist; - if ((count - del_cnt) <= frmsz) { - //if (count <= (del_cnt << 1)) { + if (count <= wsola->hanning_size + del_cnt) { TRACE_((THIS_FILE, "Not enough samples to compress!")); return samples_del; } + // Make start distance to del_cnt, so discard will be performed in + // only one iteration. //start = buf + (frmsz >> 1); start = buf + del_cnt - samples_del; - end = start + frmsz; + end = start + wsola->samples_per_frame; - if (end + frmsz > buf + count) - end = buf+count-frmsz; + if (end + wsola->hanning_size > buf + count) { + end = buf+count-wsola->hanning_size; + } - pj_assert(start < end); + CHECK_(start < end); - start = find_pitch(buf, start, end, wsola->template_size, 0); + start = find_pitch(buf, start, end, wsola->templ_size, 0); dist = start - buf; if (wsola->options & PJMEDIA_WSOLA_NO_HANNING) { - overlapp_add_simple(buf, wsola->samples_per_frame, buf, start); + overlapp_add_simple(buf, wsola->hanning_size, buf, start); } else { - overlapp_add(buf, wsola->samples_per_frame, buf, start, - wsola->hanning); + overlapp_add(buf, wsola->hanning_size, buf, start, wsola->hanning); } - pjmedia_move_samples(buf + frmsz, buf + frmsz + dist, - count - frmsz - dist); + pjmedia_move_samples(buf + wsola->hanning_size, + buf + wsola->hanning_size + dist, + count - wsola->hanning_size - dist); count -= dist; samples_del += dist; @@ -613,120 +648,108 @@ static unsigned compress(pjmedia_wsola *wsola, short *buf, unsigned count, PJ_DEF(pj_status_t) pjmedia_wsola_save( pjmedia_wsola *wsola, - short frm[], + pj_int16_t frm[], pj_bool_t prev_lost) { - unsigned extra; + unsigned buf_len; + pj_status_t status; - extra = wsola->cur_cnt - wsola->hist_cnt - wsola->samples_per_frame; - pj_assert(extra >= 0); - - if (prev_lost && extra != 0 && extra >= wsola->min_extra) { - short *dst = wsola->buf + wsola->hist_cnt + wsola->samples_per_frame; - - if (extra > wsola->samples_per_frame) - extra = wsola->samples_per_frame; - - /* Smoothen the transition. This will also erase the excess - * samples - */ - overlapp_add_simple(dst, extra, dst, frm); + buf_len = pjmedia_circ_buf_get_len(wsola->buf); + CHECK_(buf_len >= (unsigned)(wsola->hist_size + wsola->min_extra)); - /* Copy remaining samples from the frame */ - pjmedia_copy_samples(dst+extra, frm+extra, - wsola->samples_per_frame-extra); + /* Update vars */ + wsola->expand_cnt = 0; + wsola->ts.u64 += wsola->samples_per_frame; - /* Retrieve frame */ - pjmedia_copy_samples(frm, wsola->frm, wsola->samples_per_frame); + /* If previous frame was lost, smoothen this frame with the generated one */ + if (prev_lost) { + pj_int16_t *reg1, *reg2; + unsigned reg1_len, reg2_len; + pj_int16_t *ola_left; - /* Remove excess samples */ - wsola->cur_cnt = (pj_uint16_t)(wsola->hist_cnt + - wsola->samples_per_frame); + pjmedia_circ_buf_get_read_regions(wsola->buf, ®1, ®1_len, + ®2, ®2_len); - /* Shift buffer */ - pjmedia_move_samples(wsola->buf, wsola->buf+wsola->samples_per_frame, - wsola->cur_cnt); + if (reg2_len == 0) { + ola_left = reg1; + } else if (reg2_len >= wsola->min_extra) { + ola_left = reg2 + reg2_len - wsola->min_extra; + } else { + unsigned tmp; - } else { - /* Just append to end of buffer */ - if (prev_lost) { - TRACE_((THIS_FILE, - "Appending new frame without interpolation")); + tmp = wsola->min_extra - reg2_len; + pjmedia_copy_samples(wsola->merge_buf, reg1 + reg1_len - tmp, tmp); + pjmedia_copy_samples(wsola->merge_buf + tmp, reg2, reg2_len); + ola_left = wsola->merge_buf; } - /* Append frame */ - pjmedia_copy_samples(wsola->buf + wsola->cur_cnt, frm, - wsola->samples_per_frame); + overlapp_add_simple(frm, wsola->min_extra, ola_left, frm); - /* Retrieve frame */ - pjmedia_copy_samples(frm, wsola->frm, - wsola->samples_per_frame); + buf_len -= wsola->min_extra; + pjmedia_circ_buf_set_len(wsola->buf, buf_len); + } - /* Shift buffer */ - pjmedia_move_samples(wsola->buf, wsola->buf+wsola->samples_per_frame, - wsola->cur_cnt); + status = pjmedia_circ_buf_write(wsola->buf, frm, wsola->samples_per_frame); + if (status != PJ_SUCCESS) { + TRACE_((THIS_FILE, "Failed writing to circbuf [err=%d]", status)); + return status; } - - wsola->expand_cnt = 0; - wsola->ts.u64 += wsola->samples_per_frame; - return PJ_SUCCESS; + status = pjmedia_circ_buf_copy(wsola->buf, wsola->hist_size, frm, + wsola->samples_per_frame); + if (status != PJ_SUCCESS) { + TRACE_((THIS_FILE, "Failed copying from circbuf [err=%d]", status)); + return status; + } + + return pjmedia_circ_buf_adv_read_ptr(wsola->buf, wsola->samples_per_frame); } PJ_DEF(pj_status_t) pjmedia_wsola_generate( pjmedia_wsola *wsola, - short frm[]) + pj_int16_t frm[]) { - unsigned extra; - - extra = wsola->cur_cnt - wsola->hist_cnt - wsola->samples_per_frame; - - if (extra >= wsola->samples_per_frame) { - - /* We have one extra frame in the buffer, just return this frame - * rather than generating a new one. - */ - pjmedia_copy_samples(frm, wsola->frm, wsola->samples_per_frame); - pjmedia_move_samples(wsola->buf, wsola->buf+wsola->samples_per_frame, - wsola->cur_cnt - wsola->samples_per_frame); + unsigned samples_len; + pj_status_t status = PJ_SUCCESS; - pj_assert(wsola->cur_cnt >= - wsola->hist_cnt + (wsola->samples_per_frame << 1)); - wsola->cur_cnt = (pj_uint16_t)(wsola->cur_cnt - - wsola->samples_per_frame); + samples_len = pjmedia_circ_buf_get_len(wsola->buf) - wsola->hist_size; + wsola->ts.u64 += wsola->samples_per_frame; - } else { + if (samples_len < (unsigned)wsola->samples_per_frame + + (unsigned)wsola->min_extra) + { unsigned new_samples; - /* Calculate how many samples are need for a new frame */ - new_samples = ((wsola->samples_per_frame << 1) + wsola->gen_extra - - (wsola->cur_cnt - wsola->hist_cnt)); + /* Calculate how many samples are needed for a new frame */ + new_samples = wsola->samples_per_frame + wsola->min_extra - + samples_len; + if (wsola->expand_cnt == 0) + new_samples += wsola->min_extra; /* Expand buffer */ expand(wsola, new_samples); - - pjmedia_copy_samples(frm, wsola->frm, wsola->samples_per_frame); - pjmedia_move_samples(wsola->buf, wsola->buf+wsola->samples_per_frame, - wsola->cur_cnt - wsola->samples_per_frame); - - pj_assert(wsola->cur_cnt >= - wsola->hist_cnt + (wsola->samples_per_frame << 1)); - - wsola->cur_cnt = (pj_uint16_t)(wsola->cur_cnt - - wsola->samples_per_frame); + TRACE_((THIS_FILE, "Buf size after expanded = %d", + pjmedia_circ_buf_get_len(wsola->buf))); wsola->expand_cnt++; } - wsola->ts.u64 += wsola->samples_per_frame; + status = pjmedia_circ_buf_copy(wsola->buf, wsola->hist_size, frm, + wsola->samples_per_frame); + if (status != PJ_SUCCESS) { + TRACE_((THIS_FILE, "Failed copying from circbuf [err=%d]", status)); + return status; + } + + pjmedia_circ_buf_adv_read_ptr(wsola->buf, wsola->samples_per_frame); return PJ_SUCCESS; } PJ_DEF(pj_status_t) pjmedia_wsola_discard( pjmedia_wsola *wsola, - short buf1[], + pj_int16_t buf1[], unsigned buf1_cnt, - short buf2[], + pj_int16_t buf2[], unsigned buf2_cnt, unsigned *del_cnt) { @@ -734,19 +757,16 @@ PJ_DEF(pj_status_t) pjmedia_wsola_discard( pjmedia_wsola *wsola, PJ_ASSERT_RETURN(*del_cnt, PJ_EINVAL); if (buf2_cnt == 0) { - /* Buffer is contiguous space, no need to use temporary - * buffer. - */ + /* The whole buffer is contiguous space, straight away. */ *del_cnt = compress(wsola, buf1, buf1_cnt, *del_cnt); - } else { PJ_ASSERT_RETURN(buf2, PJ_EINVAL); if (buf1_cnt < ERASE_CNT * wsola->samples_per_frame && buf2_cnt < ERASE_CNT * wsola->samples_per_frame && - wsola->erasebuf == NULL) + wsola->erase_buf == NULL) { - /* We need erasebuf but WSOLA was created with + /* We need erase_buf but WSOLA was created with * PJMEDIA_WSOLA_NO_DISCARD flag. */ pj_assert(!"WSOLA need erase buffer!"); @@ -754,8 +774,13 @@ PJ_DEF(pj_status_t) pjmedia_wsola_discard( pjmedia_wsola *wsola, } if (buf2_cnt >= ERASE_CNT * wsola->samples_per_frame) { + /* Enough space to perform compress in the second buffer. */ *del_cnt = compress(wsola, buf2, buf2_cnt, *del_cnt); } else if (buf1_cnt >= ERASE_CNT * wsola->samples_per_frame) { + /* Enough space to perform compress in the first buffer, but then + * we need to re-arrange the buffers so there is no gap between + * buffers. + */ unsigned max; *del_cnt = compress(wsola, buf1, buf1_cnt, *del_cnt); @@ -764,22 +789,24 @@ PJ_DEF(pj_status_t) pjmedia_wsola_discard( pjmedia_wsola *wsola, if (max > buf2_cnt) max = buf2_cnt; - pjmedia_move_samples(buf1+buf1_cnt-(*del_cnt), buf2, - max); + pjmedia_move_samples(buf1 + buf1_cnt - (*del_cnt), buf2, max); + if (max < buf2_cnt) { pjmedia_move_samples(buf2, buf2+(*del_cnt), buf2_cnt-max); } - } else { - unsigned buf_cnt = buf1_cnt + buf2_cnt; - short *rem; /* remainder */ + /* Not enough samples in either buffers to perform compress. + * Need to combine the buffers in a contiguous space, the erase_buf. + */ + unsigned buf_size = buf1_cnt + buf2_cnt; + pj_int16_t *rem; /* remainder */ unsigned rem_cnt; - if (buf_cnt > ERASE_CNT * wsola->samples_per_frame) { - buf_cnt = ERASE_CNT * wsola->samples_per_frame; + if (buf_size > ERASE_CNT * wsola->samples_per_frame) { + buf_size = ERASE_CNT * wsola->samples_per_frame; - rem_cnt = buf1_cnt + buf2_cnt - buf_cnt; + rem_cnt = buf1_cnt + buf2_cnt - buf_size; rem = buf2 + buf2_cnt - rem_cnt; } else { @@ -787,43 +814,43 @@ PJ_DEF(pj_status_t) pjmedia_wsola_discard( pjmedia_wsola *wsola, rem_cnt = 0; } - pjmedia_copy_samples(wsola->erasebuf, buf1, buf1_cnt); - pjmedia_copy_samples(wsola->erasebuf+buf1_cnt, buf2, - buf_cnt-buf1_cnt); + pjmedia_copy_samples(wsola->erase_buf, buf1, buf1_cnt); + pjmedia_copy_samples(wsola->erase_buf+buf1_cnt, buf2, + buf_size-buf1_cnt); - *del_cnt = compress(wsola, wsola->erasebuf, buf_cnt, *del_cnt); + *del_cnt = compress(wsola, wsola->erase_buf, buf_size, *del_cnt); - buf_cnt -= (*del_cnt); + buf_size -= (*del_cnt); /* Copy back to buffers */ - if (buf_cnt == buf1_cnt) { - pjmedia_copy_samples(buf1, wsola->erasebuf, buf_cnt); + if (buf_size == buf1_cnt) { + pjmedia_copy_samples(buf1, wsola->erase_buf, buf_size); if (rem_cnt) { pjmedia_move_samples(buf2, rem, rem_cnt); } - } else if (buf_cnt < buf1_cnt) { - pjmedia_copy_samples(buf1, wsola->erasebuf, buf_cnt); + } else if (buf_size < buf1_cnt) { + pjmedia_copy_samples(buf1, wsola->erase_buf, buf_size); if (rem_cnt) { unsigned c = rem_cnt; - if (c > buf1_cnt-buf_cnt) { - c = buf1_cnt-buf_cnt; + if (c > buf1_cnt-buf_size) { + c = buf1_cnt-buf_size; } - pjmedia_copy_samples(buf1+buf_cnt, rem, c); + pjmedia_copy_samples(buf1+buf_size, rem, c); rem += c; rem_cnt -= c; if (rem_cnt) pjmedia_move_samples(buf2, rem, rem_cnt); } } else { - pjmedia_copy_samples(buf1, wsola->erasebuf, buf1_cnt); - pjmedia_copy_samples(buf2, wsola->erasebuf+buf1_cnt, - buf_cnt-buf1_cnt); + pjmedia_copy_samples(buf1, wsola->erase_buf, buf1_cnt); + pjmedia_copy_samples(buf2, wsola->erase_buf+buf1_cnt, + buf_size-buf1_cnt); if (rem_cnt) { - pjmedia_move_samples(buf2+buf_cnt-buf1_cnt, rem, + pjmedia_move_samples(buf2+buf_size-buf1_cnt, rem, rem_cnt); } } - + } } @@ -882,7 +909,7 @@ PJ_DEF(pj_status_t) pjmedia_wsola_reset( pjmedia_wsola *wsola, PJ_DEF(pj_status_t) pjmedia_wsola_save( pjmedia_wsola *wsola, - short frm[], + pj_int16_t frm[], pj_bool_t prev_lost) { PJ_UNUSED_ARG(wsola); @@ -894,7 +921,7 @@ PJ_DEF(pj_status_t) pjmedia_wsola_save( pjmedia_wsola *wsola, PJ_DEF(pj_status_t) pjmedia_wsola_generate( pjmedia_wsola *wsola, - short frm[]) + pj_int16_t frm[]) { pjmedia_zero_samples(frm, wsola->samples_per_frame); return PJ_SUCCESS; @@ -902,13 +929,13 @@ PJ_DEF(pj_status_t) pjmedia_wsola_generate( pjmedia_wsola *wsola, PJ_DEF(pj_status_t) pjmedia_wsola_discard( pjmedia_wsola *wsola, - short buf1[], + pj_int16_t buf1[], unsigned buf1_cnt, - short buf2[], + pj_int16_t buf2[], unsigned buf2_cnt, unsigned *del_cnt) { - pj_assert(buf1_cnt + buf2_cnt >= wsola->samples_per_frame); + CHECK_(buf1_cnt + buf2_cnt >= wsola->samples_per_frame); PJ_UNUSED_ARG(buf1); PJ_UNUSED_ARG(buf1_cnt); -- cgit v1.2.3