blob: 18ffd3c596309105493a58ac68a2e6d1f37119e4 [file] [log] [blame]
/* $Id$ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
*
* 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 <pjmedia/plc.h>
#include <pjmedia/errno.h>
#include <pjmedia/wsola.h>
#include <pj/assert.h>
#include <pj/pool.h>
#include <pj/string.h>
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;
}