diff --git a/daemon/codec.c b/daemon/codec.c index 0fac155d2..28c6cd8a4 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -36,6 +36,7 @@ static void __ssrc_handler_free(struct codec_ssrc_handler *p); static void __transcode_packet_free(struct transcode_packet *); static struct rtp_payload_type *__rtp_payload_type_copy(const struct rtp_payload_type *pt); +static void __rtp_payload_type_dup(struct call *call, struct rtp_payload_type *pt); static void __rtp_payload_type_add_name(GHashTable *, struct rtp_payload_type *pt); @@ -83,8 +84,9 @@ static void __make_transcoder(struct codec_handler *handler, struct rtp_payload_ handler->ssrc_hash = create_ssrc_hash_full(__ssrc_handler_new, (ssrc_free_func_t) __ssrc_handler_free, handler); - ilog(LOG_DEBUG, "Created transcode context for '" STR_FORMAT "' -> '" STR_FORMAT "'", - STR_FMT(&source->encoding), STR_FMT(&dest->encoding)); + ilog(LOG_DEBUG, "Created transcode context for " STR_FORMAT "/%u/%i -> " STR_FORMAT "/%u/%i", + STR_FMT(&source->encoding), source->clock_rate, source->channels, + STR_FMT(&dest->encoding), dest->clock_rate, dest->channels); return; @@ -304,6 +306,12 @@ static void __transcode_packet_free(struct transcode_packet *p) { static struct ssrc_entry *__ssrc_handler_new(void *p) { struct codec_handler *h = p; + + ilog(LOG_DEBUG, "Creating SSRC handler to transcode from %s/%u/%i to %s/%u/%i", + h->source_pt.codec_def->rtpname, h->source_pt.clock_rate, + h->source_pt.channels, h->dest_pt.codec_def->rtpname, h->dest_pt.clock_rate, + h->dest_pt.channels); + struct codec_ssrc_handler *ch = g_slice_alloc0(sizeof(*ch)); ch->handler = h; mutex_init(&ch->lock); @@ -441,13 +449,45 @@ void codec_packet_free(void *pp) { -static struct rtp_payload_type *codec_make_payload_type(const str *codec) { +static struct rtp_payload_type *codec_make_dynamic_payload_type(const codec_def_t *dec, struct call *call) { + if (dec->default_channels <= 0 || dec->default_clockrate < 0) + return NULL; + + struct rtp_payload_type *ret = g_slice_alloc0(sizeof(*ret)); + ret->payload_type = -1; + str_init(&ret->encoding, (char *) dec->rtpname); + ret->clock_rate = dec->default_clockrate; + ret->channels = dec->default_channels; + + char full_encoding[64]; + char params[32] = ""; + + if (ret->channels > 1) { + snprintf(full_encoding, sizeof(full_encoding), "%s/%u/%i", dec->rtpname, ret->clock_rate, + ret->channels); + snprintf(params, sizeof(params), "%i", ret->channels); + } + else + snprintf(full_encoding, sizeof(full_encoding), "%s/%u", dec->rtpname, ret->clock_rate); + + str_init(&ret->encoding_with_params, full_encoding); + str_init(&ret->encoding_parameters, params); + ret->format_parameters = STR_EMPTY; + ret->codec_def = dec; + + __rtp_payload_type_dup(call, ret); + return ret; +} + + +// XXX allow specifying codec params (e.g. "transcode=opus/16000/1") +static struct rtp_payload_type *codec_make_payload_type(const str *codec, struct call *call) { const codec_def_t *dec = codec_find(codec); if (!dec) return NULL; const struct rtp_payload_type *rfc_pt = rtp_get_rfc_codec(codec); if (!rfc_pt) - return NULL; // XXX amend for other codecs + return codec_make_dynamic_payload_type(dec, call); struct rtp_payload_type *ret = __rtp_payload_type_copy(rfc_pt); ret->codec_def = dec; @@ -457,7 +497,7 @@ static struct rtp_payload_type *codec_make_payload_type(const str *codec) { static struct rtp_payload_type *codec_add_payload_type(const str *codec, struct call_media *media) { - struct rtp_payload_type *pt = codec_make_payload_type(codec); + struct rtp_payload_type *pt = codec_make_payload_type(codec, media->call); if (!pt) { ilog(LOG_WARN, "Codec '" STR_FORMAT "' requested for transcoding is not supported", STR_FMT(codec)); diff --git a/lib/codeclib.c b/lib/codeclib.c index 1d7fcac19..288f579db 100644 --- a/lib/codeclib.c +++ b/lib/codeclib.c @@ -22,15 +22,25 @@ -#define CODEC_DEF_MULT_NAME(ref, id, mult, name) { \ +#define CODEC_DEF_FULL(ref, id, mult, name, clockrate, channels) { \ .rtpname = #ref, \ .avcodec_id = AV_CODEC_ID_ ## id, \ .clockrate_mult = mult, \ .avcodec_name = #name, \ + .default_clockrate = clockrate, \ + .default_channels = channels, \ } +#define CODEC_DEF_MULT_NAME(ref, id, mult, name) CODEC_DEF_FULL(ref, id, mult, name, -1, -1) +#define CODEC_DEF_MULT_NAME_ENC(ref, id, mult, name, clockrate, channels) \ + CODEC_DEF_FULL(ref, id, mult, name, clockrate, channels) #define CODEC_DEF_MULT(ref, id, mult) CODEC_DEF_MULT_NAME(ref, id, mult, NULL) +#define CODEC_DEF_MULT_ENC(ref, id, mult, clockrate, channels) \ + CODEC_DEF_MULT_NAME_ENC(ref, id, mult, NULL, clockrate, channels) #define CODEC_DEF_NAME(ref, id, name) CODEC_DEF_MULT_NAME(ref, id, 1, name) +#define CODEC_DEF_NAME_ENC(ref, id, name, clockrate, channels) \ + CODEC_DEF_MULT_NAME_ENC(ref, id, 1, name, clockrate, channels) #define CODEC_DEF(ref, id) CODEC_DEF_MULT(ref, id, 1) +#define CODEC_DEF_ENC(ref, id, clockrate, channels) CODEC_DEF_MULT_ENC(ref, id, 1, clockrate, channels) static const struct codec_def_s codecs[] = { CODEC_DEF(PCMA, PCM_ALAW), @@ -39,10 +49,10 @@ static const struct codec_def_s codecs[] = { CODEC_DEF_MULT(G722, ADPCM_G722, 2), CODEC_DEF(QCELP, QCELP), CODEC_DEF(G729, G729), - CODEC_DEF(speex, SPEEX), + CODEC_DEF_ENC(speex, SPEEX, 16000, 1), CODEC_DEF(GSM, GSM), CODEC_DEF(iLBC, ILBC), - CODEC_DEF_NAME(opus, OPUS, libopus), + CODEC_DEF_NAME_ENC(opus, OPUS, libopus, 48000, 2), CODEC_DEF_NAME(vorbis, VORBIS, libvorbis), CODEC_DEF(ac3, AC3), CODEC_DEF(eac3, EAC3), diff --git a/lib/codeclib.h b/lib/codeclib.h index f6ba15cb5..b436dd21f 100644 --- a/lib/codeclib.h +++ b/lib/codeclib.h @@ -28,9 +28,11 @@ typedef struct packet_sequencer_s packet_sequencer_t; struct codec_def_s { const char *rtpname; - int clockrate_mult; - int avcodec_id; + const int clockrate_mult; + const int avcodec_id; const char *avcodec_name; + const int default_clockrate; + const int default_channels; }; struct format_s { diff --git a/lib/rtplib.c b/lib/rtplib.c index de05e0ca5..bc5b8d9ab 100644 --- a/lib/rtplib.c +++ b/lib/rtplib.c @@ -20,6 +20,7 @@ struct rtp_extension { .encoding = STR_CONST_INIT(#name), \ .encoding_with_params = STR_CONST_INIT(#name "/" #c_rate), \ .clock_rate = c_rate, \ + .channels = 1, \ } const struct rtp_payload_type rfc_rtp_payload_types[] = diff --git a/lib/rtplib.h b/lib/rtplib.h index 17a1c4a7e..17b1541f5 100644 --- a/lib/rtplib.h +++ b/lib/rtplib.h @@ -18,12 +18,12 @@ struct rtp_header { struct rtp_payload_type { int payload_type; - str encoding_with_params; - str encoding; - unsigned int clock_rate; - str encoding_parameters; - int channels; - str format_parameters; + str encoding_with_params; // "opus/48000/2" + str encoding; // "opus" + unsigned int clock_rate; // 48000 + str encoding_parameters; // "2" + int channels; // 2 + str format_parameters; // value of a=fmtp const codec_def_t *codec_def; };