diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 0671374ef569e8dcc09e1799377af45404432d75..b91bc411576d376590eccb5a39b88f7aeb2c22cb 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -753,18 +753,18 @@ static void rtp_codecs_payloads_copy_rx(struct ast_rtp_codecs *src, struct ast_r /*! * \internal - * \brief Remove other matching payload mappings. + * \brief Determine if a type of payload is already present in mappings. * \since 14.0.0 * - * \param codecs Codecs that need tx mappings removed. - * \param instance RTP instance to notify of any payloads removed. + * \param codecs Codecs to be checked for mappings. * \param to_match Payload type object to compare against. * * \note It is assumed that codecs is write locked before calling. * - * \return Nothing + * \retval 0 not found + * \retval 1 found */ -static void payload_mapping_tx_remove_other_mappings(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, struct ast_rtp_payload_type *to_match) +static int payload_mapping_tx_is_present(const struct ast_rtp_codecs *codecs, const struct ast_rtp_payload_type *to_match) { int idx; struct ast_rtp_payload_type *current; @@ -772,12 +772,18 @@ static void payload_mapping_tx_remove_other_mappings(struct ast_rtp_codecs *code for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_tx); ++idx) { current = AST_VECTOR_GET(&codecs->payload_mapping_tx, idx); - if (!current || current == to_match) { + if (!current) { continue; } + if (current == to_match) { + /* The exact object is already in the mapping. */ + return 1; + } if (current->asterisk_format && to_match->asterisk_format) { - if (ast_format_cmp(current->format, to_match->format) == AST_FORMAT_CMP_NOT_EQUAL) { + if (ast_format_get_codec_id(current->format) != ast_format_get_codec_id(to_match->format)) { continue; + } else if (current->payload == to_match->payload) { + return 0; } } else if (!current->asterisk_format && !to_match->asterisk_format) { if (current->rtp_code != to_match->rtp_code) { @@ -787,13 +793,10 @@ static void payload_mapping_tx_remove_other_mappings(struct ast_rtp_codecs *code continue; } - /* Remove other mapping */ - AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, idx, NULL); - ao2_ref(current, -1); - if (instance && instance->engine && instance->engine->payload_set) { - instance->engine->payload_set(instance, idx, 0, NULL, 0); - } + return 1; } + + return 0; } /*! @@ -833,13 +836,14 @@ static void rtp_codecs_payloads_copy_tx(struct ast_rtp_codecs *src, struct ast_r if (instance && instance->engine && instance->engine->payload_set) { instance->engine->payload_set(instance, idx, type->asterisk_format, type->format, type->rtp_code); } - - payload_mapping_tx_remove_other_mappings(dest, instance, type); } } void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance) { + int idx; + struct ast_rtp_payload_type *type; + ast_rwlock_wrlock(&dest->codecs_lock); /* Deadlock avoidance because of held write lock. */ @@ -849,6 +853,17 @@ void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_cod ast_rwlock_wrlock(&dest->codecs_lock); } + /* + * This represents a completely new mapping of what the remote party is + * expecting for payloads, so we clear out the entire tx payload mapping + * vector and replace it. + */ + for (idx = 0; idx < AST_VECTOR_SIZE(&dest->payload_mapping_tx); ++idx) { + type = AST_VECTOR_GET(&dest->payload_mapping_tx, idx); + ao2_t_cleanup(type, "destroying ast_rtp_codec tx mapping"); + AST_VECTOR_REPLACE(&dest->payload_mapping_tx, idx, NULL); + } + rtp_codecs_payloads_copy_rx(src, dest, instance); rtp_codecs_payloads_copy_tx(src, dest, instance); dest->framing = src->framing; @@ -921,18 +936,20 @@ void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct as ast_rwlock_wrlock(&codecs->codecs_lock); - if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { - ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload), - "cleaning up replaced tx payload type"); - } - AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, new_type); + if (!payload_mapping_tx_is_present(codecs, new_type)) { + if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { + ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload), + "cleaning up replaced tx payload type"); + } + AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, new_type); - if (instance && instance->engine && instance->engine->payload_set) { - instance->engine->payload_set(instance, payload, new_type->asterisk_format, new_type->format, new_type->rtp_code); + if (instance && instance->engine && instance->engine->payload_set) { + instance->engine->payload_set(instance, payload, new_type->asterisk_format, new_type->format, new_type->rtp_code); + } + } else { + ao2_ref(new_type, -1); } - payload_mapping_tx_remove_other_mappings(codecs, instance, new_type); - ast_rwlock_unlock(&codecs->codecs_lock); } @@ -995,17 +1012,20 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs, new_type->format = ast_format_parse_sdp_fmtp(new_type->format, ""); } - if (pt < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { - ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, pt), - "cleaning up replaced tx payload type"); - } - AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, pt, new_type); + if (!payload_mapping_tx_is_present(codecs, new_type)) { + if (pt < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { + ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, pt), + "cleaning up replaced tx payload type"); + } + AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, pt, new_type); - if (instance && instance->engine && instance->engine->payload_set) { - instance->engine->payload_set(instance, pt, new_type->asterisk_format, new_type->format, new_type->rtp_code); + if (instance && instance->engine && instance->engine->payload_set) { + instance->engine->payload_set(instance, pt, new_type->asterisk_format, new_type->format, new_type->rtp_code); + } + } else { + ao2_ref(new_type, -1); } - payload_mapping_tx_remove_other_mappings(codecs, instance, new_type); break; } @@ -1088,11 +1108,14 @@ int ast_rtp_codecs_payload_replace_format(struct ast_rtp_codecs *codecs, int pay type->primary_mapping = 1; ast_rwlock_wrlock(&codecs->codecs_lock); - if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { - ao2_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload)); + if (!payload_mapping_tx_is_present(codecs, type)) { + if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { + ao2_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload)); + } + AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, type); + } else { + ao2_ref(type, -1); } - AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, type); - payload_mapping_tx_remove_other_mappings(codecs, NULL, type); ast_rwlock_unlock(&codecs->codecs_lock); return 0;