1 /**
2  * @file opus.c Opus Audio Codec
3  *
4  * Copyright (C) 2010 Creytiv.com
5  */
6 
7 #include <re.h>
8 #include <baresip.h>
9 #include <opus/opus.h>
10 #include "opus.h"
11 
12 
13 /**
14  * @defgroup opus opus
15  *
16  * The OPUS audio codec
17  *
18  * Supported version: libopus 1.0.0 or later
19  *
20  * Configuration options:
21  *
22  \verbatim
23   opus_bitrate    128000     # Average bitrate in [bps]
24   opus_cbr        {yes,no}   # Constant Bitrate (inverse of VBR)
25   opus_inbandfec  {yes,no}   # Enable inband Forward Error Correction (FEC)
26   opus_dtx        {yes,no}   # Enable Discontinuous Transmission (DTX)
27  \endverbatim
28  *
29  * References:
30  *
31  *    RFC 6716  Definition of the Opus Audio Codec
32  *    RFC 7587  RTP Payload Format for the Opus Speech and Audio Codec
33  *
34  *    http://opus-codec.org/downloads/
35  */
36 
37 
38 static bool opus_mirror;
39 static char fmtp[256] = "";
40 static char fmtp_mirror[256];
41 
42 
opus_fmtp_enc(struct mbuf * mb,const struct sdp_format * fmt,bool offer,void * arg)43 static int opus_fmtp_enc(struct mbuf *mb, const struct sdp_format *fmt,
44 			 bool offer, void *arg)
45 {
46 	bool mirror;
47 
48 	(void)arg;
49 	(void)offer;
50 
51 	if (!mb || !fmt)
52 		return 0;
53 
54 	mirror = !offer && str_isset(fmtp_mirror);
55 
56 	return mbuf_printf(mb, "a=fmtp:%s %s\r\n",
57 			   fmt->id, mirror ? fmtp_mirror : fmtp);
58 }
59 
60 
61 static struct aucodec opus = {
62 	.name      = "opus",
63 	.srate     = 48000,
64 	.crate     = 48000,
65 	.ch        = 2,
66 	.fmtp      = fmtp,
67 	.encupdh   = opus_encode_update,
68 	.ench      = opus_encode_frm,
69 	.decupdh   = opus_decode_update,
70 	.dech      = opus_decode_frm,
71 	.plch      = opus_decode_pkloss,
72 };
73 
74 
opus_mirror_params(const char * x)75 void opus_mirror_params(const char *x)
76 {
77 	if (!opus_mirror)
78 		return;
79 
80 	info("opus: mirror parameters: \"%s\"\n", x);
81 
82 	str_ncpy(fmtp_mirror, x, sizeof(fmtp_mirror));
83 }
84 
85 
module_init(void)86 static int module_init(void)
87 {
88 	struct conf *conf = conf_cur();
89 	uint32_t value;
90 	char *p = fmtp + str_len(fmtp);
91 	bool b, stereo = true, sprop_stereo = true;
92 	int n = 0;
93 
94 	conf_get_bool(conf, "opus_stereo", &stereo);
95 	conf_get_bool(conf, "opus_sprop_stereo", &sprop_stereo);
96 
97 	/* always set stereo parameter first */
98 	n = re_snprintf(p, sizeof(fmtp) - str_len(p),
99 			"stereo=%d;sprop-stereo=%d", stereo, sprop_stereo);
100 	if (n <= 0)
101 		return ENOMEM;
102 
103 	p += n;
104 
105 	if (0 == conf_get_u32(conf, "opus_bitrate", &value)) {
106 
107 		n = re_snprintf(p, sizeof(fmtp) - str_len(p),
108 				";maxaveragebitrate=%d", value);
109 		if (n <= 0)
110 			return ENOMEM;
111 
112 		p += n;
113 	}
114 
115 	if (0 == conf_get_bool(conf, "opus_cbr", &b)) {
116 
117 		n = re_snprintf(p, sizeof(fmtp) - str_len(p),
118 				";cbr=%d", b);
119 		if (n <= 0)
120 			return ENOMEM;
121 
122 		p += n;
123 	}
124 
125 	if (0 == conf_get_bool(conf, "opus_inbandfec", &b)) {
126 
127 		n = re_snprintf(p, sizeof(fmtp) - str_len(p),
128 				";useinbandfec=%d", b);
129 		if (n <= 0)
130 			return ENOMEM;
131 
132 		p += n;
133 	}
134 
135 	if (0 == conf_get_bool(conf, "opus_dtx", &b)) {
136 
137 		n = re_snprintf(p, sizeof(fmtp) - str_len(p),
138 				";usedtx=%d", b);
139 		if (n <= 0)
140 			return ENOMEM;
141 
142 		p += n;
143 	}
144 
145 	(void)conf_get_bool(conf, "opus_mirror", &opus_mirror);
146 
147 	if (opus_mirror) {
148 		opus.fmtp = NULL;
149 		opus.fmtp_ench = opus_fmtp_enc;
150 	}
151 
152 	debug("opus: fmtp=\"%s\"\n", fmtp);
153 
154 	aucodec_register(baresip_aucodecl(), &opus);
155 
156 	return 0;
157 }
158 
159 
module_close(void)160 static int module_close(void)
161 {
162 	aucodec_unregister(&opus);
163 
164 	return 0;
165 }
166 
167 
168 EXPORT_SYM const struct mod_export DECL_EXPORTS(opus) = {
169 	"opus",
170 	"audio codec",
171 	module_init,
172 	module_close,
173 };
174