diff options
-rw-r--r-- | channels/chan_sip.c | 54 | ||||
-rw-r--r-- | configs/codecs.conf.sample | 19 | ||||
-rw-r--r-- | include/asterisk/format.h | 2 | ||||
-rw-r--r-- | main/channel.c | 12 | ||||
-rw-r--r-- | main/format.c | 54 | ||||
-rw-r--r-- | main/frame.c | 4 | ||||
-rw-r--r-- | main/rtp_engine.c | 4 | ||||
-rw-r--r-- | res/res_rtp_asterisk.c | 1 |
8 files changed, 120 insertions, 30 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 9e2ddf7ed..9ab409265 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -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_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: - { - 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; + 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_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: - { - 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; + 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)) diff --git a/configs/codecs.conf.sample b/configs/codecs.conf.sample index 4404d4a0c..9b5738577 100644 --- a/configs/codecs.conf.sample +++ b/configs/codecs.conf.sample @@ -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 diff --git a/include/asterisk/format.h b/include/asterisk/format.h index 67e4178a2..d0f1021d5 100644 --- a/include/asterisk/format.h +++ b/include/asterisk/format.h @@ -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, diff --git a/main/channel.c b/main/channel.c index ed84da1e6..902c79d85 100644 --- a/main/channel.c +++ b/main/channel.c @@ -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 */ diff --git a/main/format.c b/main/format.c index 28b15ae21..1c60ab770 100644 --- a/main/format.c +++ b/main/format.c @@ -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); } diff --git a/main/frame.c b/main/frame.c index bb32386ca..b664e2e84 100644 --- a/main/frame.c +++ b/main/frame.c @@ -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)); } diff --git a/main/rtp_engine.c b/main/rtp_engine.c index a3d9c4d8e..4ad3c9024 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -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; } diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 60f7edacf..5948e664c 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -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: |