You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
rtpengine/lib/ilbc.c

133 lines
3.3 KiB

#include "codecmod.h"
#include "loglib.h"
static bool ilbc_format_parse(struct rtp_codec_format *f, const str *fmtp) {
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 false;
}
return true;
}
static int ilbc_mode(int ptime, const union codec_format_options *fmtp, const char *direction) {
int mode = 0;
if (fmtp)
mode = fmtp->ilbc.mode;
if (!mode) {
switch (ptime) {
case 20:
case 40:
case 60:
case 80:
case 100:
case 120:
mode = 20;
ilog(LOG_DEBUG, "Setting iLBC %s mode to 20 ms based on ptime %i",
direction, ptime);
break;
case 30:
case 90:
mode = 30;
ilog(LOG_DEBUG, "Setting iLBC %s mode to 30 ms based on ptime %i",
direction, ptime);
break;
}
}
if (!mode) {
mode = 20;
ilog(LOG_WARNING, "No iLBC %s mode specified, setting to 20 ms", direction);
}
return mode;
}
static void ilbc_set_enc_options(encoder_t *enc, const str *codec_opts) {
int mode = ilbc_mode(enc->ptime, &enc->format_options, "encoder");
codeclib_set_av_opt_int(enc, "mode", mode);
}
static void ilbc_set_dec_options(decoder_t *dec, const str *codec_opts) {
int mode = ilbc_mode(dec->ptime, &dec->format_options, "decoder");
if (mode == 20)
dec->avc.avcctx->block_align = 38;
else if (mode == 30)
dec->avc.avcctx->block_align = 50;
else
ilog(LOG_WARN, "Unsupported iLBC mode %i", mode);
}
static int ilbc_decoder_input(decoder_t *dec, const str *data, GQueue *out) {
int mode = 0, block_align = 0;
static const union codec_format_options mode_20 = { .ilbc = { 20 } };
static const union codec_format_options mode_30 = { .ilbc = { 30 } };
const union codec_format_options *fmtp;
if (data->len % 50 == 0) {
mode = 30;
block_align = 50;
fmtp = &mode_30;
}
else if (data->len % 38 == 0) {
mode = 20;
block_align = 38;
fmtp = &mode_20;
}
else
ilog(LOG_WARNING | LOG_FLAG_LIMIT, "iLBC received %i bytes packet, does not match "
"one of the block sizes", (int) data->len);
if (block_align && dec->avc.avcctx->block_align != block_align) {
ilog(LOG_INFO | LOG_FLAG_LIMIT, "iLBC decoder set to %i bytes blocks, but received packet "
"of %i bytes, therefore resetting decoder and switching to %i bytes "
"block mode (%i ms mode)",
(int) dec->avc.avcctx->block_align, (int) data->len, block_align, mode);
avc_decoder_close(dec);
dec->format_options = *fmtp;
avc_decoder_init(dec, NULL);
}
return avc_decoder_input(dec, data, out);
}
static const codec_type_t codec_type_ilbc = {
.def_init = avc_def_init,
.decoder_init = avc_decoder_init,
.decoder_input = ilbc_decoder_input,
.decoder_close = avc_decoder_close,
.encoder_init = avc_encoder_init,
.encoder_input = avc_encoder_input,
.encoder_close = avc_encoder_close,
};
static const codec_def_t ilbc = {
.rtpname = "iLBC",
.avcodec_id = AV_CODEC_ID_ILBC,
.default_clockrate = 8000,
.default_channels = 1,
.default_ptime = 30,
.default_fmtp = "mode=30",
.format_parse = ilbc_format_parse,
//.default_bitrate = 15200,
.packetizer = packetizer_passthrough,
.media_type = MT_AUDIO,
.codec_type = &codec_type_ilbc,
.set_enc_options = ilbc_set_enc_options,
.set_dec_options = ilbc_set_dec_options,
};
__attribute__((constructor))
static void init(void) {
codeclib_register_codec(&ilbc);
}