summaryrefslogtreecommitdiff
path: root/modules/plc/plc.c
blob: 9f703c19982b8f00574a1812ff06b055d3c7d53b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/**
 * @file plc.c  PLC -- Packet Loss Concealment
 *
 * Copyright (C) 2010 Creytiv.com
 */
#include <spandsp.h>
#include <re.h>
#include <baresip.h>


/**
 * @defgroup plc plc
 *
 * Packet Loss Concealment (PLC) audio-filter using spandsp
 *
 */


struct plc_st {
	struct aufilt_dec_st af; /* base class */
	plc_state_t plc;
	size_t sampc;
};


static void destructor(void *arg)
{
	struct plc_st *st = arg;

	list_unlink(&st->af.le);
}


static int update(struct aufilt_dec_st **stp, void **ctx,
		  const struct aufilt *af, struct aufilt_prm *prm)
{
	struct plc_st *st;
	int err = 0;
	(void)ctx;
	(void)af;

	if (!stp || !prm)
		return EINVAL;

	if (*stp)
		return 0;

	/* XXX: add support for stereo PLC */
	if (prm->ch != 1) {
		warning("plc: only mono supported (ch=%u)\n", prm->ch);
		return ENOSYS;
	}

	st = mem_zalloc(sizeof(*st), destructor);
	if (!st)
		return ENOMEM;

	if (!plc_init(&st->plc)) {
		err = ENOMEM;
		goto out;
	}

	st->sampc = prm->srate * prm->ch * prm->ptime / 1000;

 out:
	if (err)
		mem_deref(st);
	else
		*stp = (struct aufilt_dec_st *)st;

	return err;
}


/*
 * PLC is only valid for Decoding (RX)
 *
 * NOTE: sampc == 0 , means Packet loss
 */
static int decode(struct aufilt_dec_st *st, int16_t *sampv, size_t *sampc)
{
	struct plc_st *plc = (struct plc_st *)st;

	if (*sampc)
		plc_rx(&plc->plc, sampv, (int)*sampc);
	else
		*sampc = plc_fillin(&plc->plc, sampv, (int)plc->sampc);

	return 0;
}


static struct aufilt plc = {
	LE_INIT, "plc", NULL, NULL, update, decode
};


static int module_init(void)
{
	aufilt_register(&plc);
	return 0;
}


static int module_close(void)
{
	aufilt_unregister(&plc);
	return 0;
}


EXPORT_SYM const struct mod_export DECL_EXPORTS(plc) = {
	"plc",
	"filter",
	module_init,
	module_close
};