|
|
|
|
@ -1862,37 +1862,52 @@ struct libopus_encoder_options {
|
|
|
|
|
static void libopus_set_enc_opts(str *key, str *val, void *p) {
|
|
|
|
|
struct libopus_encoder_options *opts = p;
|
|
|
|
|
|
|
|
|
|
if (!str_cmp(key, "complexity") || !str_cmp(key, "compression_level"))
|
|
|
|
|
opts->complexity = str_to_i(val, -1);
|
|
|
|
|
else if (!str_cmp(key, "application")) {
|
|
|
|
|
if (!str_cmp(val, "VOIP") || !str_cmp(val, "VoIP") || !str_cmp(val, "voip"))
|
|
|
|
|
opts->application = OPUS_APPLICATION_VOIP;
|
|
|
|
|
else if (!str_cmp(val, "audio"))
|
|
|
|
|
opts->application = OPUS_APPLICATION_AUDIO;
|
|
|
|
|
else if (!str_cmp(val, "low-delay") || !str_cmp(val, "low delay") || !str_cmp(val, "lowdelay"))
|
|
|
|
|
opts->application = OPUS_APPLICATION_RESTRICTED_LOWDELAY;
|
|
|
|
|
else
|
|
|
|
|
ilog(LOG_WARN | LOG_FLAG_LIMIT, "Unknown Opus application: '" STR_FORMAT "'",
|
|
|
|
|
STR_FMT(val));
|
|
|
|
|
}
|
|
|
|
|
else if (!str_cmp(key, "vbr")) {
|
|
|
|
|
// aligned with ffmpeg vbr=0/1/2 option
|
|
|
|
|
opts->vbr = str_to_i(val, -1);
|
|
|
|
|
if (opts->vbr == 2) {
|
|
|
|
|
opts->vbr = 1;
|
|
|
|
|
opts->vbr_constraint = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (!str_cmp(key, "packet_loss"))
|
|
|
|
|
opts->pl = str_to_i(val, -1);
|
|
|
|
|
else if (!str_cmp(key, "fec"))
|
|
|
|
|
opts->fec = str_to_i(val, -1);
|
|
|
|
|
else {
|
|
|
|
|
ilog(LOG_WARN | LOG_FLAG_LIMIT, "Unknown Opus encoder option encountered: '" STR_FORMAT "'",
|
|
|
|
|
STR_FMT(key));
|
|
|
|
|
return;
|
|
|
|
|
switch (__csh_lookup(key)) {
|
|
|
|
|
case CSH_LOOKUP("complexity"):
|
|
|
|
|
case CSH_LOOKUP("compression_level"):
|
|
|
|
|
opts->complexity = str_to_i(val, -1);
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("application"):
|
|
|
|
|
switch (__csh_lookup(val)) {
|
|
|
|
|
case CSH_LOOKUP("VOIP"):
|
|
|
|
|
case CSH_LOOKUP("VoIP"):
|
|
|
|
|
case CSH_LOOKUP("voip"):
|
|
|
|
|
opts->application = OPUS_APPLICATION_VOIP;
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("audio"):
|
|
|
|
|
opts->application = OPUS_APPLICATION_AUDIO;
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("low-delay"):
|
|
|
|
|
case CSH_LOOKUP("low delay"):
|
|
|
|
|
case CSH_LOOKUP("lowdelay"):
|
|
|
|
|
opts->application = OPUS_APPLICATION_RESTRICTED_LOWDELAY;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ilog(LOG_WARN | LOG_FLAG_LIMIT, "Unknown Opus application: '"
|
|
|
|
|
STR_FORMAT "'", STR_FMT(val));
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("vbr"):
|
|
|
|
|
case CSH_LOOKUP("VBR"):
|
|
|
|
|
// aligned with ffmpeg vbr=0/1/2 option
|
|
|
|
|
opts->vbr = str_to_i(val, -1);
|
|
|
|
|
if (opts->vbr == 2) {
|
|
|
|
|
opts->vbr = 1;
|
|
|
|
|
opts->vbr_constraint = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("packet_loss"):
|
|
|
|
|
case CSH_LOOKUP("packet loss"):
|
|
|
|
|
opts->pl = str_to_i(val, -1);
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("fec"):
|
|
|
|
|
case CSH_LOOKUP("FEC"):
|
|
|
|
|
opts->fec = str_to_i(val, -1);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ilog(LOG_WARN | LOG_FLAG_LIMIT, "Unknown Opus encoder option encountered: '"
|
|
|
|
|
STR_FORMAT "'", STR_FMT(key));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
static const char *libopus_encoder_init(encoder_t *enc, const str *extra_opts) {
|
|
|
|
|
if (enc->requested_format.channels != 1 && enc->requested_format.channels != 2)
|
|
|
|
|
@ -2018,12 +2033,16 @@ static struct fraction opus_select_enc_clockrate(const format_t *req_format, con
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int ilbc_format_parse(struct rtp_codec_format *f, const str *fmtp) {
|
|
|
|
|
if (!str_cmp(fmtp, "mode=20"))
|
|
|
|
|
f->parsed.ilbc.mode = 20;
|
|
|
|
|
else if (!str_cmp(fmtp, "mode=30"))
|
|
|
|
|
f->parsed.ilbc.mode = 30;
|
|
|
|
|
else
|
|
|
|
|
return -1;
|
|
|
|
|
switch (__csh_lookup(fmtp)) {
|
|
|
|
|
case CSH_LOOKUP("mode=20"):
|
|
|
|
|
f->parsed.ilbc.mode = 20;
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("mode=30"):
|
|
|
|
|
f->parsed.ilbc.mode = 30;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
f->fmtp_parsed = 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
@ -2216,40 +2235,43 @@ static const unsigned int amr_wb_bits_per_frame[AMR_FT_TYPES] = {
|
|
|
|
|
static void amr_parse_format_cb(str *key, str *token, void *data) {
|
|
|
|
|
union codec_format_options *opts = data;
|
|
|
|
|
|
|
|
|
|
if (!str_cmp(key, "octet-align")) {
|
|
|
|
|
if (token->len == 1 && token->s[0] == '1')
|
|
|
|
|
opts->amr.octet_aligned = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (!str_cmp(key, "crc")) {
|
|
|
|
|
if (token->len == 1 && token->s[0] == '1') {
|
|
|
|
|
opts->amr.octet_aligned = 1;
|
|
|
|
|
opts->amr.crc = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (!str_cmp(key, "robust-sorting")) {
|
|
|
|
|
if (token->len == 1 && token->s[0] == '1') {
|
|
|
|
|
switch (__csh_lookup(key)) {
|
|
|
|
|
case CSH_LOOKUP("octet-align"):
|
|
|
|
|
if (token->len == 1 && token->s[0] == '1')
|
|
|
|
|
opts->amr.octet_aligned = 1;
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("crc"):
|
|
|
|
|
if (token->len == 1 && token->s[0] == '1') {
|
|
|
|
|
opts->amr.octet_aligned = 1;
|
|
|
|
|
opts->amr.crc = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("robust-sorting"):
|
|
|
|
|
if (token->len == 1 && token->s[0] == '1') {
|
|
|
|
|
opts->amr.octet_aligned = 1;
|
|
|
|
|
opts->amr.robust_sorting = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("interleaving"):
|
|
|
|
|
opts->amr.octet_aligned = 1;
|
|
|
|
|
opts->amr.robust_sorting = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (!str_cmp(key, "interleaving")) {
|
|
|
|
|
opts->amr.octet_aligned = 1;
|
|
|
|
|
opts->amr.interleaving = str_to_i(token, 0);
|
|
|
|
|
}
|
|
|
|
|
else if (!str_cmp(key, "mode-set")) {
|
|
|
|
|
str mode;
|
|
|
|
|
while (str_token_sep(&mode, token, ',') == 0) {
|
|
|
|
|
int m = str_to_i(&mode, -1);
|
|
|
|
|
if (m < 0 || m >= AMR_FT_TYPES)
|
|
|
|
|
continue;
|
|
|
|
|
opts->amr.mode_set |= (1 << m);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (!str_cmp(key, "mode-change-period"))
|
|
|
|
|
opts->amr.mode_change_period = str_to_i(token, 0);
|
|
|
|
|
else if (!str_cmp(key, "mode-change-neighbor")) {
|
|
|
|
|
if (token->len == 1 && token->s[0] == '1')
|
|
|
|
|
opts->amr.mode_change_neighbor = 1;
|
|
|
|
|
opts->amr.interleaving = str_to_i(token, 0);
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("mode-set"):;
|
|
|
|
|
str mode;
|
|
|
|
|
while (str_token_sep(&mode, token, ',') == 0) {
|
|
|
|
|
int m = str_to_i(&mode, -1);
|
|
|
|
|
if (m < 0 || m >= AMR_FT_TYPES)
|
|
|
|
|
continue;
|
|
|
|
|
opts->amr.mode_set |= (1 << m);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("mode-change-period"):
|
|
|
|
|
opts->amr.mode_change_period = str_to_i(token, 0);
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("mode-change-neighbor"):
|
|
|
|
|
if (token->len == 1 && token->s[0] == '1')
|
|
|
|
|
opts->amr.mode_change_neighbor = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
static int amr_format_parse(struct rtp_codec_format *f, const str *fmtp) {
|
|
|
|
|
@ -3132,42 +3154,48 @@ static unsigned int str_to_i_k(str *s) {
|
|
|
|
|
static const char *evs_bw_strings[__EVS_BW_MAX] = { "nb", "wb", "swb", "fb" };
|
|
|
|
|
|
|
|
|
|
static void evs_parse_bw(enum evs_bw *minp, enum evs_bw *maxp, const str *token) {
|
|
|
|
|
if (!str_cmp(token, "nb"))
|
|
|
|
|
*maxp = EVS_BW_NB;
|
|
|
|
|
else if (!str_cmp(token, "wb"))
|
|
|
|
|
*maxp = EVS_BW_WB;
|
|
|
|
|
else if (!str_cmp(token, "swb"))
|
|
|
|
|
*maxp = EVS_BW_SWB;
|
|
|
|
|
else if (!str_cmp(token, "fb"))
|
|
|
|
|
*maxp = EVS_BW_FB;
|
|
|
|
|
else if (!str_cmp(token, "nb-wb")) {
|
|
|
|
|
*minp = EVS_BW_NB;
|
|
|
|
|
*maxp = EVS_BW_WB;
|
|
|
|
|
}
|
|
|
|
|
else if (!str_cmp(token, "nb-swb")) {
|
|
|
|
|
*minp = EVS_BW_NB;
|
|
|
|
|
*maxp = EVS_BW_SWB;
|
|
|
|
|
}
|
|
|
|
|
else if (!str_cmp(token, "nb-fb")) {
|
|
|
|
|
*minp = EVS_BW_NB;
|
|
|
|
|
*maxp = EVS_BW_FB;
|
|
|
|
|
}
|
|
|
|
|
// the ones below are not mentioned in the spec - lower bound ignored
|
|
|
|
|
else if (!str_cmp(token, "wb-swb")) {
|
|
|
|
|
*minp = EVS_BW_WB;
|
|
|
|
|
*maxp = EVS_BW_SWB;
|
|
|
|
|
}
|
|
|
|
|
else if (!str_cmp(token, "wb-fb")) {
|
|
|
|
|
*minp = EVS_BW_WB;
|
|
|
|
|
*maxp = EVS_BW_FB;
|
|
|
|
|
}
|
|
|
|
|
else if (!str_cmp(token, "swb-fb")) {
|
|
|
|
|
*minp = EVS_BW_SWB;
|
|
|
|
|
*maxp = EVS_BW_FB;
|
|
|
|
|
switch (__csh_lookup(token)) {
|
|
|
|
|
case CSH_LOOKUP("nb"):
|
|
|
|
|
*maxp = EVS_BW_NB;
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("wb"):
|
|
|
|
|
*maxp = EVS_BW_WB;
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("swb"):
|
|
|
|
|
*maxp = EVS_BW_SWB;
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("fb"):
|
|
|
|
|
*maxp = EVS_BW_FB;
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("nb-wb"):
|
|
|
|
|
*minp = EVS_BW_NB;
|
|
|
|
|
*maxp = EVS_BW_WB;
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("nb-swb"):
|
|
|
|
|
*minp = EVS_BW_NB;
|
|
|
|
|
*maxp = EVS_BW_SWB;
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("nb-fb"):
|
|
|
|
|
*minp = EVS_BW_NB;
|
|
|
|
|
*maxp = EVS_BW_FB;
|
|
|
|
|
break;
|
|
|
|
|
// the ones below are not mentioned in the spec - lower bound ignored
|
|
|
|
|
case CSH_LOOKUP("wb-swb"):
|
|
|
|
|
*minp = EVS_BW_WB;
|
|
|
|
|
*maxp = EVS_BW_SWB;
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("wb-fb"):
|
|
|
|
|
*minp = EVS_BW_WB;
|
|
|
|
|
*maxp = EVS_BW_FB;
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("swb-fb"):
|
|
|
|
|
*minp = EVS_BW_SWB;
|
|
|
|
|
*maxp = EVS_BW_FB;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ilog(LOG_WARN, "EVS: bandwidth selection '" STR_FORMAT "' not understood",
|
|
|
|
|
STR_FMT(token));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
ilog(LOG_WARN, "EVS: bandwidth selection '" STR_FORMAT "' not understood",
|
|
|
|
|
STR_FMT(token));
|
|
|
|
|
}
|
|
|
|
|
static void evs_parse_br(unsigned int *minp, unsigned int *maxp, str *token) {
|
|
|
|
|
str min;
|
|
|
|
|
@ -3276,54 +3304,63 @@ static void evs_parse_format_cb(str *key, str *token, void *data) {
|
|
|
|
|
union codec_format_options *opts = data;
|
|
|
|
|
__auto_type o = &opts->evs;
|
|
|
|
|
|
|
|
|
|
if (!str_cmp(key, "hf-only")) {
|
|
|
|
|
if (token->len == 1 && token->s[0] == '1')
|
|
|
|
|
o->hf_only = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (!str_cmp(key, "evs-mode-switch")) {
|
|
|
|
|
if (token->len == 1 && token->s[0] == '1')
|
|
|
|
|
o->amr_io = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (!str_cmp(key, "dtx")) {
|
|
|
|
|
if (token->len == 1 && token->s[0] == '0')
|
|
|
|
|
o->no_dtx = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (!str_cmp(key, "dtx-recv")) {
|
|
|
|
|
if (token->len == 1 && token->s[0] == '0')
|
|
|
|
|
o->no_dtx_recv = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (!str_cmp(key, "cmr")) {
|
|
|
|
|
if (token->len == 1 && token->s[0] == '1')
|
|
|
|
|
o->cmr = 1;
|
|
|
|
|
else if (token->len == 2 && token->s[0] == '-' && token->s[1] == '1')
|
|
|
|
|
o->cmr = -1;
|
|
|
|
|
}
|
|
|
|
|
else if (!str_cmp(key, "br"))
|
|
|
|
|
evs_parse_br(&o->min_br, &o->max_br, token);
|
|
|
|
|
else if (!str_cmp(key, "br-send"))
|
|
|
|
|
evs_parse_br(&o->min_br_send, &o->max_br_send, token);
|
|
|
|
|
else if (!str_cmp(key, "br-recv"))
|
|
|
|
|
evs_parse_br(&o->min_br_recv, &o->max_br_recv, token);
|
|
|
|
|
else if (!str_cmp(key, "bw"))
|
|
|
|
|
evs_parse_bw(&o->min_bw, &o->max_bw, token);
|
|
|
|
|
else if (!str_cmp(key, "bw-send"))
|
|
|
|
|
evs_parse_bw(&o->min_bw_send, &o->max_bw_send, token);
|
|
|
|
|
else if (!str_cmp(key, "bw-recv"))
|
|
|
|
|
evs_parse_bw(&o->min_bw_recv, &o->max_bw_recv, token);
|
|
|
|
|
else if (!str_cmp(key, "mode-set")) {
|
|
|
|
|
str mode;
|
|
|
|
|
while (str_token_sep(&mode, token, ',') == 0) {
|
|
|
|
|
int m = str_to_i(&mode, -1);
|
|
|
|
|
if (m < 0 || m > 8)
|
|
|
|
|
continue;
|
|
|
|
|
o->mode_set |= (1 << m);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (!str_cmp(key, "mode-change-period"))
|
|
|
|
|
o->mode_change_period = str_to_i(token, 0);
|
|
|
|
|
else if (!str_cmp(key, "mode-change-neighbor")) {
|
|
|
|
|
if (token->len == 1 && token->s[0] == '1')
|
|
|
|
|
o->mode_change_neighbor = 1;
|
|
|
|
|
switch (__csh_lookup(key)) {
|
|
|
|
|
case CSH_LOOKUP("hf-only"):
|
|
|
|
|
if (token->len == 1 && token->s[0] == '1')
|
|
|
|
|
o->hf_only = 1;
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("evs-mode-switch"):
|
|
|
|
|
if (token->len == 1 && token->s[0] == '1')
|
|
|
|
|
o->amr_io = 1;
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("dtx"):
|
|
|
|
|
if (token->len == 1 && token->s[0] == '0')
|
|
|
|
|
o->no_dtx = 1;
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("dtx-recv"):
|
|
|
|
|
if (token->len == 1 && token->s[0] == '0')
|
|
|
|
|
o->no_dtx_recv = 1;
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("cmr"):
|
|
|
|
|
if (token->len == 1 && token->s[0] == '1')
|
|
|
|
|
o->cmr = 1;
|
|
|
|
|
else if (token->len == 2 && token->s[0] == '-' && token->s[1] == '1')
|
|
|
|
|
o->cmr = -1;
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("br"):
|
|
|
|
|
evs_parse_br(&o->min_br, &o->max_br, token);
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("br-send"):
|
|
|
|
|
evs_parse_br(&o->min_br_send, &o->max_br_send, token);
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("br-recv"):
|
|
|
|
|
evs_parse_br(&o->min_br_recv, &o->max_br_recv, token);
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("bw"):
|
|
|
|
|
evs_parse_bw(&o->min_bw, &o->max_bw, token);
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("bw-send"):
|
|
|
|
|
evs_parse_bw(&o->min_bw_send, &o->max_bw_send, token);
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("bw-recv"):
|
|
|
|
|
evs_parse_bw(&o->min_bw_recv, &o->max_bw_recv, token);
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("mode-set"):;
|
|
|
|
|
str mode;
|
|
|
|
|
while (str_token_sep(&mode, token, ',') == 0) {
|
|
|
|
|
int m = str_to_i(&mode, -1);
|
|
|
|
|
if (m < 0 || m > 8)
|
|
|
|
|
continue;
|
|
|
|
|
o->mode_set |= (1 << m);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("mode-change-period"):
|
|
|
|
|
o->mode_change_period = str_to_i(token, 0);
|
|
|
|
|
break;
|
|
|
|
|
case CSH_LOOKUP("mode-change-neighbor"):
|
|
|
|
|
if (token->len == 1 && token->s[0] == '1')
|
|
|
|
|
o->mode_change_neighbor = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
static int evs_format_parse(struct rtp_codec_format *f, const str *fmtp) {
|
|
|
|
|
|