TT#91003 support sending CMR

Change-Id: Ief485087b36ce61c80f9d004e77113b31298b250
pull/1077/head
Richard Fuchs 5 years ago
parent c239035057
commit ed9de316c7

@ -505,6 +505,15 @@ The default (highest) bitrates for AMR and AMR-WB are 6700 and 14250, respective
If a Codec Mode Request (CMR) is received from the AMR peer, then *rtpengine* will adhere to the request
and switch encoder bitrate unconditionally, even if it's a higher bitrate than originally desired.
To enable sending CMRs to the AMR peer, the codec-specific option `CMR-interval` is provided. It takes
a number of milliseconds as argument. Throughout each interval, *rtpengine* will track which AMR frame
types were received from the peer, and then based on that will make a decision at the end of the
interval. If a higher bitrate is allowed by the mode set that was not received from the AMR peer at all,
then *rtpengine* will request switching to that bitrate per CMR. Only the next-highest bitrate mode that
was not received will ever be requested, and a CMR will be sent only once per interval. Full example to
specify a CMR interval of 500 milliseconds (with `=` escapes):
`codec-transcode-AMR-WB/16000/1/23850//mode-set--0,1,2/CMR-interval--500`
Call recording
==============

@ -1735,6 +1735,10 @@ static int codec_decoder_event(enum codec_event event, void *ptr, void *data) {
media->u.amr.cmr.cmr_in = GPOINTER_TO_UINT(ptr);
media->u.amr.cmr.cmr_in_ts = rtpe_now;
break;
case CE_AMR_SEND_CMR:
// ignore locking and races for this
media->u.amr.cmr.cmr_out = GPOINTER_TO_UINT(ptr);
media->u.amr.cmr.cmr_out_ts = rtpe_now;
default:
break;
}

