|
|
@ -448,6 +448,85 @@ void codec_packet_free(void *pp) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct rtp_payload_type *codec_make_payload_type(const str *codec_str, struct call_media *media) { |
|
|
|
|
|
str codec_fmt = *codec_str; |
|
|
|
|
|
str codec, parms, chans, opts, extra_opts; |
|
|
|
|
|
if (str_token_sep(&codec, &codec_fmt, '/')) |
|
|
|
|
|
return NULL; |
|
|
|
|
|
str_token_sep(&parms, &codec_fmt, '/'); |
|
|
|
|
|
str_token_sep(&chans, &codec_fmt, '/'); |
|
|
|
|
|
str_token_sep(&opts, &codec_fmt, '/'); |
|
|
|
|
|
str_token_sep(&extra_opts, &codec_fmt, '/'); |
|
|
|
|
|
|
|
|
|
|
|
int clockrate = str_to_i(&parms, 0); |
|
|
|
|
|
int channels = str_to_i(&chans, 0); |
|
|
|
|
|
int bitrate = str_to_i(&opts, 0); |
|
|
|
|
|
int ptime = str_to_i(&extra_opts, 0); |
|
|
|
|
|
|
|
|
|
|
|
if (clockrate && !channels) |
|
|
|
|
|
channels = 1; |
|
|
|
|
|
|
|
|
|
|
|
struct rtp_payload_type *ret = g_slice_alloc0(sizeof(*ret)); |
|
|
|
|
|
ret->payload_type = -1; |
|
|
|
|
|
ret->encoding = codec; |
|
|
|
|
|
ret->clock_rate = clockrate; |
|
|
|
|
|
ret->channels = channels; |
|
|
|
|
|
ret->bitrate = bitrate; |
|
|
|
|
|
ret->ptime = ptime; |
|
|
|
|
|
|
|
|
|
|
|
const codec_def_t *def = codec_find(&ret->encoding, 0); |
|
|
|
|
|
ret->codec_def = def; |
|
|
|
|
|
|
|
|
|
|
|
#ifdef WITH_TRANSCODING |
|
|
|
|
|
if (!ret->clock_rate) |
|
|
|
|
|
ret->clock_rate = def->default_clockrate; |
|
|
|
|
|
if (!ret->channels) |
|
|
|
|
|
ret->channels = def->default_channels; |
|
|
|
|
|
if (!ret->ptime) |
|
|
|
|
|
ret->ptime = def->default_ptime; |
|
|
|
|
|
|
|
|
|
|
|
if (def->init) |
|
|
|
|
|
def->init(ret); |
|
|
|
|
|
|
|
|
|
|
|
if (def->rfc_payload_type >= 0) { |
|
|
|
|
|
const struct rtp_payload_type *rfc_pt = rtp_get_rfc_payload_type(def->rfc_payload_type); |
|
|
|
|
|
// only use the RFC payload type if all parameters match |
|
|
|
|
|
if (rfc_pt |
|
|
|
|
|
&& (ret->clock_rate == 0 || ret->clock_rate == rfc_pt->clock_rate) |
|
|
|
|
|
&& (ret->channels == 0 || ret->channels == rfc_pt->channels)) |
|
|
|
|
|
{ |
|
|
|
|
|
ret->payload_type = rfc_pt->payload_type; |
|
|
|
|
|
if (!ret->clock_rate) |
|
|
|
|
|
ret->clock_rate = rfc_pt->clock_rate; |
|
|
|
|
|
if (!ret->channels) |
|
|
|
|
|
ret->channels = rfc_pt->channels; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
// init params strings |
|
|
|
|
|
char full_encoding[64]; |
|
|
|
|
|
char params[32] = ""; |
|
|
|
|
|
|
|
|
|
|
|
if (ret->channels > 1) { |
|
|
|
|
|
snprintf(full_encoding, sizeof(full_encoding), STR_FORMAT "/%u/%i", STR_FMT(&codec), |
|
|
|
|
|
ret->clock_rate, |
|
|
|
|
|
ret->channels); |
|
|
|
|
|
snprintf(params, sizeof(params), "%i", ret->channels); |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
snprintf(full_encoding, sizeof(full_encoding), STR_FORMAT "/%u", STR_FMT(&codec), |
|
|
|
|
|
ret->clock_rate); |
|
|
|
|
|
|
|
|
|
|
|
str_init(&ret->encoding_with_params, full_encoding); |
|
|
|
|
|
str_init(&ret->encoding_parameters, params); |
|
|
|
|
|
ret->format_parameters = STR_EMPTY; |
|
|
|
|
|
|
|
|
|
|
|
__rtp_payload_type_dup(media->call, ret); |
|
|
|
|
|
|
|
|
|
|
|
return ret; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef WITH_TRANSCODING |
|
|
#ifdef WITH_TRANSCODING |
|
|
@ -692,95 +771,36 @@ static int handler_func_transcode(struct codec_handler *h, struct call_media *me |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct rtp_payload_type *codec_make_dynamic_payload_type(const codec_def_t *dec, struct call_media *media, |
|
|
|
|
|
int clockrate, int channels, int bitrate, int ptime) |
|
|
|
|
|
{ |
|
|
|
|
|
if (dec->default_channels <= 0 || dec->default_clockrate < 0) |
|
|
|
|
|
|
|
|
// special return value `(void *) 0x1` to signal type mismatch |
|
|
|
|
|
static struct rtp_payload_type *codec_make_payload_type_sup(const str *codec_str, struct call_media *media) { |
|
|
|
|
|
struct rtp_payload_type *ret = codec_make_payload_type(codec_str, media); |
|
|
|
|
|
if (!ret) |
|
|
return NULL; |
|
|
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 = clockrate ? : dec->default_clockrate; |
|
|
|
|
|
ret->channels = channels ? : dec->default_channels; |
|
|
|
|
|
ret->bitrate = bitrate; |
|
|
|
|
|
ret->ptime = ptime ? : (media->ptime ? : dec->default_ptime); |
|
|
|
|
|
|
|
|
|
|
|
if (dec->init) |
|
|
|
|
|
dec->init(ret); |
|
|
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
|
if (media->type_id && ret->codec_def->media_type != media->type_id) { |
|
|
|
|
|
payload_type_free(ret); |
|
|
|
|
|
return (void *) 0x1; |
|
|
} |
|
|
} |
|
|
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(media->call, ret); |
|
|
|
|
|
|
|
|
// we must support both encoding and decoding |
|
|
|
|
|
if (!ret->codec_def->support_decoding) |
|
|
|
|
|
goto err; |
|
|
|
|
|
if (!ret->codec_def->support_encoding) |
|
|
|
|
|
goto err; |
|
|
|
|
|
if (ret->codec_def->default_channels <= 0 || ret->codec_def->default_clockrate < 0) |
|
|
|
|
|
goto err; |
|
|
|
|
|
|
|
|
return ret; |
|
|
return ret; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// special return value `(void *) 0x1` to signal type mismatch |
|
|
|
|
|
struct rtp_payload_type *codec_make_payload_type(const str *codec_str, struct call_media *media) { |
|
|
|
|
|
str codec_fmt = *codec_str; |
|
|
|
|
|
str codec, parms, chans, opts, extra_opts; |
|
|
|
|
|
if (str_token_sep(&codec, &codec_fmt, '/')) |
|
|
|
|
|
return NULL; |
|
|
|
|
|
str_token_sep(&parms, &codec_fmt, '/'); |
|
|
|
|
|
str_token_sep(&chans, &codec_fmt, '/'); |
|
|
|
|
|
str_token_sep(&opts, &codec_fmt, '/'); |
|
|
|
|
|
str_token_sep(&extra_opts, &codec_fmt, '/'); |
|
|
|
|
|
|
|
|
|
|
|
int clockrate = str_to_i(&parms, 0); |
|
|
|
|
|
int channels = str_to_i(&chans, 0); |
|
|
|
|
|
int bitrate = str_to_i(&opts, 0); |
|
|
|
|
|
int ptime = str_to_i(&extra_opts, 0); |
|
|
|
|
|
|
|
|
|
|
|
if (clockrate && !channels) |
|
|
|
|
|
channels = 1; |
|
|
|
|
|
|
|
|
|
|
|
const codec_def_t *dec = codec_find(&codec, 0); |
|
|
|
|
|
if (!dec) |
|
|
|
|
|
return NULL; |
|
|
|
|
|
if (media->type_id && dec->media_type != media->type_id) |
|
|
|
|
|
return (void *) 0x1; |
|
|
|
|
|
// we must support both encoding and decoding |
|
|
|
|
|
if (!dec->support_decoding) |
|
|
|
|
|
return NULL; |
|
|
|
|
|
if (!dec->support_encoding) |
|
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
|
|
|
if (dec->rfc_payload_type >= 0) { |
|
|
|
|
|
const struct rtp_payload_type *rfc_pt = rtp_get_rfc_payload_type(dec->rfc_payload_type); |
|
|
|
|
|
// only use the RFC payload type if all parameters match |
|
|
|
|
|
if (rfc_pt |
|
|
|
|
|
&& (clockrate == 0 || clockrate == rfc_pt->clock_rate) |
|
|
|
|
|
&& (channels == 0 || channels == rfc_pt->channels)) |
|
|
|
|
|
{ |
|
|
|
|
|
struct rtp_payload_type *ret = __rtp_payload_type_copy(rfc_pt); |
|
|
|
|
|
ret->codec_def = dec; |
|
|
|
|
|
ret->ptime = ptime; |
|
|
|
|
|
return ret; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
return codec_make_dynamic_payload_type(dec, media, clockrate, channels, bitrate, ptime); |
|
|
|
|
|
|
|
|
err: |
|
|
|
|
|
payload_type_free(ret); |
|
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct rtp_payload_type *codec_add_payload_type(const str *codec, struct call_media *media) { |
|
|
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, media); |
|
|
|
|
|
|
|
|
struct rtp_payload_type *pt = codec_make_payload_type_sup(codec, media); |
|
|
if (!pt) { |
|
|
if (!pt) { |
|
|
ilog(LOG_WARN, "Codec '" STR_FORMAT "' requested for transcoding is not supported", |
|
|
ilog(LOG_WARN, "Codec '" STR_FORMAT "' requested for transcoding is not supported", |
|
|
STR_FMT(codec)); |
|
|
STR_FMT(codec)); |
|
|
|