Asterisk - The Open Source Telephony Project  21.4.1
asterisk-opus-a959f072d3f364be983dd27e6e250b038aaef747/codecs/codec_opus_open_source.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2014, Lorenzo Miniero
5  *
6  * Lorenzo Miniero <lorenzo@meetecho.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief Translate between signed linear and Opus (Open Codec)
22  *
23  * \author Lorenzo Miniero <lorenzo@meetecho.com>
24  *
25  * \note This work was motivated by Mozilla
26  *
27  * \ingroup codecs
28  *
29  * \extref http://www.opus-codec.org/docs/html_api-1.1.0/
30  *
31  */
32 
33 /*** MODULEINFO
34  <depend>opus</depend>
35  <conflict>codec_opus</conflict>
36  <defaultenabled>yes</defaultenabled>
37 ***/
38 
39 #include "asterisk.h"
40 
41 #if defined(ASTERISK_REGISTER_FILE)
42 ASTERISK_REGISTER_FILE()
43 #elif defined(ASTERISK_FILE_VERSION)
44 ASTERISK_FILE_VERSION(__FILE__, "$Revision: $")
45 #endif
46 
47 #include "asterisk/astobj2.h" /* for ao2_ref */
48 #include "asterisk/cli.h" /* for ast_cli_entry, ast_cli, etc */
49 #include "asterisk/codec.h" /* for ast_codec_get */
50 #include "asterisk/format.h" /* for ast_format_get_attribute_data */
51 #include "asterisk/frame.h" /* for ast_frame, etc */
52 #include "asterisk/linkedlists.h" /* for AST_LIST_NEXT, etc */
53 #include "asterisk/lock.h" /* for ast_atomic_fetchadd_int */
54 #include "asterisk/logger.h" /* for ast_log, LOG_ERROR, etc */
55 #include "asterisk/module.h"
56 #include "asterisk/translate.h" /* for ast_trans_pvt, etc */
57 #include "asterisk/utils.h" /* for ARRAY_LEN */
58 
59 #include <opus/opus.h>
60 
61 #include "asterisk/opus.h" /* for CODEC_OPUS_DEFAULT_* */
62 
63 #define BUFFER_SAMPLES 5760
64 #define MAX_CHANNELS 2
65 #define OPUS_SAMPLES 960
66 
67 /* Sample frame data */
68 #include "asterisk/slin.h"
69 #include "ex_opus.h"
70 
71 static struct codec_usage {
72  int encoder_id;
73  int decoder_id;
74  int encoders;
75  int decoders;
76 } usage;
77 
78 /*
79  * Stores the function pointer 'sample_count' of the cached ast_codec
80  * before this module was loaded. Allows to restore this previous
81  * function pointer, when this module in unloaded.
82  */
83 static struct ast_codec *opus_codec; /* codec of the cached format */
84 static int (*opus_samples_previous)(struct ast_frame *frame);
85 
86 /* Private structures */
88  void *opus; /* May be encoder or decoder */
89  int sampling_rate;
90  int multiplier;
91  int id;
92  int16_t buf[BUFFER_SAMPLES];
93  int framesize;
94  int inited;
95  int channels;
96  int decode_fec_incoming;
97  int previous_lost;
98 };
99 
100 struct opus_attr {
101  unsigned int maxbitrate;
102  unsigned int maxplayrate;
103  unsigned int unused; /* was minptime */
104  unsigned int stereo;
105  unsigned int cbr;
106  unsigned int fec;
107  unsigned int dtx;
108  unsigned int spropmaxcapturerate; /* FIXME: not utilised, yet */
109  unsigned int spropstereo; /* FIXME: currently, we are just mono */
110 };
111 
112 /* Helper methods */
113 static int opus_encoder_construct(struct ast_trans_pvt *pvt, int sampling_rate)
114 {
115  struct opus_coder_pvt *opvt = pvt->pvt;
116  struct opus_attr *attr = pvt->explicit_dst ? ast_format_get_attribute_data(pvt->explicit_dst) : NULL;
117  const opus_int32 bitrate = attr ? attr->maxbitrate : CODEC_OPUS_DEFAULT_BITRATE;
118  const int maxplayrate = attr ? attr->maxplayrate : CODEC_OPUS_DEFAULT_MAX_PLAYBACK_RATE;
119  const int channels = attr ? attr->stereo + 1 : CODEC_OPUS_DEFAULT_STEREO + 1;
120  const opus_int32 vbr = attr ? !(attr->cbr) : !CODEC_OPUS_DEFAULT_CBR;
121  const opus_int32 fec = attr ? attr->fec : CODEC_OPUS_DEFAULT_FEC;
122  const opus_int32 dtx = attr ? attr->dtx : CODEC_OPUS_DEFAULT_DTX;
123  const int application = OPUS_APPLICATION_VOIP;
124  int status = 0;
125 
126  opvt->opus = opus_encoder_create(sampling_rate, channels, application, &status);
127 
128  if (status != OPUS_OK) {
129  ast_log(LOG_ERROR, "Error creating the Opus encoder: %s\n", opus_strerror(status));
130  return -1;
131  }
132 
133  if (sampling_rate <= 8000 || maxplayrate <= 8000) {
134  status = opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
135  } else if (sampling_rate <= 12000 || maxplayrate <= 12000) {
136  status = opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND));
137  } else if (sampling_rate <= 16000 || maxplayrate <= 16000) {
138  status = opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
139  } else if (sampling_rate <= 24000 || maxplayrate <= 24000) {
140  status = opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
141  } /* else we use the default: OPUS_BANDWIDTH_FULLBAND */
142 
143  if (0 < bitrate && bitrate != 510000) {
144  status = opus_encoder_ctl(opvt->opus, OPUS_SET_BITRATE(bitrate));
145  } /* else we use the default: OPUS_AUTO */
146  status = opus_encoder_ctl(opvt->opus, OPUS_SET_VBR(vbr));
147  status = opus_encoder_ctl(opvt->opus, OPUS_SET_INBAND_FEC(fec));
148  status = opus_encoder_ctl(opvt->opus, OPUS_SET_DTX(dtx));
149 
150  opvt->sampling_rate = sampling_rate;
151  opvt->multiplier = 48000 / sampling_rate;
152  opvt->framesize = sampling_rate / 50;
153  opvt->id = ast_atomic_fetchadd_int(&usage.encoder_id, 1) + 1;
154 
155  ast_atomic_fetchadd_int(&usage.encoders, +1);
156 
157  ast_debug(3, "Created encoder #%d (%d -> opus)\n", opvt->id, sampling_rate);
158 
159  return 0;
160 }
161 
162 static int opus_decoder_construct(struct ast_trans_pvt *pvt, struct ast_frame *f)
163 {
164  struct opus_coder_pvt *opvt = pvt->pvt;
165  /* struct opus_attr *attr = ast_format_get_attribute_data(f->subclass.format); */
166  int error = 0;
167 
168  opvt->sampling_rate = pvt->t->dst_codec.sample_rate;
169  opvt->multiplier = 48000 / opvt->sampling_rate;
170  opvt->channels = /* attr ? attr->spropstereo + 1 :*/ 1; /* FIXME */
171 
172  opvt->opus = opus_decoder_create(opvt->sampling_rate, opvt->channels, &error);
173 
174  if (error != OPUS_OK) {
175  ast_log(LOG_ERROR, "Error creating the Opus decoder: %s\n", opus_strerror(error));
176  return -1;
177  }
178 
179  opvt->id = ast_atomic_fetchadd_int(&usage.decoder_id, 1) + 1;
180 
181  ast_atomic_fetchadd_int(&usage.decoders, +1);
182 
183  ast_debug(3, "Created decoder #%d (opus -> %d)\n", opvt->id, opvt->sampling_rate);
184 
185  return 0;
186 }
187 
188 /* Translator callbacks */
189 static int lintoopus_new(struct ast_trans_pvt *pvt)
190 {
191  return opus_encoder_construct(pvt, pvt->t->src_codec.sample_rate);
192 }
193 
194 static int opustolin_new(struct ast_trans_pvt *pvt)
195 {
196  struct opus_coder_pvt *opvt = pvt->pvt;
197 
198  opvt->previous_lost = 0; /* we are new and have not lost anything */
199  opvt->inited = 0; /* we do not know the "sprop" values, yet */
200 
201  return 0;
202 }
203 
204 static int lintoopus_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
205 {
206  struct opus_coder_pvt *opvt = pvt->pvt;
207 
208  /* XXX We should look at how old the rest of our stream is, and if it
209  is too old, then we should overwrite it entirely, otherwise we can
210  get artifacts of earlier talk that do not belong */
211  memcpy(opvt->buf + pvt->samples, f->data.ptr, f->datalen);
212  pvt->samples += f->samples;
213 
214  return 0;
215 }
216 
217 static struct ast_frame *lintoopus_frameout(struct ast_trans_pvt *pvt)
218 {
219  struct opus_coder_pvt *opvt = pvt->pvt;
220  struct ast_frame *result = NULL;
221  struct ast_frame *last = NULL;
222  int samples = 0; /* output samples */
223 
224  while (pvt->samples >= opvt->framesize) {
225  /* status is either error or output bytes */
226  const int status = opus_encode(opvt->opus,
227  opvt->buf + samples,
228  opvt->framesize,
229  pvt->outbuf.uc,
230  BUFFER_SAMPLES);
231 
232  samples += opvt->framesize;
233  pvt->samples -= opvt->framesize;
234 
235  if (status < 0) {
236  ast_log(LOG_ERROR, "Error encoding the Opus frame: %s\n", opus_strerror(status));
237  } else {
238  struct ast_frame *current = ast_trans_frameout(pvt,
239  status,
240  OPUS_SAMPLES);
241 
242  if (!current) {
243  continue;
244  } else if (last) {
245  AST_LIST_NEXT(last, frame_list) = current;
246  } else {
247  result = current;
248  }
249  last = current;
250  }
251  }
252 
253  /* Move the data at the end of the buffer to the front */
254  if (samples) {
255  memmove(opvt->buf, opvt->buf + samples, pvt->samples * 2);
256  }
257 
258  return result;
259 }
260 
261 static int opustolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
262 {
263  struct opus_coder_pvt *opvt = pvt->pvt;
264  int decode_fec;
265  int frame_size;
266  opus_int16 *dst;
267  opus_int32 len;
268  unsigned char *src;
269  int status;
270 
271  if (!opvt->inited && f->datalen == 0) {
272  return 0; /* we cannot start without data */
273  } else if (!opvt->inited) { /* 0 < f->datalen */
274  status = opus_decoder_construct(pvt, f);
275  opvt->inited = 1;
276  if (status) {
277  return status;
278  }
279  }
280 
281  /*
282  * When we get a frame indicator (ast_null_frame), format is NULL. Because FEC
283  * status can change any time (SDP re-negotiation), we save again and again.
284  */
285  if (f->subclass.format) {
287 
288  if (attr) {
289  opvt->decode_fec_incoming = attr->fec;
290  }
291  }
292  decode_fec = opvt->decode_fec_incoming;
293 
294  /*
295  * The Opus Codec, actually its library allows
296  * - Forward-Error Correction (FEC), and
297  * - native Packet-Loss Concealment (PLC).
298  * The sender might include FEC. If there is no FEC, because it was not send
299  * or the FEC data got lost, the API of the Opus library does PLC instead.
300  * Therefore we have three boolean variables:
301  * - current frame got lost: f->datalen == 0,
302  * - previous frame got lost: opvt->previous_lost, and
303  * - FEC negotiated on SDP layer: decode_fec.
304  * Now, we go through all cases. Because some cases use the same source code
305  * we have less than 8 (2^3) cases.
306  *
307  * Some notes on the coding style of this section:
308  * This code section is passed for each incoming frame, normally every
309  * 20 milliseconds. For each channel, this code is passed individually.
310  * Therefore, this code should be as performant as possible. On the other
311  * hand, PLC plus FEC is complicated. Therefore, code readability is one
312  * prerequisite to understand, debug, and review this code section. Because
313  * we do have optimising compilers, we are able to sacrify optimised code
314  * for code readability. If you find an error or unnecessary calculation
315  * which is not optimised = removed by your compiler, please, create an
316  * issue on <https://github.com/traud/asterisk-opus/issues>. I am just
317  * a human and human do mistakes. However, humans love to learn.
318  *
319  * Source-code examples are
320  * - <https://git.xiph.org/?p=opus.git;a=history;f=src/opus_demo.c>,
321  * - <https://freeswitch.org/stash/projects/FS/repos/freeswitch/browse/src/mod/codecs/mod_opus/mod_opus.c>
322  * and the official mailing list itself:
323  * <https://www.google.de/search?q=site:lists.xiph.org+opus>.
324  */
325 
326  /* Case 1 and 2 */
327  if (f->datalen == 0 && opvt->previous_lost) {
328  /*
329  * If this frame and the previous frame got lost, we do not have any
330  * data for FEC. Therefore, we go for PLC on the previous frame. However,
331  * the next frame could include FEC for the currently lost frame.
332  * Therefore, we "wait" for the next frame to fix the current frame.
333  */
334  decode_fec = 0; /* = do PLC */
335  opus_decoder_ctl(opvt->opus, OPUS_GET_LAST_PACKET_DURATION(&frame_size));
336  dst = pvt->outbuf.i16 + (pvt->samples * opvt->channels);
337  len = 0;
338  src = NULL;
339  status = opus_decode(opvt->opus, src, len, dst, frame_size, decode_fec);
340  if (status < 0) {
341  ast_log(LOG_ERROR, "%s\n", opus_strerror(status));
342  } else {
343  pvt->samples += status;
344  pvt->datalen += status * opvt->channels * sizeof(int16_t);
345  }
346  /*
347  * Save the state of the current frame, whether it is lost = "wait".
348  * That way, we are able to decide whether to do FEC next time.
349  */
350  opvt->previous_lost = (f->datalen == 0 || status < 0);
351  return 0;
352  }
353 
354  /* Case 3 */
355  if (f->datalen == 0 && !decode_fec) { /* !opvt->previous_lost */
356  /*
357  * The sender stated in SDP: "I am not going to provide FEC". Therefore,
358  * we do not wait for the next frame and do PLC right away.
359  */
360  decode_fec = 0;
361  opus_decoder_ctl(opvt->opus, OPUS_GET_LAST_PACKET_DURATION(&frame_size));
362  dst = pvt->outbuf.i16 + (pvt->samples * opvt->channels);
363  len = f->datalen;
364  src = NULL;
365  status = opus_decode(opvt->opus, src, len, dst, frame_size, decode_fec);
366  if (status < 0) {
367  ast_log(LOG_ERROR, "%s\n", opus_strerror(status));
368  } else {
369  pvt->samples += status;
370  pvt->datalen += status * opvt->channels * sizeof(int16_t);
371  }
372  opvt->previous_lost = (f->datalen == 0 || status < 0);
373  return 0;
374  }
375 
376  /* Case 4 */
377  if (f->datalen == 0) { /* decode_fec && !opvt->previous_lost */
378  /*
379  * The previous frame was of no issue. Therefore, we do not have to
380  * reconstruct it. We do not have any data in the current frame but the
381  * sender might give us FEC with the next frame. We cannot do anything
382  * but wait for the next frame. Till Asterisk 13.7, this creates the
383  * warning "opustolin48 did not update samples 0". Please, ignore this
384  * warning or apply the patch included in the GitHub repository.
385  */
386  status = 0; /* no samples to add currently */
387  if (status < 0) {
388  ast_log(LOG_ERROR, "%s\n", opus_strerror(status));
389  } else {
390  pvt->samples += status;
391  pvt->datalen += status * opvt->channels * sizeof(int16_t);
392  }
393  opvt->previous_lost = (f->datalen == 0 || status < 0);
394  return 0;
395  }
396 
397  /* Case 5 and 6 */
398  if (!opvt->previous_lost) { /* 0 < f->datalen */
399  /*
400  * The perfect case - the previous frame was not lost and we have data
401  * in the current frame. Therefore, neither FEC nor PLC are required.
402  */
403  decode_fec = 0;
404  frame_size = BUFFER_SAMPLES / opvt->multiplier; /* parse everything */
405  dst = pvt->outbuf.i16 + (pvt->samples * opvt->channels);
406  len = f->datalen;
407  src = f->data.ptr;
408  status = opus_decode(opvt->opus, src, len, dst, frame_size, decode_fec);
409  if (status < 0) {
410  ast_log(LOG_ERROR, "%s\n", opus_strerror(status));
411  } else {
412  pvt->samples += status;
413  pvt->datalen += status * opvt->channels * sizeof(int16_t);
414  }
415  opvt->previous_lost = (f->datalen == 0 || status < 0);
416  return 0;
417  }
418 
419  /* Case 7 */
420  if (!decode_fec) { /* 0 < f->datalen && opvt->previous_lost */
421  /*
422  * The previous frame got lost and the sender stated in SDP: "I am not
423  * going to provide FEC". Therefore, we do PLC. Furthermore, we try to
424  * decode the current frame because we have data. This creates jitter
425  * because we create double the amount of frames as normal, see
426  * <https://issues.asterisk.org/jira/browse/ASTERISK-25483>. If this is
427  * an issue for your use-case, please, file and issue report on
428  * <https://github.com/traud/asterisk-opus/issues>.
429  */
430  decode_fec = 0;
431  opus_decoder_ctl(opvt->opus, OPUS_GET_LAST_PACKET_DURATION(&frame_size));
432  dst = pvt->outbuf.i16 + (pvt->samples * opvt->channels);
433  len = 0;
434  src = NULL;
435  status = opus_decode(opvt->opus, src, len, dst, frame_size, decode_fec);
436  if (status < 0) {
437  ast_log(LOG_ERROR, "%s\n", opus_strerror(status));
438  } else {
439  pvt->samples += status;
440  pvt->datalen += status * opvt->channels * sizeof(int16_t);
441  }
442  decode_fec = 0;
443  frame_size = BUFFER_SAMPLES / opvt->multiplier; /* parse everything */
444  dst = pvt->outbuf.i16 + (pvt->samples * opvt->channels); /* append after PLC data */
445  len = f->datalen;
446  src = f->data.ptr;
447  status = opus_decode(opvt->opus, src, len, dst, frame_size, decode_fec);
448  if (status < 0) {
449  ast_log(LOG_ERROR, "%s\n", opus_strerror(status));
450  } else {
451  pvt->samples += status;
452  pvt->datalen += status * opvt->channels * sizeof(int16_t);
453  }
454  opvt->previous_lost = (f->datalen == 0 || status < 0);
455  return 0;
456  }
457 
458  /* Case 8; Last Case */
459  { /* 0 < f->datalen && opvt->previous_lost && decode_fec */
460  decode_fec = 1;
461  opus_decoder_ctl(opvt->opus, OPUS_GET_LAST_PACKET_DURATION(&frame_size));
462  dst = pvt->outbuf.i16 + (pvt->samples * opvt->channels);
463  len = f->datalen;
464  src = f->data.ptr;
465  status = opus_decode(opvt->opus, src, len, dst, frame_size, decode_fec);
466  if (status < 0) {
467  ast_log(LOG_ERROR, "%s\n", opus_strerror(status));
468  } else {
469  pvt->samples += status;
470  pvt->datalen += status * opvt->channels * sizeof(int16_t);
471  }
472  decode_fec = 0;
473  frame_size = BUFFER_SAMPLES / opvt->multiplier; /* parse everything */
474  dst = pvt->outbuf.i16 + (pvt->samples * opvt->channels); /* append after FEC data */
475  len = f->datalen;
476  src = f->data.ptr;
477  status = opus_decode(opvt->opus, src, len, dst, frame_size, decode_fec);
478  if (status < 0) {
479  ast_log(LOG_ERROR, "%s\n", opus_strerror(status));
480  } else {
481  pvt->samples += status;
482  pvt->datalen += status * opvt->channels * sizeof(int16_t);
483  }
484  opvt->previous_lost = (f->datalen == 0 || status < 0);
485  return 0;
486  }
487 }
488 
489 static void lintoopus_destroy(struct ast_trans_pvt *arg)
490 {
491  struct opus_coder_pvt *opvt = arg->pvt;
492 
493  if (!opvt || !opvt->opus) {
494  return;
495  }
496 
497  opus_encoder_destroy(opvt->opus);
498  opvt->opus = NULL;
499 
500  ast_atomic_fetchadd_int(&usage.encoders, -1);
501 
502  ast_debug(3, "Destroyed encoder #%d (%d->opus)\n", opvt->id, opvt->sampling_rate);
503 }
504 
505 static void opustolin_destroy(struct ast_trans_pvt *arg)
506 {
507  struct opus_coder_pvt *opvt = arg->pvt;
508 
509  if (!opvt || !opvt->opus) {
510  return;
511  }
512 
513  opus_decoder_destroy(opvt->opus);
514  opvt->opus = NULL;
515 
516  ast_atomic_fetchadd_int(&usage.decoders, -1);
517 
518  ast_debug(3, "Destroyed decoder #%d (opus->%d)\n", opvt->id, opvt->sampling_rate);
519 }
520 
521 static char *handle_cli_opus_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
522 {
523  struct codec_usage copy;
524 
525  switch (cmd) {
526  case CLI_INIT:
527  e->command = "opus show";
528  e->usage =
529  "Usage: opus show\n"
530  " Displays Opus encoder/decoder utilization.\n";
531  return NULL;
532  case CLI_GENERATE:
533  return NULL;
534  }
535 
536  if (a->argc != 2) {
537  return CLI_SHOWUSAGE;
538  }
539 
540  copy = usage;
541 
542  ast_cli(a->fd, "%d/%d encoders/decoders are in use.\n", copy.encoders, copy.decoders);
543 
544  return CLI_SUCCESS;
545 }
546 
547 /* Translators */
548 static struct ast_translator opustolin = {
550  .name = "opustolin",
551  .src_codec = {
552  .name = "opus",
553  .type = AST_MEDIA_TYPE_AUDIO,
554  .sample_rate = 48000,
555  },
556  .dst_codec = {
557  .name = "slin",
558  .type = AST_MEDIA_TYPE_AUDIO,
559  .sample_rate = 8000,
560  },
561  .format = "slin",
562  .newpvt = opustolin_new,
563  .framein = opustolin_framein,
564  .destroy = opustolin_destroy,
565  .sample = opus_sample,
566  .desc_size = sizeof(struct opus_coder_pvt),
567  .buffer_samples = (BUFFER_SAMPLES / (48000 / 8000)) * 2, /* because of possible FEC */
568  .buf_size = (BUFFER_SAMPLES / (48000 / 8000)) * MAX_CHANNELS * sizeof(opus_int16) * 2,
569  .native_plc = 1,
570 };
571 
572 static struct ast_translator lintoopus = {
574  .name = "lintoopus",
575  .src_codec = {
576  .name = "slin",
577  .type = AST_MEDIA_TYPE_AUDIO,
578  .sample_rate = 8000,
579  },
580  .dst_codec = {
581  .name = "opus",
582  .type = AST_MEDIA_TYPE_AUDIO,
583  .sample_rate = 48000,
584  },
585  .format = "opus",
586  .newpvt = lintoopus_new,
587  .framein = lintoopus_framein,
588  .frameout = lintoopus_frameout,
589  .destroy = lintoopus_destroy,
590  .sample = slin8_sample,
591  .desc_size = sizeof(struct opus_coder_pvt),
592  .buffer_samples = BUFFER_SAMPLES,
593  .buf_size = BUFFER_SAMPLES * 2,
594 };
595 
596 static struct ast_translator opustolin12 = {
598  .name = "opustolin12",
599  .src_codec = {
600  .name = "opus",
601  .type = AST_MEDIA_TYPE_AUDIO,
602  .sample_rate = 48000,
603  },
604  .dst_codec = {
605  .name = "slin",
606  .type = AST_MEDIA_TYPE_AUDIO,
607  .sample_rate = 12000,
608  },
609  .format = "slin12",
610  .newpvt = opustolin_new,
611  .framein = opustolin_framein,
612  .destroy = opustolin_destroy,
613  .sample = opus_sample,
614  .desc_size = sizeof(struct opus_coder_pvt),
615  .buffer_samples = (BUFFER_SAMPLES / (48000 / 12000)) * 2, /* because of possible FEC */
616  .buf_size = (BUFFER_SAMPLES / (48000 / 12000)) * MAX_CHANNELS * sizeof(opus_int16) * 2,
617  .native_plc = 1,
618 };
619 
620 static struct ast_translator lin12toopus = {
622  .name = "lin12toopus",
623  .src_codec = {
624  .name = "slin",
625  .type = AST_MEDIA_TYPE_AUDIO,
626  .sample_rate = 12000,
627  },
628  .dst_codec = {
629  .name = "opus",
630  .type = AST_MEDIA_TYPE_AUDIO,
631  .sample_rate = 48000,
632  },
633  .format = "opus",
634  .newpvt = lintoopus_new,
635  .framein = lintoopus_framein,
636  .frameout = lintoopus_frameout,
637  .destroy = lintoopus_destroy,
638  .desc_size = sizeof(struct opus_coder_pvt),
639  .buffer_samples = BUFFER_SAMPLES,
640  .buf_size = BUFFER_SAMPLES * 2,
641 };
642 
643 static struct ast_translator opustolin16 = {
645  .name = "opustolin16",
646  .src_codec = {
647  .name = "opus",
648  .type = AST_MEDIA_TYPE_AUDIO,
649  .sample_rate = 48000,
650  },
651  .dst_codec = {
652  .name = "slin",
653  .type = AST_MEDIA_TYPE_AUDIO,
654  .sample_rate = 16000,
655  },
656  .format = "slin16",
657  .newpvt = opustolin_new,
658  .framein = opustolin_framein,
659  .destroy = opustolin_destroy,
660  .sample = opus_sample,
661  .desc_size = sizeof(struct opus_coder_pvt),
662  .buffer_samples = (BUFFER_SAMPLES / (48000 / 16000)) * 2, /* because of possible FEC */
663  .buf_size = (BUFFER_SAMPLES / (48000 / 16000)) * MAX_CHANNELS * sizeof(opus_int16) * 2,
664  .native_plc = 1,
665 };
666 
667 static struct ast_translator lin16toopus = {
669  .name = "lin16toopus",
670  .src_codec = {
671  .name = "slin",
672  .type = AST_MEDIA_TYPE_AUDIO,
673  .sample_rate = 16000,
674  },
675  .dst_codec = {
676  .name = "opus",
677  .type = AST_MEDIA_TYPE_AUDIO,
678  .sample_rate = 48000,
679  },
680  .format = "opus",
681  .newpvt = lintoopus_new,
682  .framein = lintoopus_framein,
683  .frameout = lintoopus_frameout,
684  .destroy = lintoopus_destroy,
685  .sample = slin16_sample,
686  .desc_size = sizeof(struct opus_coder_pvt),
687  .buffer_samples = BUFFER_SAMPLES,
688  .buf_size = BUFFER_SAMPLES * 2,
689 };
690 
691 static struct ast_translator opustolin24 = {
693  .name = "opustolin24",
694  .src_codec = {
695  .name = "opus",
696  .type = AST_MEDIA_TYPE_AUDIO,
697  .sample_rate = 48000,
698  },
699  .dst_codec = {
700  .name = "slin",
701  .type = AST_MEDIA_TYPE_AUDIO,
702  .sample_rate = 24000,
703  },
704  .format = "slin24",
705  .newpvt = opustolin_new,
706  .framein = opustolin_framein,
707  .destroy = opustolin_destroy,
708  .sample = opus_sample,
709  .desc_size = sizeof(struct opus_coder_pvt),
710  .buffer_samples = (BUFFER_SAMPLES / (48000 / 24000)) * 2, /* because of possible FEC */
711  .buf_size = (BUFFER_SAMPLES / (48000 / 24000)) * MAX_CHANNELS * sizeof(opus_int16) * 2,
712  .native_plc = 1,
713 };
714 
715 static struct ast_translator lin24toopus = {
717  .name = "lin24toopus",
718  .src_codec = {
719  .name = "slin",
720  .type = AST_MEDIA_TYPE_AUDIO,
721  .sample_rate = 24000,
722  },
723  .dst_codec = {
724  .name = "opus",
725  .type = AST_MEDIA_TYPE_AUDIO,
726  .sample_rate = 48000,
727  },
728  .format = "opus",
729  .newpvt = lintoopus_new,
730  .framein = lintoopus_framein,
731  .frameout = lintoopus_frameout,
732  .destroy = lintoopus_destroy,
733  .desc_size = sizeof(struct opus_coder_pvt),
734  .buffer_samples = BUFFER_SAMPLES,
735  .buf_size = BUFFER_SAMPLES * 2,
736 };
737 
738 static struct ast_translator opustolin48 = {
740  .name = "opustolin48",
741  .src_codec = {
742  .name = "opus",
743  .type = AST_MEDIA_TYPE_AUDIO,
744  .sample_rate = 48000,
745  },
746  .dst_codec = {
747  .name = "slin",
748  .type = AST_MEDIA_TYPE_AUDIO,
749  .sample_rate = 48000,
750  },
751  .format = "slin48",
752  .newpvt = opustolin_new,
753  .framein = opustolin_framein,
754  .destroy = opustolin_destroy,
755  .sample = opus_sample,
756  .desc_size = sizeof(struct opus_coder_pvt),
757  .buffer_samples = BUFFER_SAMPLES * 2, /* twice, because of possible FEC */
758  .buf_size = BUFFER_SAMPLES * MAX_CHANNELS * sizeof(opus_int16) * 2,
759  .native_plc = 1,
760 };
761 
762 static struct ast_translator lin48toopus = {
764  .name = "lin48toopus",
765  .src_codec = {
766  .name = "slin",
767  .type = AST_MEDIA_TYPE_AUDIO,
768  .sample_rate = 48000,
769  },
770  .dst_codec = {
771  .name = "opus",
772  .type = AST_MEDIA_TYPE_AUDIO,
773  .sample_rate = 48000,
774  },
775  .format = "opus",
776  .newpvt = lintoopus_new,
777  .framein = lintoopus_framein,
778  .frameout = lintoopus_frameout,
779  .destroy = lintoopus_destroy,
780  .desc_size = sizeof(struct opus_coder_pvt),
781  .buffer_samples = BUFFER_SAMPLES,
782  .buf_size = BUFFER_SAMPLES * 2,
783 };
784 
785 static struct ast_cli_entry cli[] = {
786  AST_CLI_DEFINE(handle_cli_opus_show, "Display Opus codec utilization.")
787 };
788 
789 static int opus_samples(struct ast_frame *frame)
790 {
791  opus_int32 sampling_rate = 48000; /* FIXME */
792 
793  return opus_packet_get_nb_samples(frame->data.ptr, frame->datalen, sampling_rate);
794 }
795 
796 static int reload(void)
797 {
798  /* Reload does nothing */
800 }
801 
802 static int unload_module(void)
803 {
804  int res;
805 
806  opus_codec->samples_count = opus_samples_previous;
807  ao2_ref(opus_codec, -1);
808 
809  res = ast_unregister_translator(&opustolin);
810  res |= ast_unregister_translator(&lintoopus);
811  res |= ast_unregister_translator(&opustolin12);
812  res |= ast_unregister_translator(&lin12toopus);
813  res |= ast_unregister_translator(&opustolin16);
814  res |= ast_unregister_translator(&lin16toopus);
815  res |= ast_unregister_translator(&opustolin24);
816  res |= ast_unregister_translator(&lin24toopus);
817  res |= ast_unregister_translator(&opustolin48);
818  res |= ast_unregister_translator(&lin48toopus);
819 
820  ast_cli_unregister_multiple(cli, ARRAY_LEN(cli));
821 
822  return res;
823 }
824 
825 static int load_module(void)
826 {
827  int res;
828 
829  opus_codec = ast_codec_get("opus", AST_MEDIA_TYPE_AUDIO, 48000);
830  opus_samples_previous = opus_codec->samples_count;
831  opus_codec->samples_count = opus_samples;
832 
833  res = ast_register_translator(&opustolin);
834  res |= ast_register_translator(&lintoopus);
835  res |= ast_register_translator(&opustolin12);
836  res |= ast_register_translator(&lin12toopus);
837  res |= ast_register_translator(&opustolin16);
838  res |= ast_register_translator(&lin16toopus);
839  res |= ast_register_translator(&opustolin24);
840  res |= ast_register_translator(&lin24toopus);
841  res |= ast_register_translator(&opustolin48);
842  res |= ast_register_translator(&lin48toopus);
843 
844  ast_cli_register_multiple(cli, ARRAY_LEN(cli));
845 
846  return res;
847 }
848 
849 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Opus Coder/Decoder",
850  .load = load_module,
851  .unload = unload_module,
852  .reload = reload,
853  );
struct ast_frame * ast_trans_frameout(struct ast_trans_pvt *pvt, int datalen, int samples)
generic frameout function
Definition: translate.c:439
int datalen
actual space used in outbuf
Definition: translate.h:218
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
8-bit data
Descriptor of a translator.
Definition: translate.h:137
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
Support for translation of data formats. translate.c.
descriptor for a cli entry.
Definition: cli.h:171
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:439
Codec API.
unsigned char * uc
Definition: translate.h:222
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
static int copy(char *infile, char *outfile)
Utility function to copy a file.
void * ast_format_get_attribute_data(const struct ast_format *format)
Get the attribute data on a format.
Definition: format.c:125
struct ast_codec * ast_codec_get(const char *name, enum ast_media_type type, unsigned int sample_rate)
Retrieve a codec given a name, type, and sample rate.
Definition: codec.c:327
void * pvt
Definition: translate.h:219
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:757
struct ast_frame_subclass subclass
Utility functions.
Media Format API.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ast_register_translator(t)
See __ast_register_translator()
Definition: translate.h:258
Asterisk internal frame definitions.
int ast_unregister_translator(struct ast_translator *t)
Unregister a translator Unregisters the given translator.
Definition: translate.c:1350
A set of macros to manage forward-linked lists.
#define ast_debug(level,...)
Log a DEBUG message.
struct ast_codec dst_codec
Definition: translate.h:140
struct ast_format * explicit_dst
Definition: translate.h:237
Default structure for translators, with the basic fields and buffers, all allocated as part of the sa...
Definition: translate.h:213
struct ast_codec src_codec
Definition: translate.h:139
union ast_frame::@224 data
char * command
Definition: cli.h:186
Support for logging to various files, console and syslog Configuration in file logger.conf.
unsigned int sample_rate
Sample rate (number of samples carried in a second)
Definition: codec.h:52
const char * usage
Definition: cli.h:177
Standard Command Line Interface.
int(* samples_count)(struct ast_frame *frame)
Retrieve the number of samples in a frame.
Definition: codec.h:68
Data structure associated with a single frame of data.
struct ast_format * format
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
Represents a media codec within Asterisk.
Definition: codec.h:42