@ -1530,7 +1530,6 @@ static void codeclib_key_value_parse(const str *instr, int need_value,
#define AMR_FT_TYPES 14
const static unsigned int amr_bitrates[AMR_FT_TYPES] = {
4750, // 0
5150, // 1
@ -1641,9 +1640,29 @@ static void amr_set_encdec_options(codec_options_t *opts, const str *fmtp, const
codeclib_key_value_parse(fmtp, 1, amr_set_encdec_options_cb, opts);
}
static void amr_set_dec_codec_options(str *key, str *value, void *data) {
decoder_t *dec = data;
if (!str_cmp(key, "CMR-interval"))
dec->codec_options.amr.cmr_interval = str_to_i(value, 0);
}
static void amr_set_enc_codec_options(str *key, str *value, void *data) {
encoder_t *enc = data;
if (!str_cmp(key, "CMR-interval"))
; // not an encoder optoin
else {
// our string might not be null terminated
char *s = g_strdup_printf(STR_FORMAT, STR_FMT(key));
codeclib_set_av_opt_intstr(enc, s, value);
g_free(s);
}
}
static void amr_set_enc_options(encoder_t *enc, const str *fmtp, const str *codec_opts) {
amr_set_encdec_options(&enc->codec_options, fmtp, enc->def);
codeclib_key_value_parse(codec_opts, 1, amr_set_enc_codec_options, enc);
// if a mode-set was given, pick the highest supported bitrate
if (enc->codec_options.amr.mode_set) {
int max_bitrate = enc->u.avc.avcctx->bit_rate;
@ -1672,8 +1691,61 @@ static void amr_set_enc_options(encoder_t *enc, const str *fmtp, const str *code
}
static void amr_set_dec_options(decoder_t *dec, const str *fmtp, const str *codec_opts) {
amr_set_encdec_options(&dec->codec_options, fmtp, dec->def);
codeclib_key_value_parse(codec_opts, 1, amr_set_dec_codec_options, dec);
}
static void amr_bitrate_tracker(decoder_t *dec, unsigned int ft) {
if (dec->codec_options.amr.cmr_interval <= 0)
return;
if (dec->u.avc.u.amr.tracker_end.tv_sec
&& timeval_cmp(&dec->u.avc.u.amr.tracker_end, &rtpe_now) >= 0) {
// analyse the data we gathered
int next_highest = -1;
int lowest_used = -1;
for (int i = 0; i < AMR_FT_TYPES; i++) {
unsigned int br = dec->codec_options.amr.bitrates[i];
if (!br)
break; // end of list
// ignore restricted modes
if (dec->codec_options.amr.mode_set) {
if (!(dec->codec_options.amr.mode_set & (1 << i)))
continue;
}
// would this be a "next step up" mode?
if (next_highest == -1)
next_highest = i;
// did we see any frames?
if (!dec->u.avc.u.amr.bitrate_tracker[i])
continue;
next_highest = -1;
lowest_used = i;
}
if (lowest_used != -1 && next_highest != -1) {
// we can request a switch up
ilog(LOG_DEBUG, "Sending %s CMR to request upping bitrate to %u",
dec->def->rtpname, dec->codec_options.amr.bitrates[next_highest]);
decoder_event(dec, CE_AMR_SEND_CMR, GINT_TO_POINTER(next_highest));
}
// and reset tracker
ZERO(dec->u.avc.u.amr.tracker_end);
}
if (!dec->u.avc.u.amr.tracker_end.tv_sec) {
// init
ZERO(dec->u.avc.u.amr.bitrate_tracker);
dec->u.avc.u.amr.tracker_end = rtpe_now;
timeval_add_usec(&dec->u.avc.u.amr.tracker_end, dec->codec_options.amr.cmr_interval * 1000);
}
dec->u.avc.u.amr.bitrate_tracker[ft]++;
}
static int amr_decoder_input(decoder_t *dec, const str *data, GQueue *out) {
const char *err = NULL;
@ -1785,6 +1857,8 @@ static int amr_decoder_input(decoder_t *dec, const str *data, GQueue *out) {
err = "failed to decode AMR data";
if (avc_decoder_input(dec, &frame, out))
goto err;
amr_bitrate_tracker(dec, ft);
}
return 0;
@ -1829,6 +1903,21 @@ static int packetizer_amr(AVPacket *pkt, GString *buf, str *output, encoder_t *e
s[0] = '\xf0'; // no CMR req (4 bits)
// or do we have a CMR?
if (!enc->u.avc.u.amr.cmr_out_seq) {
if (memcmp(&enc->u.avc.u.amr.cmr_out_ts, &enc->codec_options.amr.cmr.cmr_out_ts,
sizeof(struct timeval))) {
enc->u.avc.u.amr.cmr_out_seq += 3; // make this configurable?
enc->u.avc.u.amr.cmr_out_ts = enc->codec_options.amr.cmr.cmr_out_ts;
}
}
if (enc->u.avc.u.amr.cmr_out_seq) {
enc->u.avc.u.amr.cmr_out_seq--;
unsigned int cmr = enc->codec_options.amr.cmr.cmr_out;
if (cmr < AMR_FT_TYPES && enc->codec_options.amr.bitrates[cmr])
s[0] = cmr << 4;
}
if (enc->codec_options.amr.octet_aligned) {
unsigned int offset = 1; // CMR byte
if (enc->codec_options.amr.interleaving)

@ -46,6 +46,8 @@ INLINE enum media_type codec_get_type(const str *type) {
#include <bcg729/decoder.h>
#endif
#define AMR_FT_TYPES 14
struct codec_type_s;
@ -88,6 +90,9 @@ struct codec_type_s {
struct amr_cmr {
struct timeval cmr_in_ts;
unsigned int cmr_in;
struct timeval cmr_out_ts;
unsigned int cmr_out;
};
union codec_options_u {
@ -102,6 +107,8 @@ union codec_options_u {
const unsigned int *bitrates;
struct amr_cmr cmr; // input from external calling code
int cmr_interval;
} amr;
};
@ -154,6 +161,7 @@ struct resample_s {
enum codec_event {
CE_AMR_CMR_RECV,
CE_AMR_SEND_CMR,
};
struct decoder_s {
@ -169,6 +177,13 @@ struct decoder_s {
struct {
AVCodecContext *avcctx;
AVPacket avpkt;
union {
struct {
uint16_t bitrate_tracker[AMR_FT_TYPES];
struct timeval tracker_end;
} amr;
} u;
} avc;
#ifdef HAVE_BCG729
bcg729DecoderChannelContextStruct *bcg729;
@ -202,7 +217,9 @@ struct encoder_s {
union {
struct {
struct timeval cmr_in_ts; // used internally
struct timeval cmr_in_ts;
struct timeval cmr_out_ts;
unsigned int cmr_out_seq;
} amr;
} u;
} avc;

Loading…
Cancel
Save