diff --git a/daemon/codec.c b/daemon/codec.c index 43b08b586..e00a69570 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -419,7 +419,7 @@ static void __make_transcoder(struct codec_handler *handler, struct rtp_payload_ // don't reset handler if it already matches what we want if (!handler->transcoder) goto reset; - if (!rtp_payload_type_eq(dest, &handler->dest_pt)) + if (!rtp_payload_type_eq_exact(dest, &handler->dest_pt)) goto reset; if (handler->handler_func != handler_func_transcode) goto reset; @@ -707,7 +707,7 @@ static struct codec_handler *__get_pt_handler(struct call_media *receiver, struc handler = codec_handler_lookup(receiver->codec_handlers, pt->payload_type, sink); if (handler) { // make sure existing handler matches this PT - if (!rtp_payload_type_eq(pt, &handler->source_pt)) { + if (!rtp_payload_type_eq_exact(pt, &handler->source_pt)) { ilogs(codec, LOG_DEBUG, "Resetting codec handler for PT %i", pt->payload_type); g_hash_table_remove(receiver->codec_handlers, handler); __handler_shutdown(handler); @@ -1069,7 +1069,7 @@ bool codec_handlers_update(struct call_media *receiver, struct call_media *sink, sink_pt = g_hash_table_lookup(sink->codecs.codecs, GINT_TO_POINTER(pt->payload_type)); // is it actually the same? - if (sink_pt && !rtp_payload_type_eq(pt, sink_pt)) + if (sink_pt && !rtp_payload_type_eq_compat(pt, sink_pt)) sink_pt = NULL; } @@ -4894,7 +4894,7 @@ bool codec_store_is_full_answer(const struct codec_store *src, const struct code const struct rtp_payload_type *src_pt = l->data; const struct rtp_payload_type *dst_pt = g_hash_table_lookup(dst->codecs, GINT_TO_POINTER(src_pt->payload_type)); - if (!dst_pt || !rtp_payload_type_eq(src_pt, dst_pt)) { + if (!dst_pt || !rtp_payload_type_eq_compat(src_pt, dst_pt)) { ilogs(codec, LOG_DEBUG, "Source codec " STR_FORMAT " is not present in the answer", STR_FMT(&src_pt->encoding_with_params)); return false; diff --git a/daemon/media_player.c b/daemon/media_player.c index f2d3ae340..d103ac3e2 100644 --- a/daemon/media_player.c +++ b/daemon/media_player.c @@ -308,8 +308,8 @@ found: // if we already have a handler, see if anything needs changing if (mp->handler) { - if (!rtp_payload_type_eq(&mp->handler->dest_pt, dst_pt) - || !rtp_payload_type_eq(&mp->handler->source_pt, src_pt)) + if (!rtp_payload_type_eq_exact(&mp->handler->dest_pt, dst_pt) + || !rtp_payload_type_eq_exact(&mp->handler->source_pt, src_pt)) { ilog(LOG_DEBUG, "Resetting codec handler for media player"); codec_handler_free(&mp->handler); diff --git a/lib/codeclib.h b/lib/codeclib.h index d8b781260..3b9e3a05d 100644 --- a/lib/codeclib.h +++ b/lib/codeclib.h @@ -6,6 +6,7 @@ struct codec_def_s; struct packet_sequencer_s; typedef struct codec_def_s codec_def_t; typedef struct packet_sequencer_s packet_sequencer_t; +struct rtp_payload_type; enum media_type { MT_UNKNOWN = 0, @@ -35,6 +36,12 @@ INLINE enum media_type codec_get_type(const str *type) { } +// 0: exact match +// 1: a is compatible with b (not necessarily the other way around) +// -1: a is not compatible with b +typedef int format_cmp_f(const struct rtp_payload_type *a, const struct rtp_payload_type *b); + + #ifndef WITHOUT_CODECLIB @@ -77,7 +84,7 @@ typedef int packetizer_f(AVPacket *, GString *, str *, encoder_t *); typedef void format_init_f(struct rtp_payload_type *); typedef void set_enc_options_f(encoder_t *, const str *); typedef void set_dec_options_f(decoder_t *, const str *); -typedef int format_cmp_f(const struct rtp_payload_type *, const struct rtp_payload_type *); + typedef int format_parse_f(struct rtp_codec_format *, const str *fmtp); @@ -389,7 +396,6 @@ INLINE int decoder_event(decoder_t *dec, enum codec_event event, void *ptr) { #else -typedef int format_cmp_f(const void *, const void *); // stubs struct codec_def_s { diff --git a/lib/rtplib.c b/lib/rtplib.c index 96de9ae54..fbfda7a15 100644 --- a/lib/rtplib.c +++ b/lib/rtplib.c @@ -144,28 +144,53 @@ const struct rtp_payload_type *rtp_get_rfc_codec(const str *codec) { return NULL; } -bool rtp_payload_type_eq(const struct rtp_payload_type *a, const struct rtp_payload_type *b) { - if (!rtp_payload_type_eq_nf(a, b)) +// helper function: matches only basic params, without matching payload type number +static bool rtp_payload_type_fmt_eq_nf(const struct rtp_payload_type *a, const struct rtp_payload_type *b) { + if (a->clock_rate != b->clock_rate) + return false; + if (a->channels != b->channels) return false; + if (str_casecmp_str(&a->encoding, &b->encoding)) + return false; + return true; +} + +// matches basic params and format params, but not payload type number +// returns matching val as per format_cmp_f +int rtp_payload_type_fmt_eq(const struct rtp_payload_type *a, const struct rtp_payload_type *b) { + if (!rtp_payload_type_fmt_eq_nf(a, b)) + return -1; if (a->codec_def && a->codec_def == b->codec_def) { if (a->codec_def->format_cmp) - return a->codec_def->format_cmp(a, b) == 0; + return a->codec_def->format_cmp(a, b); } if (!a->codec_def) // ignore format of codecs we don't know - return true; + return 0; if (str_cmp_str(&a->format_parameters, &b->format_parameters)) - return false; - return true; + return -1; + return 0; +} +bool rtp_payload_type_fmt_eq_exact(const struct rtp_payload_type *a, const struct rtp_payload_type *b) { + return rtp_payload_type_fmt_eq(a, b) == 0; +} +bool rtp_payload_type_fmt_eq_compat(const struct rtp_payload_type *a, const struct rtp_payload_type *b) { + return rtp_payload_type_fmt_eq(a, b) >= 0; } -bool rtp_payload_type_eq_nf(const struct rtp_payload_type *a, const struct rtp_payload_type *b) { +bool rtp_payload_type_eq_exact(const struct rtp_payload_type *a, const struct rtp_payload_type *b) { if (a->payload_type != b->payload_type) return false; - if (a->clock_rate != b->clock_rate) - return false; - if (a->channels != b->channels) + return rtp_payload_type_fmt_eq(a, b) == 0; +} +bool rtp_payload_type_eq_compat(const struct rtp_payload_type *a, const struct rtp_payload_type *b) { + if (a->payload_type != b->payload_type) return false; - if (str_casecmp_str(&a->encoding, &b->encoding)) + return rtp_payload_type_fmt_eq(a, b) >= 0; +} + +// same as rtp_payload_type_fmt_eq_nf plus matching payload type number +bool rtp_payload_type_eq_nf(const struct rtp_payload_type *a, const struct rtp_payload_type *b) { + if (a->payload_type != b->payload_type) return false; - return true; + return rtp_payload_type_fmt_eq_nf(a, b); } diff --git a/lib/rtplib.h b/lib/rtplib.h index d40076b02..0b76e785c 100644 --- a/lib/rtplib.h +++ b/lib/rtplib.h @@ -75,8 +75,16 @@ int rtp_padding(const struct rtp_header *header, str *payload); const struct rtp_payload_type *rtp_get_rfc_payload_type(unsigned int type); const struct rtp_payload_type *rtp_get_rfc_codec(const str *codec); -bool rtp_payload_type_eq(const struct rtp_payload_type *, const struct rtp_payload_type *); +// if not `exact` then also returns true if `a` is compatible with `b` +// matches all params +bool rtp_payload_type_eq_exact(const struct rtp_payload_type *a, const struct rtp_payload_type *b); +bool rtp_payload_type_eq_compat(const struct rtp_payload_type *a, const struct rtp_payload_type *b); +// matches only basic params and payload type number bool rtp_payload_type_eq_nf(const struct rtp_payload_type *, const struct rtp_payload_type *); +// matches all params except payload type number +int rtp_payload_type_fmt_eq(const struct rtp_payload_type *a, const struct rtp_payload_type *b); +bool rtp_payload_type_fmt_eq_exact(const struct rtp_payload_type *a, const struct rtp_payload_type *b); +bool rtp_payload_type_fmt_eq_compat(const struct rtp_payload_type *a, const struct rtp_payload_type *b); #endif