summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/asterisk/format_cache.h8
-rw-r--r--main/codec_builtin.c63
-rw-r--r--main/format_cache.c20
-rw-r--r--main/rtp_engine.c10
-rw-r--r--res/res_format_attr_silk.c64
5 files changed, 134 insertions, 31 deletions
diff --git a/include/asterisk/format_cache.h b/include/asterisk/format_cache.h
index 64e53b9c5..3894ad21b 100644
--- a/include/asterisk/format_cache.h
+++ b/include/asterisk/format_cache.h
@@ -224,6 +224,14 @@ extern struct ast_format *ast_format_t140_red;
extern struct ast_format *ast_format_none;
/*!
+ * \brief Built-in SILK format.
+ */
+extern struct ast_format *ast_format_silk8;
+extern struct ast_format *ast_format_silk12;
+extern struct ast_format *ast_format_silk16;
+extern struct ast_format *ast_format_silk24;
+
+/*!
* \brief Initialize format cache support within the core.
*
* \retval 0 success
diff --git a/main/codec_builtin.c b/main/codec_builtin.c
index 913164328..50fbf555c 100644
--- a/main/codec_builtin.c
+++ b/main/codec_builtin.c
@@ -772,6 +772,65 @@ static struct ast_codec t140 = {
.type = AST_MEDIA_TYPE_TEXT,
};
+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; \
@@ -843,6 +902,10 @@ int ast_codec_builtin_init(void)
res |= CODEC_REGISTER_AND_CACHE(t140red);
res |= CODEC_REGISTER_AND_CACHE(t140);
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;
}
diff --git a/main/format_cache.c b/main/format_cache.c
index def795c9d..b4d426092 100644
--- a/main/format_cache.c
+++ b/main/format_cache.c
@@ -232,6 +232,14 @@ struct ast_format *ast_format_t140_red;
*/
struct ast_format *ast_format_none;
+/*!
+ * \brief Built-in "silk" format
+ */
+struct ast_format *ast_format_silk8;
+struct ast_format *ast_format_silk12;
+struct ast_format *ast_format_silk16;
+struct ast_format *ast_format_silk24;
+
/*! \brief Number of buckets to use for the media format cache (should be prime for performance reasons) */
#define CACHE_BUCKETS 53
@@ -331,6 +339,10 @@ static void format_cache_shutdown(void)
ao2_replace(ast_format_t140_red, NULL);
ao2_replace(ast_format_t140, NULL);
ao2_replace(ast_format_none, NULL);
+ ao2_replace(ast_format_silk8, NULL);
+ ao2_replace(ast_format_silk12, NULL);
+ ao2_replace(ast_format_silk16, NULL);
+ ao2_replace(ast_format_silk24, NULL);
}
int ast_format_cache_init(void)
@@ -426,6 +438,14 @@ static void set_cached_format(const char *name, struct ast_format *format)
ao2_replace(ast_format_t140, format);
} else if (!strcmp(name, "none")) {
ao2_replace(ast_format_none, format);
+ } else if (!strcmp(name, "silk8")) {
+ ao2_replace(ast_format_silk8, format);
+ } else if (!strcmp(name, "silk12")) {
+ ao2_replace(ast_format_silk12, format);
+ } else if (!strcmp(name, "silk16")) {
+ ao2_replace(ast_format_silk16, format);
+ } else if (!strcmp(name, "silk24")) {
+ ao2_replace(ast_format_silk24, format);
}
}
diff --git a/main/rtp_engine.c b/main/rtp_engine.c
index 11e94c699..feadda3d3 100644
--- a/main/rtp_engine.c
+++ b/main/rtp_engine.c
@@ -2690,6 +2690,11 @@ int ast_rtp_engine_init(void)
/* Opus and VP8 */
set_next_mime_type(ast_format_opus, 0, "audio", "opus", 48000);
set_next_mime_type(ast_format_vp8, 0, "video", "VP8", 90000);
+ /* DA SILK */
+ set_next_mime_type(ast_format_silk8, 0, "audio", "silk", 8000);
+ set_next_mime_type(ast_format_silk12, 0, "audio", "silk", 12000);
+ set_next_mime_type(ast_format_silk16, 0, "audio", "silk", 16000);
+ set_next_mime_type(ast_format_silk24, 0, "audio", "silk", 24000);
/* Define the static rtp payload mappings */
add_static_payload(0, ast_format_ulaw, 0);
@@ -2743,6 +2748,11 @@ int ast_rtp_engine_init(void)
add_static_payload(100, ast_format_vp8, 0);
add_static_payload(107, ast_format_opus, 0);
+ add_static_payload(108, ast_format_silk8, 0);
+ add_static_payload(109, ast_format_silk12, 0);
+ add_static_payload(113, ast_format_silk16, 0);
+ add_static_payload(114, ast_format_silk24, 0);
+
return 0;
}
diff --git a/res/res_format_attr_silk.c b/res/res_format_attr_silk.c
index f3f43821c..e69e3f43c 100644
--- a/res/res_format_attr_silk.c
+++ b/res/res_format_attr_silk.c
@@ -40,7 +40,6 @@ ASTERISK_REGISTER_FILE()
* \note The only attribute that affects compatibility here is the sample rate.
*/
struct silk_attr {
- unsigned int samplerate;
unsigned int maxbitrate;
unsigned int dtx;
unsigned int fec;
@@ -54,10 +53,15 @@ static void silk_destroy(struct ast_format *format)
ast_free(attr);
}
+static void attr_init(struct silk_attr *attr)
+{
+ memset(attr, 0, sizeof(*attr));
+}
+
static int silk_clone(const struct ast_format *src, struct ast_format *dst)
{
struct silk_attr *original = ast_format_get_attribute_data(src);
- struct silk_attr *attr = ast_calloc(1, sizeof(*attr));
+ struct silk_attr *attr = ast_malloc(sizeof(*attr));
if (!attr) {
return -1;
@@ -65,6 +69,8 @@ static int silk_clone(const struct ast_format *src, struct ast_format *dst)
if (original) {
*attr = *original;
+ } else {
+ attr_init(attr);
}
ast_format_set_attribute_data(dst, attr);
@@ -109,17 +115,17 @@ static void silk_generate_sdp_fmtp(const struct ast_format *format, unsigned int
ast_str_append(str, 0, "a=fmtp:%u maxaveragebitrate=%u\r\n", payload, attr->maxbitrate);
}
- ast_str_append(str, 0, "a=fmtp:%u usedtx=%u\r\n", payload, attr->dtx);
- ast_str_append(str, 0, "a=fmtp:%u useinbandfec=%u\r\n", payload, attr->fec);
+ if (attr->dtx) {
+ ast_str_append(str, 0, "a=fmtp:%u usedtx=%u\r\n", payload, attr->dtx);
+ }
+ if (attr->fec) {
+ ast_str_append(str, 0, "a=fmtp:%u useinbandfec=%u\r\n", payload, attr->fec);
+ }
}
static enum ast_format_cmp_res silk_cmp(const struct ast_format *format1, const struct ast_format *format2)
{
- struct silk_attr *attr1 = ast_format_get_attribute_data(format1);
- struct silk_attr *attr2 = ast_format_get_attribute_data(format2);
-
- if (((!attr1 || !attr1->samplerate) && (!attr2 || !attr2->samplerate)) ||
- (attr1->samplerate == attr2->samplerate)) {
+ if (ast_format_get_sample_rate(format1) == ast_format_get_sample_rate(format2)) {
return AST_FORMAT_CMP_EQUAL;
}
@@ -130,13 +136,10 @@ static struct ast_format *silk_getjoint(const struct ast_format *format1, const
{
struct silk_attr *attr1 = ast_format_get_attribute_data(format1);
struct silk_attr *attr2 = ast_format_get_attribute_data(format2);
- unsigned int samplerate;
struct ast_format *jointformat;
struct silk_attr *attr_res;
- samplerate = attr1->samplerate & attr2->samplerate;
- /* sample rate is the only attribute that has any bearing on if joint capabilities exist or not */
- if (samplerate) {
+ if (ast_format_get_sample_rate(format1) != ast_format_get_sample_rate(format2)) {
return NULL;
}
@@ -145,22 +148,25 @@ static struct ast_format *silk_getjoint(const struct ast_format *format1, const
return NULL;
}
attr_res = ast_format_get_attribute_data(jointformat);
- attr_res->samplerate = samplerate;
- /* Take the lowest max bitrate */
- attr_res->maxbitrate = MIN(attr1->maxbitrate, attr2->maxbitrate);
+ if (!attr1 || !attr2) {
+ attr_init(attr_res);
+ } else {
+ /* Take the lowest max bitrate */
+ attr_res->maxbitrate = MIN(attr1->maxbitrate, attr2->maxbitrate);
- /* Only do dtx if both sides want it. DTX is a trade off between
- * computational complexity and bandwidth. */
- attr_res->dtx = attr1->dtx && attr2->dtx ? 1 : 0;
+ /* Only do dtx if both sides want it. DTX is a trade off between
+ * computational complexity and bandwidth. */
+ attr_res->dtx = attr1->dtx && attr2->dtx ? 1 : 0;
- /* Only do FEC if both sides want it. If a peer specifically requests not
- * to receive with FEC, it may be a waste of bandwidth. */
- attr_res->fec = attr1->fec && attr2->fec ? 1 : 0;
+ /* Only do FEC if both sides want it. If a peer specifically requests not
+ * to receive with FEC, it may be a waste of bandwidth. */
+ attr_res->fec = attr1->fec && attr2->fec ? 1 : 0;
- /* Use the maximum packetloss percentage between the two attributes. This affects how
- * much redundancy is used in the FEC. */
- attr_res->packetloss_percentage = MAX(attr1->packetloss_percentage, attr2->packetloss_percentage);
+ /* Use the maximum packetloss percentage between the two attributes. This affects how
+ * much redundancy is used in the FEC. */
+ attr_res->packetloss_percentage = MAX(attr1->packetloss_percentage, attr2->packetloss_percentage);
+ }
return jointformat;
}
@@ -183,9 +189,7 @@ static struct ast_format *silk_set(const struct ast_format *format, const char *
}
attr = ast_format_get_attribute_data(cloned);
- if (!strcasecmp(name, "sample_rate")) {
- attr->samplerate = val;
- } else if (!strcasecmp(name, "max_bitrate")) {
+ if (!strcasecmp(name, "max_bitrate")) {
attr->maxbitrate = val;
} else if (!strcasecmp(name, "dtx")) {
attr->dtx = val;
@@ -205,9 +209,7 @@ static const void *silk_get(const struct ast_format *format, const char *name)
struct silk_attr *attr = ast_format_get_attribute_data(format);
unsigned int *val;
- if (!strcasecmp(name, "sample_rate")) {
- val = &attr->samplerate;
- } else if (!strcasecmp(name, "max_bitrate")) {
+ if (!strcasecmp(name, "max_bitrate")) {
val = &attr->maxbitrate;
} else if (!strcasecmp(name, "dtx")) {
val = &attr->dtx;