Adds pass-through support for codec CELT.
This patch adds pass-through support for CELT. CELT formats are defined in codecs.conf and can be configured to any sample rate a CELT endpoint supports. This patch also addresses a crash in channel.c resulting from a frame list being freed incorrectly. This crash was discovered while testing a CELT translator which had to split encoded audio into multiple frames. The codec translator is not a part of this patch, but may be contributed in the future. Review: https://reviewboard.asterisk.org/r/1294/ git-svn-id: http://svn.digium.com/svn/asterisk/trunk@326855 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
parent
0847f36c97
commit
d94bb98bec
|
@ -9468,6 +9468,7 @@ static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_
|
|||
|
||||
if ((format = ast_rtp_codecs_get_payload_format(newaudiortp, codec))) {
|
||||
unsigned int bit_rate;
|
||||
int val = 0;
|
||||
|
||||
switch ((int) format->id) {
|
||||
case AST_FORMAT_SIREN7:
|
||||
|
@ -9500,20 +9501,21 @@ static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_
|
|||
}
|
||||
}
|
||||
break;
|
||||
case AST_FORMAT_SILK:
|
||||
{
|
||||
int val = 0;
|
||||
if (sscanf(fmtp_string, "maxaveragebitrate=%30u", &val) == 1) {
|
||||
ast_format_append(format, SILK_ATTR_KEY_MAX_BITRATE, val, AST_FORMAT_ATTR_END);
|
||||
}
|
||||
if (sscanf(fmtp_string, "usedtx=%30u", &val) == 1) {
|
||||
ast_format_append(format, SILK_ATTR_KEY_DTX, val ? 1 : 0, AST_FORMAT_ATTR_END);
|
||||
}
|
||||
if (sscanf(fmtp_string, "useinbandfec=%30u", &val) == 1) {
|
||||
ast_format_append(format, SILK_ATTR_KEY_FEC, val ? 1 : 0, AST_FORMAT_ATTR_END);
|
||||
}
|
||||
break;
|
||||
case AST_FORMAT_CELT:
|
||||
if (sscanf(fmtp_string, "framesize=%30u", &val) == 1) {
|
||||
ast_format_append(format, CELT_ATTR_KEY_FRAME_SIZE, val, AST_FORMAT_ATTR_END);
|
||||
}
|
||||
case AST_FORMAT_SILK:
|
||||
if (sscanf(fmtp_string, "maxaveragebitrate=%30u", &val) == 1) {
|
||||
ast_format_append(format, SILK_ATTR_KEY_MAX_BITRATE, val, AST_FORMAT_ATTR_END);
|
||||
}
|
||||
if (sscanf(fmtp_string, "usedtx=%30u", &val) == 1) {
|
||||
ast_format_append(format, SILK_ATTR_KEY_DTX, val ? 1 : 0, AST_FORMAT_ATTR_END);
|
||||
}
|
||||
if (sscanf(fmtp_string, "useinbandfec=%30u", &val) == 1) {
|
||||
ast_format_append(format, SILK_ATTR_KEY_FEC, val ? 1 : 0, AST_FORMAT_ATTR_END);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10829,7 +10831,7 @@ static void add_codec_to_sdp(const struct sip_pvt *p,
|
|||
{
|
||||
int rtp_code;
|
||||
struct ast_format_list fmt;
|
||||
|
||||
int val = 0;
|
||||
|
||||
if (debug)
|
||||
ast_verbose("Adding codec %d (%s) to SDP\n", format->id, ast_getformatname(format));
|
||||
|
@ -10872,20 +10874,22 @@ static void add_codec_to_sdp(const struct sip_pvt *p,
|
|||
/* Indicate that we only expect 64Kbps */
|
||||
ast_str_append(a_buf, 0, "a=fmtp:%d bitrate=64000\r\n", rtp_code);
|
||||
break;
|
||||
case AST_FORMAT_SILK:
|
||||
{
|
||||
int val = 0;
|
||||
if (!ast_format_get_value(format, SILK_ATTR_KEY_MAX_BITRATE, &val) && val > 5000 && val < 40000) {
|
||||
ast_str_append(a_buf, 0, "a=fmtp:%d maxaveragebitrate=%u\r\n", rtp_code, val);
|
||||
}
|
||||
if (!ast_format_get_value(format, SILK_ATTR_KEY_DTX, &val)) {
|
||||
ast_str_append(a_buf, 0, "a=fmtp:%d usedtx=%u\r\n", rtp_code, val ? 1 : 0);
|
||||
}
|
||||
if (!ast_format_get_value(format, SILK_ATTR_KEY_FEC, &val)) {
|
||||
ast_str_append(a_buf, 0, "a=fmtp:%d useinbandfec=%u\r\n", rtp_code, val ? 1 : 0);
|
||||
}
|
||||
break;
|
||||
case AST_FORMAT_CELT:
|
||||
if (!ast_format_get_value(format, CELT_ATTR_KEY_FRAME_SIZE, &val) && val > 0) {
|
||||
ast_str_append(a_buf, 0, "a=fmtp:%d framesize=%u\r\n", rtp_code, val);
|
||||
}
|
||||
break;
|
||||
case AST_FORMAT_SILK:
|
||||
if (!ast_format_get_value(format, SILK_ATTR_KEY_MAX_BITRATE, &val) && val > 5000 && val < 40000) {
|
||||
ast_str_append(a_buf, 0, "a=fmtp:%d maxaveragebitrate=%u\r\n", rtp_code, val);
|
||||
}
|
||||
if (!ast_format_get_value(format, SILK_ATTR_KEY_DTX, &val)) {
|
||||
ast_str_append(a_buf, 0, "a=fmtp:%d usedtx=%u\r\n", rtp_code, val ? 1 : 0);
|
||||
}
|
||||
if (!ast_format_get_value(format, SILK_ATTR_KEY_FEC, &val)) {
|
||||
ast_str_append(a_buf, 0, "a=fmtp:%d useinbandfec=%u\r\n", rtp_code, val ? 1 : 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (fmt.cur_ms && (fmt.cur_ms < *min_packet_size))
|
||||
|
|
|
@ -126,7 +126,6 @@ maxbitrate=20000
|
|||
fec=true
|
||||
packetloss_percentage=10;
|
||||
|
||||
|
||||
[silk24]
|
||||
type=silk
|
||||
samprate=24000
|
||||
|
@ -134,3 +133,21 @@ maxbitrate=30000
|
|||
fec=true
|
||||
packetloss_percentage=10;
|
||||
|
||||
|
||||
; Default custom CELT codec definitions. Only one custom CELT definition is allowed
|
||||
; per a sample rate.
|
||||
;[celt44]
|
||||
;type=celt
|
||||
;samprate=44100 ; The samplerate in hz. This option is required.
|
||||
;framesize=480 ; The framesize option represents the duration of each frame in samples.
|
||||
; This must be a factor of 2. This option is only advertised in an SDP
|
||||
; when it is set. Otherwise a default of framesize of 480 is assumed
|
||||
; internally
|
||||
|
||||
;[celt48]
|
||||
;type=celt
|
||||
;samprate=48000
|
||||
|
||||
;[celt32]
|
||||
;type=celt
|
||||
;samprate=32000
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "asterisk/astobj2.h"
|
||||
#include "asterisk/silk.h"
|
||||
#include "asterisk/celt.h"
|
||||
#define AST_FORMAT_ATTR_SIZE 128
|
||||
#define AST_FORMAT_INC 100000
|
||||
|
||||
|
@ -99,6 +100,7 @@ enum ast_format_id {
|
|||
/*! Raw 16-bit Signed Linear (192000 Hz) PCM. maybe we're taking this too far. */
|
||||
AST_FORMAT_SLINEAR192 = 27 + AST_FORMAT_TYPE_AUDIO,
|
||||
AST_FORMAT_SPEEX32 = 28 + AST_FORMAT_TYPE_AUDIO,
|
||||
AST_FORMAT_CELT = 29 + AST_FORMAT_TYPE_AUDIO,
|
||||
|
||||
/*! H.261 Video */
|
||||
AST_FORMAT_H261 = 1 + AST_FORMAT_TYPE_VIDEO,
|
||||
|
|
|
@ -1081,6 +1081,8 @@ struct ast_format *ast_best_codec(struct ast_format_cap *cap, struct ast_format
|
|||
AST_FORMAT_SPEEX,
|
||||
/*! SILK is pretty awesome. */
|
||||
AST_FORMAT_SILK,
|
||||
/*! CELT supports crazy high sample rates */
|
||||
AST_FORMAT_CELT,
|
||||
/*! Ick, LPC10 sounds terrible, but at least we have code for it, if you're tacky enough
|
||||
to use it */
|
||||
AST_FORMAT_LPC10,
|
||||
|
@ -5019,12 +5021,13 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
|
|||
from the single frame we passed in; if so, feed each one of them to the
|
||||
channel, freeing each one after it has been written */
|
||||
if ((f != fr) && AST_LIST_NEXT(f, frame_list)) {
|
||||
struct ast_frame *cur, *next;
|
||||
struct ast_frame *cur, *next = NULL;
|
||||
unsigned int skip = 0;
|
||||
|
||||
for (cur = f, next = AST_LIST_NEXT(cur, frame_list);
|
||||
cur;
|
||||
cur = next, next = cur ? AST_LIST_NEXT(cur, frame_list) : NULL) {
|
||||
cur = f;
|
||||
while (cur) {
|
||||
next = AST_LIST_NEXT(cur, frame_list);
|
||||
AST_LIST_NEXT(cur, frame_list) = NULL;
|
||||
if (!skip) {
|
||||
if ((res = chan->tech->write(chan, cur)) < 0) {
|
||||
chan->_softhangup |= AST_SOFTHANGUP_DEV;
|
||||
|
@ -5037,6 +5040,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
|
|||
}
|
||||
}
|
||||
ast_frfree(cur);
|
||||
cur = next;
|
||||
}
|
||||
|
||||
/* reset f so the code below doesn't attempt to free it */
|
||||
|
|
|
@ -748,6 +748,15 @@ int ast_format_rate(const struct ast_format *format)
|
|||
} else {
|
||||
return 8000;
|
||||
}
|
||||
case AST_FORMAT_CELT:
|
||||
{
|
||||
int samplerate;
|
||||
if (!(ast_format_get_value(format,
|
||||
CELT_ATTR_KEY_SAMP_RATE,
|
||||
&samplerate))) {
|
||||
return samplerate;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return 8000;
|
||||
}
|
||||
|
@ -1085,6 +1094,32 @@ init_cleanup:
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int custom_celt_format(struct ast_format_list *entry, unsigned int maxbitrate, unsigned int framesize)
|
||||
{
|
||||
if (!entry->samplespersecond) {
|
||||
ast_log(LOG_WARNING, "Custom CELT format definition '%s' requires sample rate to be defined.\n", entry->name);
|
||||
}
|
||||
ast_format_set(&entry->format, AST_FORMAT_CELT, 0);
|
||||
if (!has_interface(&entry->format)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(entry->desc, sizeof(entry->desc), "CELT Custom Format %dkhz", entry->samplespersecond/1000);
|
||||
|
||||
ast_format_append(&entry->format,
|
||||
CELT_ATTR_KEY_SAMP_RATE, entry->samplespersecond,
|
||||
CELT_ATTR_KEY_MAX_BITRATE, maxbitrate,
|
||||
CELT_ATTR_KEY_FRAME_SIZE, framesize,
|
||||
AST_FORMAT_ATTR_END);
|
||||
|
||||
entry->fr_len = 80;
|
||||
entry->min_ms = 20;
|
||||
entry->max_ms = 20;
|
||||
entry->inc_ms = 20;
|
||||
entry->def_ms = 20;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int custom_silk_format(struct ast_format_list *entry, unsigned int maxbitrate, int usedtx, int usefec, int packetloss_percentage)
|
||||
{
|
||||
if (!entry->samplespersecond) {
|
||||
|
@ -1144,6 +1179,8 @@ static int conf_process_format_name(const char *name, enum ast_format_id *id)
|
|||
{
|
||||
if (!strcasecmp(name, "silk")) {
|
||||
*id = AST_FORMAT_SILK;
|
||||
} else if (!strcasecmp(name, "celt")) {
|
||||
*id = AST_FORMAT_CELT;
|
||||
} else {
|
||||
*id = 0;
|
||||
return -1;
|
||||
|
@ -1163,8 +1200,14 @@ static int conf_process_sample_rate(const char *rate, unsigned int *result)
|
|||
*result = 24000;
|
||||
} else if (!strcasecmp(rate, "32000")) {
|
||||
*result = 32000;
|
||||
} else if (!strcasecmp(rate, "44100")) {
|
||||
*result = 44100;
|
||||
} else if (!strcasecmp(rate, "48000")) {
|
||||
*result = 48000;
|
||||
} else if (!strcasecmp(rate, "96000")) {
|
||||
*result = 96000;
|
||||
} else if (!strcasecmp(rate, "192000")) {
|
||||
*result = 192000;
|
||||
} else {
|
||||
*result = 0;
|
||||
return -1;
|
||||
|
@ -1184,6 +1227,7 @@ static int load_format_config(void)
|
|||
struct {
|
||||
enum ast_format_id id;
|
||||
unsigned int maxbitrate;
|
||||
unsigned int framesize;
|
||||
unsigned int packetloss_percentage;
|
||||
int usefec;
|
||||
int usedtx;
|
||||
|
@ -1221,6 +1265,11 @@ static int load_format_config(void)
|
|||
ast_log(LOG_WARNING, "maxbitrate '%s' at line %d of %s is not supported.\n",
|
||||
var->value, var->lineno, FORMAT_CONFIG);
|
||||
}
|
||||
} else if (!strcasecmp(var->name, "framesize")) {
|
||||
if (sscanf(var->value, "%30u", &settings.framesize) != 1) {
|
||||
ast_log(LOG_WARNING, "framesize '%s' at line %d of %s is not supported.\n",
|
||||
var->value, var->lineno, FORMAT_CONFIG);
|
||||
}
|
||||
} else if (!strcasecmp(var->name, "dtx")) {
|
||||
settings.usedtx = ast_true(var->value) ? 1 : 0;
|
||||
} else if (!strcasecmp(var->name, "fec")) {
|
||||
|
@ -1239,6 +1288,11 @@ static int load_format_config(void)
|
|||
add_it = 1;
|
||||
}
|
||||
break;
|
||||
case AST_FORMAT_CELT:
|
||||
if (!(custom_celt_format(&entry, settings.maxbitrate, settings.framesize))) {
|
||||
add_it = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ast_log(LOG_WARNING, "Can not create custom format %s\n", entry.name);
|
||||
}
|
||||
|
|
|
@ -1011,6 +1011,10 @@ int ast_codec_get_samples(struct ast_frame *f)
|
|||
} else {
|
||||
return 160;
|
||||
}
|
||||
case AST_FORMAT_CELT:
|
||||
/* TODO The assumes 20ms delivery right now, which is incorrect */
|
||||
samples = ast_format_rate(&f->subclass.format) / 50;
|
||||
break;
|
||||
default:
|
||||
ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(&f->subclass.format));
|
||||
}
|
||||
|
|
|
@ -1931,6 +1931,10 @@ int ast_rtp_engine_load_format(const struct ast_format *format)
|
|||
set_next_mime_type(format, 0, "audio", "SILK", ast_format_rate(format));
|
||||
add_static_payload(-1, format, 0);
|
||||
break;
|
||||
case AST_FORMAT_CELT:
|
||||
set_next_mime_type(format, 0, "audio", "CELT", ast_format_rate(format));
|
||||
add_static_payload(-1, format, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1254,6 +1254,7 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr
|
|||
case AST_FORMAT_SPEEX16:
|
||||
case AST_FORMAT_SPEEX32:
|
||||
case AST_FORMAT_SILK:
|
||||
case AST_FORMAT_CELT:
|
||||
case AST_FORMAT_G723_1:
|
||||
case AST_FORMAT_SIREN7:
|
||||
case AST_FORMAT_SIREN14:
|
||||
|
|
Reference in New Issue