/* $Id$ */ /* * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include static void* plc_wsola_create(pj_pool_t*, unsigned c, unsigned f); static void plc_wsola_save(void*, pj_int16_t*); static void plc_wsola_generate(void*, pj_int16_t*); /** * This struct is used internally to represent a PLC backend. */ struct plc_alg { void* (*plc_create)(pj_pool_t*, unsigned c, unsigned f); void (*plc_save)(void*, pj_int16_t*); void (*plc_generate)(void*, pj_int16_t*); }; static struct plc_alg plc_wsola = { &plc_wsola_create, &plc_wsola_save, &plc_wsola_generate }; struct pjmedia_plc { void *obj; struct plc_alg *op; }; /* * Create PLC session. This function will select the PLC algorithm to * use based on the arguments. */ PJ_DEF(pj_status_t) pjmedia_plc_create( pj_pool_t *pool, unsigned clock_rate, unsigned samples_per_frame, unsigned options, pjmedia_plc **p_plc) { pjmedia_plc *plc; PJ_ASSERT_RETURN(pool && clock_rate && samples_per_frame && p_plc, PJ_EINVAL); PJ_ASSERT_RETURN(options == 0, PJ_EINVAL); PJ_UNUSED_ARG(options); plc = PJ_POOL_ZALLOC_T(pool, pjmedia_plc); plc->op = &plc_wsola; plc->obj = plc->op->plc_create(pool, clock_rate, samples_per_frame); *p_plc = plc; return PJ_SUCCESS; } /* * Save a good frame to PLC. */ PJ_DEF(pj_status_t) pjmedia_plc_save( pjmedia_plc *plc, pj_int16_t *frame ) { PJ_ASSERT_RETURN(plc && frame, PJ_EINVAL); plc->op->plc_save(plc->obj, frame); return PJ_SUCCESS; } /* * Generate a replacement for lost frame. */ PJ_DEF(pj_status_t) pjmedia_plc_generate( pjmedia_plc *plc, pj_int16_t *frame ) { PJ_ASSERT_RETURN(plc && frame, PJ_EINVAL); plc->op->plc_generate(plc->obj, frame); return PJ_SUCCESS; } ////////////////////////////////////////////////////////////////////////////// /* * Packet loss concealment based on WSOLA */ struct wsola_plc { pjmedia_wsola *wsola; pj_bool_t prev_lost; }; static void* plc_wsola_create(pj_pool_t *pool, unsigned clock_rate, unsigned samples_per_frame) { struct wsola_plc *o; unsigned flag; pj_status_t status; PJ_UNUSED_ARG(clock_rate); o = PJ_POOL_ZALLOC_T(pool, struct wsola_plc); o->prev_lost = PJ_FALSE; flag = PJMEDIA_WSOLA_NO_DISCARD; if (PJMEDIA_WSOLA_PLC_NO_FADING) flag |= PJMEDIA_WSOLA_NO_FADING; status = pjmedia_wsola_create(pool, clock_rate, samples_per_frame, 1, flag, &o->wsola); if (status != PJ_SUCCESS) return NULL; return o; } static void plc_wsola_save(void *plc, pj_int16_t *frame) { struct wsola_plc *o = (struct wsola_plc*) plc; pjmedia_wsola_save(o->wsola, frame, o->prev_lost); o->prev_lost = PJ_FALSE; } static void plc_wsola_generate(void *plc, pj_int16_t *frame) { struct wsola_plc *o = (struct wsola_plc*) plc; pjmedia_wsola_generate(o->wsola, frame); o->prev_lost = PJ_TRUE; }