asterisk/main/codec_builtin.c
Sean Bright 5c27fe2187 format: Reintroduce smoother flags
In review 4843 (ASTERISK-24858), we added a hack that forced a smoother
creation when sending signed linear so that the byte order was adjusted
during transmission. This was needed because smoother flags were lost
during the new format work that was done in Asterisk 13.

Rather than rolling that same hack into res_rtp_multicast, re-introduce
smoother flags so that formats can dictate their own options.

Change-Id: I77b835fba0e539c6ce50014a984766f63cab2c16
2017-05-30 15:10:20 -05:00

980 lines
23 KiB
C

/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2014, Digium, Inc.
*
* Joshua Colp <jcolp@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
*
* \brief Built-in supported codecs
*
* \author Joshua Colp <jcolp@digium.com>
*/
/*** MODULEINFO
<support_level>core</support_level>
***/
#include "asterisk.h"
#include "asterisk/ilbc.h"
#include "asterisk/logger.h"
#include "asterisk/astobj2.h"
#include "asterisk/codec.h"
#include "asterisk/format.h"
#include "asterisk/format_cache.h"
#include "asterisk/frame.h"
#include "asterisk/smoother.h"
int __ast_codec_register_with_format(struct ast_codec *codec, const char *format_name,
struct ast_module *mod);
enum frame_type {
TYPE_HIGH, /* 0x0 */
TYPE_LOW, /* 0x1 */
TYPE_SILENCE, /* 0x2 */
TYPE_DONTSEND /* 0x3 */
};
#define TYPE_MASK 0x3
static int g723_len(unsigned char buf)
{
enum frame_type type = buf & TYPE_MASK;
switch(type) {
case TYPE_DONTSEND:
return 0;
break;
case TYPE_SILENCE:
return 4;
break;
case TYPE_HIGH:
return 24;
break;
case TYPE_LOW:
return 20;
break;
default:
ast_log(LOG_WARNING, "Badly encoded frame (%u)\n", type);
}
return -1;
}
static int g723_samples(struct ast_frame *frame)
{
unsigned char *buf = frame->data.ptr;
int pos = 0, samples = 0, res;
while(pos < frame->datalen) {
res = g723_len(buf[pos]);
if (res <= 0)
break;
samples += 240;
pos += res;
}
return samples;
}
static int g723_length(unsigned int samples)
{
return (samples / 240) * 20;
}
static struct ast_codec g723 = {
.name = "g723",
.description = "G.723.1",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 8000,
.minimum_ms = 30,
.maximum_ms = 300,
.default_ms = 30,
.minimum_bytes = 20,
.samples_count = g723_samples,
.get_length = g723_length,
};
static int codec2_samples(struct ast_frame *frame)
{
return 160 * (frame->datalen / 6);
}
static int codec2_length(unsigned int samples)
{
return (samples / 160) * 6;
}
static struct ast_codec codec2 = {
.name = "codec2",
.description = "Codec 2",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 8000,
.minimum_ms = 20,
.maximum_ms = 300,
.default_ms = 20,
.minimum_bytes = 6,
.samples_count = codec2_samples,
.get_length = codec2_length,
.smooth = 1,
};
static int none_samples(struct ast_frame *frame)
{
return frame->datalen;
}
static int none_length(unsigned int samples) {
return samples;
}
static struct ast_codec none = {
.name = "none",
.description = "<Null> codec",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 8000, /* This must have some sample rate to prevent divide by 0 */
.minimum_ms = 10,
.maximum_ms = 150,
.default_ms = 20,
.minimum_bytes = 20,
.samples_count = none_samples,
.get_length = none_length,
};
static int ulaw_samples(struct ast_frame *frame)
{
return frame->datalen;
}
static int ulaw_length(unsigned int samples)
{
return samples;
}
static struct ast_codec ulaw = {
.name = "ulaw",
.description = "G.711 u-law",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 8000,
.minimum_ms = 10,
.maximum_ms = 150,
.default_ms = 20,
.minimum_bytes = 80,
.samples_count = ulaw_samples,
.get_length = ulaw_length,
.smooth = 1,
};
static struct ast_codec alaw = {
.name = "alaw",
.description = "G.711 a-law",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 8000,
.minimum_ms = 10,
.maximum_ms = 150,
.default_ms = 20,
.minimum_bytes = 80,
.samples_count = ulaw_samples,
.get_length = ulaw_length,
.smooth = 1,
};
static int gsm_samples(struct ast_frame *frame)
{
return 160 * (frame->datalen / 33);
}
static int gsm_length(unsigned int samples)
{
return (samples / 160) * 33;
}
static struct ast_codec gsm = {
.name = "gsm",
.description = "GSM",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 8000,
.minimum_ms = 20,
.maximum_ms = 300,
.default_ms = 20,
.minimum_bytes = 33,
.samples_count = gsm_samples,
.get_length = gsm_length,
.smooth = 1,
};
static int g726_samples(struct ast_frame *frame)
{
return frame->datalen * 2;
}
static int g726_length(unsigned int samples)
{
return samples / 2;
}
static struct ast_codec g726rfc3551 = {
.name = "g726",
.description = "G.726 RFC3551",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 8000,
.minimum_ms = 10,
.maximum_ms = 300,
.default_ms = 20,
.minimum_bytes = 40,
.samples_count = g726_samples,
.get_length = g726_length,
.smooth = 1,
};
static struct ast_codec g726aal2 = {
.name = "g726aal2",
.description = "G.726 AAL2",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 8000,
.minimum_ms = 10,
.maximum_ms = 300,
.default_ms = 20,
.minimum_bytes = 40,
.samples_count = g726_samples,
.get_length = g726_length,
.smooth = 1,
};
static struct ast_codec adpcm = {
.name = "adpcm",
.description = "Dialogic ADPCM",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 8000,
.minimum_ms = 10,
.maximum_ms = 300,
.default_ms = 20,
.minimum_bytes = 40,
.samples_count = g726_samples,
.get_length = g726_length,
.smooth = 1,
};
static int slin_samples(struct ast_frame *frame)
{
return frame->datalen / 2;
}
static int slin_length(unsigned int samples)
{
return samples * 2;
}
static struct ast_codec slin8 = {
.name = "slin",
.description = "16 bit Signed Linear PCM",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 8000,
.minimum_ms = 10,
.maximum_ms = 70,
.default_ms = 20,
.minimum_bytes = 160,
.samples_count = slin_samples,
.get_length = slin_length,
.smooth = 1,
.smoother_flags = AST_SMOOTHER_FLAG_BE | AST_SMOOTHER_FLAG_FORCED,
};
static struct ast_codec slin12 = {
.name = "slin",
.description = "16 bit Signed Linear PCM (12kHz)",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 12000,
.minimum_ms = 10,
.maximum_ms = 70,
.default_ms = 20,
.minimum_bytes = 240,
.samples_count = slin_samples,
.get_length = slin_length,
.smooth = 1,
.smoother_flags = AST_SMOOTHER_FLAG_BE | AST_SMOOTHER_FLAG_FORCED,
};
static struct ast_codec slin16 = {
.name = "slin",
.description = "16 bit Signed Linear PCM (16kHz)",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 16000,
.minimum_ms = 10,
.maximum_ms = 70,
.default_ms = 20,
.minimum_bytes = 320,
.samples_count = slin_samples,
.get_length = slin_length,
.smooth = 1,
.smoother_flags = AST_SMOOTHER_FLAG_BE | AST_SMOOTHER_FLAG_FORCED,
};
static struct ast_codec slin24 = {
.name = "slin",
.description = "16 bit Signed Linear PCM (24kHz)",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 24000,
.minimum_ms = 10,
.maximum_ms = 70,
.default_ms = 20,
.minimum_bytes = 480,
.samples_count = slin_samples,
.get_length = slin_length,
.smooth = 1,
.smoother_flags = AST_SMOOTHER_FLAG_BE | AST_SMOOTHER_FLAG_FORCED,
};
static struct ast_codec slin32 = {
.name = "slin",
.description = "16 bit Signed Linear PCM (32kHz)",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 32000,
.minimum_ms = 10,
.maximum_ms = 70,
.default_ms = 20,
.minimum_bytes = 640,
.samples_count = slin_samples,
.get_length = slin_length,
.smooth = 1,
.smoother_flags = AST_SMOOTHER_FLAG_BE | AST_SMOOTHER_FLAG_FORCED,
};
static struct ast_codec slin44 = {
.name = "slin",
.description = "16 bit Signed Linear PCM (44kHz)",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 44100,
.minimum_ms = 10,
.maximum_ms = 70,
.default_ms = 20,
.minimum_bytes = 882,
.samples_count = slin_samples,
.get_length = slin_length,
.smooth = 1,
.smoother_flags = AST_SMOOTHER_FLAG_BE | AST_SMOOTHER_FLAG_FORCED,
};
static struct ast_codec slin48 = {
.name = "slin",
.description = "16 bit Signed Linear PCM (48kHz)",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 48000,
.minimum_ms = 10,
.maximum_ms = 70,
.default_ms = 20,
.minimum_bytes = 960,
.samples_count = slin_samples,
.get_length = slin_length,
.smooth = 1,
.smoother_flags = AST_SMOOTHER_FLAG_BE | AST_SMOOTHER_FLAG_FORCED,
};
static struct ast_codec slin96 = {
.name = "slin",
.description = "16 bit Signed Linear PCM (96kHz)",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 96000,
.minimum_ms = 10,
.maximum_ms = 70,
.default_ms = 20,
.minimum_bytes = 1920,
.samples_count = slin_samples,
.get_length = slin_length,
.smooth = 1,
.smoother_flags = AST_SMOOTHER_FLAG_BE | AST_SMOOTHER_FLAG_FORCED,
};
static struct ast_codec slin192 = {
.name = "slin",
.description = "16 bit Signed Linear PCM (192kHz)",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 192000,
.minimum_ms = 10,
.maximum_ms = 70,
.default_ms = 20,
.minimum_bytes = 3840,
.samples_count = slin_samples,
.get_length = slin_length,
.smooth = 1,
.smoother_flags = AST_SMOOTHER_FLAG_BE | AST_SMOOTHER_FLAG_FORCED,
};
static int lpc10_samples(struct ast_frame *frame)
{
int samples = 22 * 8;
/* assumes that the RTP packet contains one LPC10 frame */
samples += (((char *)(frame->data.ptr))[7] & 0x1) * 8;
return samples;
}
static struct ast_codec lpc10 = {
.name = "lpc10",
.description = "LPC10",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 8000,
.minimum_ms = 20,
.maximum_ms = 20,
.default_ms = 20,
.minimum_bytes = 7,
.samples_count = lpc10_samples,
.smooth = 1,
};
static int g729_samples(struct ast_frame *frame)
{
return frame->datalen * 8;
}
static int g729_length(unsigned int samples)
{
return samples / 8;
}
static struct ast_codec g729a = {
.name = "g729",
.description = "G.729A",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 8000,
.minimum_ms = 10,
.maximum_ms = 230,
.default_ms = 20,
.minimum_bytes = 10,
.samples_count = g729_samples,
.get_length = g729_length,
.smooth = 1,
};
static unsigned char get_n_bits_at(unsigned char *data, int n, int bit)
{
int byte = bit / 8; /* byte containing first bit */
int rem = 8 - (bit % 8); /* remaining bits in first byte */
unsigned char ret = 0;
if (n <= 0 || n > 8)
return 0;
if (rem < n) {
ret = (data[byte] << (n - rem));
ret |= (data[byte + 1] >> (8 - n + rem));
} else {
ret = (data[byte] >> (rem - n));
}
return (ret & (0xff >> (8 - n)));
}
static int speex_get_wb_sz_at(unsigned char *data, int len, int bit)
{
static const int SpeexWBSubModeSz[] = {
4, 36, 112, 192,
352, 0, 0, 0 };
int off = bit;
unsigned char c;
/* skip up to two wideband frames */
if (((len * 8 - off) >= 5) &&
get_n_bits_at(data, 1, off)) {
c = get_n_bits_at(data, 3, off + 1);
off += SpeexWBSubModeSz[c];
if (((len * 8 - off) >= 5) &&
get_n_bits_at(data, 1, off)) {
c = get_n_bits_at(data, 3, off + 1);
off += SpeexWBSubModeSz[c];
if (((len * 8 - off) >= 5) &&
get_n_bits_at(data, 1, off)) {
ast_log(LOG_WARNING, "Encountered corrupt speex frame; too many wideband frames in a row.\n");
return -1;
}
}
}
return off - bit;
}
static int speex_samples(unsigned char *data, int len)
{
static const int SpeexSubModeSz[] = {
5, 43, 119, 160,
220, 300, 364, 492,
79, 0, 0, 0,
0, 0, 0, 0 };
static const int SpeexInBandSz[] = {
1, 1, 4, 4,
4, 4, 4, 4,
8, 8, 16, 16,
32, 32, 64, 64 };
int bit = 0;
int cnt = 0;
int off;
unsigned char c;
while ((len * 8 - bit) >= 5) {
/* skip wideband frames */
off = speex_get_wb_sz_at(data, len, bit);
if (off < 0) {
ast_log(LOG_WARNING, "Had error while reading wideband frames for speex samples\n");
break;
}
bit += off;
if ((len * 8 - bit) < 5)
break;
/* get control bits */
c = get_n_bits_at(data, 5, bit);
bit += 5;
if (c == 15) {
/* terminator */
break;
} else if (c == 14) {
/* in-band signal; next 4 bits contain signal id */
c = get_n_bits_at(data, 4, bit);
bit += 4;
bit += SpeexInBandSz[c];
} else if (c == 13) {
/* user in-band; next 4 bits contain msg len */
c = get_n_bits_at(data, 4, bit);
bit += 4;
/* after which it's 5-bit signal id + c bytes of data */
bit += 5 + c * 8;
} else if (c > 8) {
/* unknown */
ast_log(LOG_WARNING, "Unknown speex control frame %d\n", c);
break;
} else {
/* skip number bits for submode (less the 5 control bits) */
bit += SpeexSubModeSz[c] - 5;
cnt += 160; /* new frame */
}
}
return cnt;
}
static int speex8_samples(struct ast_frame *frame)
{
return speex_samples(frame->data.ptr, frame->datalen);
}
static struct ast_codec speex8 = {
.name = "speex",
.description = "SpeeX",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 8000,
.minimum_ms = 10,
.maximum_ms = 60,
.default_ms = 20,
.minimum_bytes = 10,
.samples_count = speex8_samples,
};
static int speex16_samples(struct ast_frame *frame)
{
return 2 * speex_samples(frame->data.ptr, frame->datalen);
}
static struct ast_codec speex16 = {
.name = "speex",
.description = "SpeeX 16khz",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 16000,
.minimum_ms = 10,
.maximum_ms = 60,
.default_ms = 20,
.minimum_bytes = 10,
.samples_count = speex16_samples,
};
static int speex32_samples(struct ast_frame *frame)
{
return 4 * speex_samples(frame->data.ptr, frame->datalen);
}
static struct ast_codec speex32 = {
.name = "speex",
.description = "SpeeX 32khz",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 32000,
.minimum_ms = 10,
.maximum_ms = 60,
.default_ms = 20,
.minimum_bytes = 10,
.samples_count = speex32_samples,
};
static int ilbc_samples(struct ast_frame *frame)
{
struct ilbc_attr *attr = ast_format_get_attribute_data(frame->subclass.format);
const unsigned int mode = attr ? attr->mode : 30;
const unsigned int samples_per_frame = mode * ast_format_get_sample_rate(frame->subclass.format) / 1000;
const unsigned int octets_per_frame = (mode == 20) ? 38 : 50;
return samples_per_frame * frame->datalen / octets_per_frame;
}
static struct ast_codec ilbc = {
.name = "ilbc",
.description = "iLBC",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 8000,
.minimum_ms = 20,
.maximum_ms = 300,
.default_ms = 20,
.minimum_bytes = 38,
.samples_count = ilbc_samples,
.smooth = 0,
};
static struct ast_codec g722 = {
.name = "g722",
.description = "G722",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 16000,
.minimum_ms = 10,
.maximum_ms = 150,
.default_ms = 20,
.minimum_bytes = 80,
.samples_count = g726_samples,
.get_length = g726_length,
.smooth = 1,
};
static int siren7_samples(struct ast_frame *frame)
{
return frame->datalen * (16000 / 4000);
}
static int siren7_length(unsigned int samples)
{
return samples / (16000 / 4000);
}
static struct ast_codec siren7 = {
.name = "siren7",
.description = "ITU G.722.1 (Siren7, licensed from Polycom)",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 16000,
.minimum_ms = 20,
.maximum_ms = 80,
.default_ms = 20,
.minimum_bytes = 80,
.samples_count = siren7_samples,
.get_length = siren7_length,
};
static int siren14_samples(struct ast_frame *frame)
{
return (int) frame->datalen * ((float) 32000 / 6000);
}
static int siren14_length(unsigned int samples)
{
return (int) samples / ((float) 32000 / 6000);;
}
static struct ast_codec siren14 = {
.name = "siren14",
.description = "ITU G.722.1 Annex C, (Siren14, licensed from Polycom)",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 32000,
.minimum_ms = 20,
.maximum_ms = 80,
.default_ms = 20,
.minimum_bytes = 120,
.samples_count = siren14_samples,
.get_length = siren14_length,
};
static struct ast_codec testlaw = {
.name = "testlaw",
.description = "G.711 test-law",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 8000,
.minimum_ms = 10,
.maximum_ms = 150,
.default_ms = 20,
.minimum_bytes = 80,
.samples_count = ulaw_samples,
.get_length = ulaw_length,
.smooth = 1,
};
static int g719_samples(struct ast_frame *frame)
{
return (int) frame->datalen * ((float) 48000 / 8000);
}
static int g719_length(unsigned int samples)
{
return (int) samples / ((float) 48000 / 8000);
}
static struct ast_codec g719 = {
.name = "g719",
.description = "ITU G.719",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 48000,
.minimum_ms = 20,
.maximum_ms = 80,
.default_ms = 20,
.minimum_bytes = 160,
.samples_count = g719_samples,
.get_length = g719_length,
};
static int opus_samples(struct ast_frame *frame)
{
/*
* XXX This is likely not at all what's intended from this
* callback. If you have codec_opus.so loaded then this
* function is overridden anyway. However, since opus is
* variable bit rate and I cannot extract the calculation code
* from the opus library, I am going to punt and assume 20ms
* worth of samples. In testing, this has worked just fine.
* Pass through support doesn't seem to care about the value
* returned anyway.
*/
return ast_format_get_sample_rate(frame->subclass.format) / 50;
}
static struct ast_codec opus = {
.name = "opus",
.description = "Opus Codec",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 48000,
.minimum_ms = 20,
.maximum_ms = 60,
.default_ms = 20,
.samples_count = opus_samples,
.minimum_bytes = 10,
};
static struct ast_codec jpeg = {
.name = "jpeg",
.description = "JPEG image",
.type = AST_MEDIA_TYPE_IMAGE,
};
static struct ast_codec png = {
.name = "png",
.description = "PNG Image",
.type = AST_MEDIA_TYPE_IMAGE,
};
static struct ast_codec h261 = {
.name = "h261",
.description = "H.261 video",
.type = AST_MEDIA_TYPE_VIDEO,
.sample_rate = 1000,
};
static struct ast_codec h263 = {
.name = "h263",
.description = "H.263 video",
.type = AST_MEDIA_TYPE_VIDEO,
.sample_rate = 1000,
};
static struct ast_codec h263p = {
.name = "h263p",
.description = "H.263+ video",
.type = AST_MEDIA_TYPE_VIDEO,
.sample_rate = 1000,
};
static struct ast_codec h264 = {
.name = "h264",
.description = "H.264 video",
.type = AST_MEDIA_TYPE_VIDEO,
.sample_rate = 1000,
};
static struct ast_codec mpeg4 = {
.name = "mpeg4",
.description = "MPEG4 video",
.type = AST_MEDIA_TYPE_VIDEO,
.sample_rate = 1000,
};
static struct ast_codec vp8 = {
.name = "vp8",
.description = "VP8 video",
.type = AST_MEDIA_TYPE_VIDEO,
.sample_rate = 1000,
};
static struct ast_codec t140red = {
.name = "red",
.description = "T.140 Realtime Text with redundancy",
.type = AST_MEDIA_TYPE_TEXT,
};
static struct ast_codec t140 = {
.name = "t140",
.description = "Passthrough T.140 Realtime Text",
.type = AST_MEDIA_TYPE_TEXT,
};
static struct ast_codec t38 = {
.name = "t38",
.description = "T.38 UDPTL Fax",
.type = AST_MEDIA_TYPE_IMAGE,
};
static int silk_samples(struct ast_frame *frame)
{
/* XXX This is likely not at all what's intended from this callback. However,
* since SILK is variable bit rate, I have no idea how to take a frame of data
* and determine the number of samples present. Instead, we base this on the
* sample rate of the codec and the expected number of samples to receive in 20ms.
* In testing, this has worked just fine.
*/
return ast_format_get_sample_rate(frame->subclass.format) / 50;
}
static struct ast_codec silk8 = {
.name = "silk",
.description = "SILK Codec (8 KHz)",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 8000,
.minimum_ms = 20,
.maximum_ms = 100,
.default_ms = 20,
.minimum_bytes = 160,
.samples_count = silk_samples
};
static struct ast_codec silk12 = {
.name = "silk",
.description = "SILK Codec (12 KHz)",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 12000,
.minimum_ms = 20,
.maximum_ms = 100,
.default_ms = 20,
.minimum_bytes = 240,
.samples_count = silk_samples
};
static struct ast_codec silk16 = {
.name = "silk",
.description = "SILK Codec (16 KHz)",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 16000,
.minimum_ms = 20,
.maximum_ms = 100,
.default_ms = 20,
.minimum_bytes = 320,
.samples_count = silk_samples
};
static struct ast_codec silk24 = {
.name = "silk",
.description = "SILK Codec (24 KHz)",
.type = AST_MEDIA_TYPE_AUDIO,
.sample_rate = 24000,
.minimum_ms = 20,
.maximum_ms = 100,
.default_ms = 20,
.minimum_bytes = 480,
.samples_count = silk_samples
};
#define CODEC_REGISTER_AND_CACHE(codec) \
({ \
int __res_ ## __LINE__ = 0; \
struct ast_format *__fmt_ ## __LINE__; \
struct ast_codec *__codec_ ## __LINE__; \
res |= __ast_codec_register_with_format(&(codec), (codec).name, NULL); \
__codec_ ## __LINE__ = ast_codec_get((codec).name, (codec).type, (codec).sample_rate); \
__fmt_ ## __LINE__ = __codec_ ## __LINE__ ? ast_format_create(__codec_ ## __LINE__) : NULL; \
res |= ast_format_cache_set(__fmt_ ## __LINE__); \
ao2_ref(__fmt_ ## __LINE__, -1); \
ao2_ref(__codec_ ## __LINE__, -1); \
__res_ ## __LINE__; \
})
#define CODEC_REGISTER_AND_CACHE_NAMED(fmt_name, codec) \
({ \
int __res_ ## __LINE__ = 0; \
struct ast_format *__fmt_ ## __LINE__; \
struct ast_codec *__codec_ ## __LINE__; \
res |= __ast_codec_register_with_format(&(codec), fmt_name, NULL); \
__codec_ ## __LINE__ = ast_codec_get((codec).name, (codec).type, (codec).sample_rate); \
__fmt_ ## __LINE__ = ast_format_create_named((fmt_name), __codec_ ## __LINE__); \
res |= ast_format_cache_set(__fmt_ ## __LINE__); \
ao2_ref(__fmt_ ## __LINE__, -1); \
ao2_ref(__codec_ ## __LINE__, -1); \
__res_ ## __LINE__; \
})
int ast_codec_builtin_init(void)
{
int res = 0;
res |= CODEC_REGISTER_AND_CACHE(codec2);
res |= CODEC_REGISTER_AND_CACHE(g723);
res |= CODEC_REGISTER_AND_CACHE(ulaw);
res |= CODEC_REGISTER_AND_CACHE(alaw);
res |= CODEC_REGISTER_AND_CACHE(gsm);
res |= CODEC_REGISTER_AND_CACHE(g726rfc3551);
res |= CODEC_REGISTER_AND_CACHE(g726aal2);
res |= CODEC_REGISTER_AND_CACHE(adpcm);
res |= CODEC_REGISTER_AND_CACHE(slin8);
res |= CODEC_REGISTER_AND_CACHE_NAMED("slin12", slin12);
res |= CODEC_REGISTER_AND_CACHE_NAMED("slin16", slin16);
res |= CODEC_REGISTER_AND_CACHE_NAMED("slin24", slin24);
res |= CODEC_REGISTER_AND_CACHE_NAMED("slin32", slin32);
res |= CODEC_REGISTER_AND_CACHE_NAMED("slin44", slin44);
res |= CODEC_REGISTER_AND_CACHE_NAMED("slin48", slin48);
res |= CODEC_REGISTER_AND_CACHE_NAMED("slin96", slin96);
res |= CODEC_REGISTER_AND_CACHE_NAMED("slin192", slin192);
res |= CODEC_REGISTER_AND_CACHE(lpc10);
res |= CODEC_REGISTER_AND_CACHE(g729a);
res |= CODEC_REGISTER_AND_CACHE(speex8);
res |= CODEC_REGISTER_AND_CACHE_NAMED("speex16", speex16);
res |= CODEC_REGISTER_AND_CACHE_NAMED("speex32", speex32);
res |= CODEC_REGISTER_AND_CACHE(ilbc);
res |= CODEC_REGISTER_AND_CACHE(g722);
res |= CODEC_REGISTER_AND_CACHE(siren7);
res |= CODEC_REGISTER_AND_CACHE(siren14);
res |= CODEC_REGISTER_AND_CACHE(testlaw);
res |= CODEC_REGISTER_AND_CACHE(g719);
res |= CODEC_REGISTER_AND_CACHE(opus);
res |= CODEC_REGISTER_AND_CACHE(jpeg);
res |= CODEC_REGISTER_AND_CACHE(png);
res |= CODEC_REGISTER_AND_CACHE(h261);
res |= CODEC_REGISTER_AND_CACHE(h263);
res |= CODEC_REGISTER_AND_CACHE(h263p);
res |= CODEC_REGISTER_AND_CACHE(h264);
res |= CODEC_REGISTER_AND_CACHE(mpeg4);
res |= CODEC_REGISTER_AND_CACHE(vp8);
res |= CODEC_REGISTER_AND_CACHE(t140red);
res |= CODEC_REGISTER_AND_CACHE(t140);
res |= CODEC_REGISTER_AND_CACHE(t38);
res |= CODEC_REGISTER_AND_CACHE(none);
res |= CODEC_REGISTER_AND_CACHE_NAMED("silk8", silk8);
res |= CODEC_REGISTER_AND_CACHE_NAMED("silk12", silk12);
res |= CODEC_REGISTER_AND_CACHE_NAMED("silk16", silk16);
res |= CODEC_REGISTER_AND_CACHE_NAMED("silk24", silk24);
return res;
}