diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index d9e182cc79be83777d0a9057b7018ff0451f690f..0210e8ab2c8efd51a95328fa55177bff2a114556 100644 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -2018,7 +2018,6 @@ static int process_sdp(struct mgcp_subchannel *sub, struct mgcp_request *req) ast_rtp_instance_set_remote_address(sub->rtp, &sin_tmp); ast_debug(3, "Peer RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); /* Scan through the RTP payload types specified in a "m=" line: */ - ast_rtp_codecs_payloads_clear(ast_rtp_instance_get_codecs(sub->rtp), sub->rtp); codecs = ast_strdupa(m + len); while (!ast_strlen_zero(codecs)) { if (sscanf(codecs, "%30d%n", &codec, &len) != 1) { @@ -4487,7 +4486,8 @@ static enum ast_rtp_glue_result mgcp_get_rtp_peer(struct ast_channel *chan, stru if (!(sub = ast_channel_tech_pvt(chan)) || !(sub->rtp)) return AST_RTP_GLUE_RESULT_FORBID; - *instance = sub->rtp ? ao2_ref(sub->rtp, +1), sub->rtp : NULL; + ao2_ref(sub->rtp, +1); + *instance = sub->rtp; if (sub->parent->directmedia) return AST_RTP_GLUE_RESULT_REMOTE; diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c index a3c0ffd5c13a5d43b927d0801bb8e49a42aaaeee..874f6b2dccc5f36b94ecdf4b02dda147f83832e0 100644 --- a/channels/chan_unistim.c +++ b/channels/chan_unistim.c @@ -2709,7 +2709,8 @@ static void send_start_rtp(struct unistim_subchannel *sub) } pte = sub->parent->parent->session; - codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(sub->rtp), 1, ast_channel_readformat(sub->owner), 0); + codec = ast_rtp_codecs_payload_code_tx(ast_rtp_instance_get_codecs(sub->rtp), + 1, ast_channel_readformat(sub->owner), 0); if ((ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) || (ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_alaw) == AST_FORMAT_CMP_EQUAL)) { if (unistimdebug) { diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h index d6a9be57401d7db0039c4438d3cc714d5dbf186f..a52567a139637c7eccaccf6b96ab09d8d6a7c12c 100644 --- a/include/asterisk/rtp_engine.h +++ b/include/asterisk/rtp_engine.h @@ -251,6 +251,8 @@ struct ast_rtp_payload_type { int rtp_code; /*! Actual payload number */ int payload; + /*! TRUE if this is the primary mapping to the format. */ + unsigned int primary_mapping:1; }; /* Common RTCP report types */ @@ -577,16 +579,18 @@ struct ast_rtp_engine { /*! Structure that represents codec and packetization information */ struct ast_rtp_codecs { - /*! Payloads present */ - AST_VECTOR(, struct ast_rtp_payload_type *) payloads; - /*! The framing for this media session */ - unsigned int framing; /*! RW lock that protects elements in this structure */ ast_rwlock_t codecs_lock; + /*! Rx payload type mapping exceptions */ + AST_VECTOR(, struct ast_rtp_payload_type *) payload_mapping_rx; + /*! Tx payload type mapping */ + AST_VECTOR(, struct ast_rtp_payload_type *) payload_mapping_tx; + /*! The framing for this media session */ + unsigned int framing; }; #define AST_RTP_CODECS_NULL_INIT \ - { .payloads = { 0, }, .framing = 0, .codecs_lock = AST_RWLOCK_INIT_VALUE, } + { .codecs_lock = AST_RWLOCK_INIT_VALUE, .payload_mapping_rx = { 0, }, .payload_mapping_tx = { 0, }, .framing = 0, } /*! Structure that represents the glue that binds an RTP instance to a channel */ struct ast_rtp_glue { @@ -1192,7 +1196,7 @@ int ast_rtp_codecs_payloads_initialize(struct ast_rtp_codecs *codecs); void ast_rtp_codecs_payloads_destroy(struct ast_rtp_codecs *codecs); /*! - * \brief Clear payload information from an RTP instance + * \brief Clear rx and tx payload mapping information from an RTP instance * * \param codecs The codecs structure that payloads will be cleared from * \param instance Optionally the instance that the codecs structure belongs to @@ -1230,7 +1234,19 @@ void ast_rtp_codecs_payloads_clear(struct ast_rtp_codecs *codecs, struct ast_rtp void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance); /*! - * \brief Record payload information that was seen in an m= SDP line + * \brief Crossover copy the tx payload mapping of src to the rx payload mapping of dest. + * \since 14.0.0 + * + * \param src The source codecs structure + * \param dest The destination codecs structure that the values from src will be copied to + * \param instance Optionally the instance that the dst codecs structure belongs to + * + * \return Nothing + */ +void ast_rtp_codecs_payloads_xover(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance); + +/*! + * \brief Record tx payload type information that was seen in an m= SDP line * * \param codecs The codecs structure to muck with * \param instance Optionally the instance that the codecs structure belongs to @@ -1249,7 +1265,7 @@ void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_cod void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload); /*! - * \brief Record payload information that was seen in an a=rtpmap: SDP line + * \brief Record tx payload type information that was seen in an a=rtpmap: SDP line * * \param codecs The codecs structure to muck with * \param instance Optionally the instance that the codecs structure belongs to @@ -1275,7 +1291,7 @@ void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct as int ast_rtp_codecs_payloads_set_rtpmap_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload, char *mimetype, char *mimesubtype, enum ast_rtp_options options); /*! - * \brief Set payload type to a known MIME media type for a codec with a specific sample rate + * \brief Set tx payload type to a known MIME media type for a codec with a specific sample rate * * \param codecs RTP structure to modify * \param instance Optionally the instance that the codecs structure belongs to @@ -1300,7 +1316,7 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs, unsigned int sample_rate); /*! - * \brief Remove payload information + * \brief Remove tx payload type mapped information * * \param codecs The codecs structure to muck with * \param instance Optionally the instance that the codecs structure belongs to @@ -1319,7 +1335,7 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs, void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload); /*! - * \brief Retrieve payload information by payload + * \brief Retrieve rx payload mapped information by payload type * * \param codecs Codecs structure to look in * \param payload Numerical payload to look up @@ -1342,10 +1358,10 @@ void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp struct ast_rtp_payload_type *ast_rtp_codecs_get_payload(struct ast_rtp_codecs *codecs, int payload); /*! - * \brief Update the format associated with a payload in a codecs structure + * \brief Update the format associated with a tx payload type in a codecs structure * * \param codecs Codecs structure to operate on - * \param payload Numerical payload to look up + * \param payload Numerical payload type to look up * \param format The format to replace the existing one * * \retval 0 success @@ -1356,10 +1372,10 @@ struct ast_rtp_payload_type *ast_rtp_codecs_get_payload(struct ast_rtp_codecs *c int ast_rtp_codecs_payload_replace_format(struct ast_rtp_codecs *codecs, int payload, struct ast_format *format); /*! - * \brief Retrieve the actual ast_format stored on the codecs structure for a specific payload + * \brief Retrieve the actual ast_format stored on the codecs structure for a specific tx payload type * * \param codecs Codecs structure to look in - * \param payload Numerical payload to look up + * \param payload Numerical payload type to look up * * \retval pointer to format structure on success * \retval NULL on failure @@ -1428,14 +1444,15 @@ unsigned int ast_rtp_lookup_sample_rate2(int asterisk_format, struct ast_format void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, struct ast_format_cap *astformats, int *nonastformats); /*! - * \brief Retrieve a payload based on whether it is an Asterisk format and the code + * \brief Retrieve a rx mapped payload type based on whether it is an Asterisk format and the code * * \param codecs Codecs structure to look in * \param asterisk_format Non-zero if the given Asterisk format is present * \param format Asterisk format to look for * \param code The format to look for * - * \retval Numerical payload + * \retval Numerical payload type + * \retval -1 if not found. * * Example usage: * @@ -1450,12 +1467,26 @@ void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, struct ast_fo int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code); /*! - * \brief Search for a payload code in the ast_rtp_codecs structure + * \brief Retrieve a tx mapped payload type based on whether it is an Asterisk format and the code + * \since 14.0.0 * * \param codecs Codecs structure to look in + * \param asterisk_format Non-zero if the given Asterisk format is present + * \param format Asterisk format to look for * \param code The format to look for * - * \retval Numerical payload or -1 if unable to find payload in codecs + * \retval Numerical payload type + * \retval -1 if not found. + */ +int ast_rtp_codecs_payload_code_tx(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code); + +/*! + * \brief Search for the tx payload type in the ast_rtp_codecs structure + * + * \param codecs Codecs structure to look in + * \param payload The payload type format to look for + * + * \retval Numerical payload type or -1 if unable to find payload in codecs * * Example usage: * @@ -1464,9 +1495,8 @@ int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_form * \endcode * * This looks for the numerical payload for ULAW in the codecs structure. - * */ -int ast_rtp_codecs_find_payload_code(struct ast_rtp_codecs *codecs, int code); +int ast_rtp_codecs_find_payload_code(struct ast_rtp_codecs *codecs, int payload); /*! * \brief Retrieve mime subtype information on a payload diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 1375897d67f320a97cc4aaf0fda70f115c7fb6bc..229af8fc9e1abc5cb945dc6bdbdbfdee1f9d536d 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -580,22 +580,32 @@ int ast_rtp_codecs_payloads_initialize(struct ast_rtp_codecs *codecs) codecs->framing = 0; ast_rwlock_init(&codecs->codecs_lock); - res = AST_VECTOR_INIT(&codecs->payloads, AST_RTP_MAX_PT); + res = AST_VECTOR_INIT(&codecs->payload_mapping_rx, AST_RTP_MAX_PT); + res |= AST_VECTOR_INIT(&codecs->payload_mapping_tx, AST_RTP_MAX_PT); + if (res) { + AST_VECTOR_FREE(&codecs->payload_mapping_rx); + AST_VECTOR_FREE(&codecs->payload_mapping_tx); + } return res; } void ast_rtp_codecs_payloads_destroy(struct ast_rtp_codecs *codecs) { - int i; + int idx; + struct ast_rtp_payload_type *type; - for (i = 0; i < AST_VECTOR_SIZE(&codecs->payloads); i++) { - struct ast_rtp_payload_type *type; + for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_rx); ++idx) { + type = AST_VECTOR_GET(&codecs->payload_mapping_rx, idx); + ao2_t_cleanup(type, "destroying ast_rtp_codec rx mapping"); + } + AST_VECTOR_FREE(&codecs->payload_mapping_rx); - type = AST_VECTOR_GET(&codecs->payloads, i); - ao2_t_cleanup(type, "destroying ast_rtp_codec"); + for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_tx); ++idx) { + type = AST_VECTOR_GET(&codecs->payload_mapping_tx, idx); + ao2_t_cleanup(type, "destroying ast_rtp_codec tx mapping"); } - AST_VECTOR_FREE(&codecs->payloads); + AST_VECTOR_FREE(&codecs->payload_mapping_tx); ast_rwlock_destroy(&codecs->codecs_lock); } @@ -613,34 +623,254 @@ void ast_rtp_codecs_payloads_clear(struct ast_rtp_codecs *codecs, struct ast_rtp } } -void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance) +/*! + * \internal + * \brief Clear the rx primary mapping flag on all other matching mappings. + * \since 14.0.0 + * + * \param codecs Codecs that need rx clearing. + * \param to_match Payload type object to compare against. + * + * \note It is assumed that codecs is write locked before calling. + * + * \return Nothing + */ +static void payload_mapping_rx_clear_primary(struct ast_rtp_codecs *codecs, struct ast_rtp_payload_type *to_match) { - int i; + int idx; + struct ast_rtp_payload_type *current; + struct ast_rtp_payload_type *new_type; + + if (!to_match->primary_mapping) { + return; + } + + for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_rx); ++idx) { + current = AST_VECTOR_GET(&codecs->payload_mapping_rx, idx); + + if (!current || current == to_match || !current->primary_mapping) { + continue; + } + if (current->asterisk_format && to_match->asterisk_format) { + if (ast_format_cmp(current->format, to_match->format) == AST_FORMAT_CMP_NOT_EQUAL) { + continue; + } + } else if (!current->asterisk_format && !to_match->asterisk_format) { + if (current->rtp_code != to_match->rtp_code) { + continue; + } + } else { + continue; + } + + /* Replace current with non-primary marked version */ + new_type = ast_rtp_engine_alloc_payload_type(); + if (!new_type) { + continue; + } + *new_type = *current; + new_type->primary_mapping = 0; + ao2_bump(new_type->format); + AST_VECTOR_REPLACE(&codecs->payload_mapping_rx, idx, new_type); + ao2_ref(current, -1); + } +} + +/*! + * \internal + * \brief Copy the rx payload type mapping to the destination. + * \since 14.0.0 + * + * \param src The source codecs structure + * \param dest The destination codecs structure that the values from src will be copied to + * \param instance Optionally the instance that the dst codecs structure belongs to + * + * \note It is assumed that src is at least read locked before calling. + * \note It is assumed that dest is write locked before calling. + * + * \return Nothing + */ +static void rtp_codecs_payloads_copy_rx(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance) +{ + int idx; + struct ast_rtp_payload_type *type; + + for (idx = 0; idx < AST_VECTOR_SIZE(&src->payload_mapping_rx); ++idx) { + type = AST_VECTOR_GET(&src->payload_mapping_rx, idx); + if (!type) { + continue; + } + + ast_debug(2, "Copying rx payload mapping %d (%p) from %p to %p\n", + idx, type, src, dest); + ao2_ref(type, +1); + if (idx < AST_VECTOR_SIZE(&dest->payload_mapping_rx)) { + ao2_t_cleanup(AST_VECTOR_GET(&dest->payload_mapping_rx, idx), + "cleaning up rx mapping vector element about to be replaced"); + } + AST_VECTOR_REPLACE(&dest->payload_mapping_rx, idx, type); + + payload_mapping_rx_clear_primary(dest, type); + + if (instance && instance->engine && instance->engine->payload_set) { + instance->engine->payload_set(instance, idx, type->asterisk_format, type->format, type->rtp_code); + } + } +} + +/*! + * \internal + * \brief Remove other matching payload mappings. + * \since 14.0.0 + * + * \param codecs Codecs that need tx mappings removed. + * \param instance RTP instance to notify of any payloads removed. + * \param to_match Payload type object to compare against. + * + * \note It is assumed that codecs is write locked before calling. + * + * \return Nothing + */ +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) +{ + int idx; + struct ast_rtp_payload_type *current; + + 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) { + continue; + } + if (current->asterisk_format && to_match->asterisk_format) { + if (ast_format_cmp(current->format, to_match->format) == AST_FORMAT_CMP_NOT_EQUAL) { + continue; + } + } else if (!current->asterisk_format && !to_match->asterisk_format) { + if (current->rtp_code != to_match->rtp_code) { + continue; + } + } else { + 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); + } + } +} + +/*! + * \internal + * \brief Copy the tx payload type mapping to the destination. + * \since 14.0.0 + * + * \param src The source codecs structure + * \param dest The destination codecs structure that the values from src will be copied to + * \param instance Optionally the instance that the dst codecs structure belongs to + * + * \note It is assumed that src is at least read locked before calling. + * \note It is assumed that dest is write locked before calling. + * + * \return Nothing + */ +static void rtp_codecs_payloads_copy_tx(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance) +{ + int idx; + struct ast_rtp_payload_type *type; + + for (idx = 0; idx < AST_VECTOR_SIZE(&src->payload_mapping_tx); ++idx) { + type = AST_VECTOR_GET(&src->payload_mapping_tx, idx); + if (!type) { + continue; + } + + ast_debug(2, "Copying tx payload mapping %d (%p) from %p to %p\n", + idx, type, src, dest); + ao2_ref(type, +1); + if (idx < AST_VECTOR_SIZE(&dest->payload_mapping_tx)) { + ao2_t_cleanup(AST_VECTOR_GET(&dest->payload_mapping_tx, idx), + "cleaning up tx mapping vector element about to be replaced"); + } + AST_VECTOR_REPLACE(&dest->payload_mapping_tx, idx, type); + + 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); + } +} - ast_rwlock_rdlock(&src->codecs_lock); +void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance) +{ ast_rwlock_wrlock(&dest->codecs_lock); - for (i = 0; i < AST_VECTOR_SIZE(&src->payloads); i++) { - struct ast_rtp_payload_type *type; + /* Deadlock avoidance because of held write lock. */ + while (ast_rwlock_tryrdlock(&src->codecs_lock)) { + ast_rwlock_unlock(&dest->codecs_lock); + sched_yield(); + ast_rwlock_wrlock(&dest->codecs_lock); + } - type = AST_VECTOR_GET(&src->payloads, i); + rtp_codecs_payloads_copy_rx(src, dest, instance); + rtp_codecs_payloads_copy_tx(src, dest, instance); + dest->framing = src->framing; + + ast_rwlock_unlock(&src->codecs_lock); + ast_rwlock_unlock(&dest->codecs_lock); +} + +void ast_rtp_codecs_payloads_xover(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); + if (src != dest) { + /* Deadlock avoidance because of held write lock. */ + while (ast_rwlock_tryrdlock(&src->codecs_lock)) { + ast_rwlock_unlock(&dest->codecs_lock); + sched_yield(); + ast_rwlock_wrlock(&dest->codecs_lock); + } + } + + /* Crossover copy payload type tx mapping to rx mapping. */ + for (idx = 0; idx < AST_VECTOR_SIZE(&src->payload_mapping_tx); ++idx) { + type = AST_VECTOR_GET(&src->payload_mapping_tx, idx); if (!type) { continue; } - if (i < AST_VECTOR_SIZE(&dest->payloads)) { - ao2_t_cleanup(AST_VECTOR_GET(&dest->payloads, i), "cleaning up vector element about to be replaced"); + + /* All tx mapping elements should have the primary flag set. */ + ast_assert(type->primary_mapping); + + ast_debug(2, "Crossover copying tx to rx payload mapping %d (%p) from %p to %p\n", + idx, type, src, dest); + ao2_ref(type, +1); + if (idx < AST_VECTOR_SIZE(&dest->payload_mapping_rx)) { + ao2_t_cleanup(AST_VECTOR_GET(&dest->payload_mapping_rx, idx), + "cleaning up rx mapping vector element about to be replaced"); } - ast_debug(2, "Copying payload %d (%p) from %p to %p\n", i, type, src, dest); - ao2_bump(type); - AST_VECTOR_REPLACE(&dest->payloads, i, type); + AST_VECTOR_REPLACE(&dest->payload_mapping_rx, idx, type); + + payload_mapping_rx_clear_primary(dest, type); if (instance && instance->engine && instance->engine->payload_set) { - instance->engine->payload_set(instance, i, type->asterisk_format, type->format, type->rtp_code); + instance->engine->payload_set(instance, idx, type->asterisk_format, type->format, type->rtp_code); } } + dest->framing = src->framing; + + if (src != dest) { + ast_rwlock_unlock(&src->codecs_lock); + } ast_rwlock_unlock(&dest->codecs_lock); - ast_rwlock_unlock(&src->codecs_lock); } void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload) @@ -665,15 +895,18 @@ 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->payloads)) { - ao2_t_cleanup(AST_VECTOR_GET(&codecs->payloads, payload), "cleaning up replaced payload 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->payloads, payload, new_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); } + payload_mapping_tx_remove_other_mappings(codecs, instance, new_type); + ast_rwlock_unlock(&codecs->codecs_lock); } @@ -682,7 +915,7 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs, enum ast_rtp_options options, unsigned int sample_rate) { - unsigned int i; + unsigned int idx; int found = 0; if (pt < 0 || pt >= AST_RTP_MAX_PT) { @@ -691,8 +924,9 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs, ast_rwlock_rdlock(&mime_types_lock); ast_rwlock_wrlock(&codecs->codecs_lock); - for (i = 0; i < mime_types_len; ++i) { - const struct ast_rtp_mime_type *t = &ast_rtp_mime_types[i]; + + for (idx = 0; idx < mime_types_len; ++idx) { + const struct ast_rtp_mime_type *t = &ast_rtp_mime_types[idx]; struct ast_rtp_payload_type *new_type; if (strcasecmp(mimesubtype, t->subtype)) { @@ -718,27 +952,32 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs, continue; } - if (pt < AST_VECTOR_SIZE(&codecs->payloads)) { - ao2_t_cleanup(AST_VECTOR_GET(&codecs->payloads, pt), "cleaning up replaced payload type"); - } - - new_type->payload = pt; new_type->asterisk_format = t->payload_type.asterisk_format; new_type->rtp_code = t->payload_type.rtp_code; - if ((ast_format_cmp(t->payload_type.format, ast_format_g726) == AST_FORMAT_CMP_EQUAL) && - t->payload_type.asterisk_format && (options & AST_RTP_OPT_G726_NONSTANDARD)) { + new_type->payload = pt; + new_type->primary_mapping = 1; + if (t->payload_type.asterisk_format + && ast_format_cmp(t->payload_type.format, ast_format_g726) == AST_FORMAT_CMP_EQUAL + && (options & AST_RTP_OPT_G726_NONSTANDARD)) { new_type->format = ao2_bump(ast_format_g726_aal2); } else { new_type->format = ao2_bump(t->payload_type.format); } - AST_VECTOR_REPLACE(&codecs->payloads, pt, 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); } + payload_mapping_tx_remove_other_mappings(codecs, instance, new_type); break; } + ast_rwlock_unlock(&codecs->codecs_lock); ast_rwlock_unlock(&mime_types_lock); @@ -761,10 +1000,11 @@ void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp ast_debug(2, "Unsetting payload %d on %p\n", payload, codecs); ast_rwlock_wrlock(&codecs->codecs_lock); - if (payload < AST_VECTOR_SIZE(&codecs->payloads)) { - type = AST_VECTOR_GET(&codecs->payloads, payload); + + if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { + type = AST_VECTOR_GET(&codecs->payload_mapping_tx, payload); ao2_cleanup(type); - AST_VECTOR_REPLACE(&codecs->payloads, payload, NULL); + AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, NULL); } if (instance && instance->engine && instance->engine->payload_set) { @@ -783,8 +1023,8 @@ struct ast_rtp_payload_type *ast_rtp_codecs_get_payload(struct ast_rtp_codecs *c } ast_rwlock_rdlock(&codecs->codecs_lock); - if (payload < AST_VECTOR_SIZE(&codecs->payloads)) { - type = AST_VECTOR_GET(&codecs->payloads, payload); + if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_rx)) { + type = AST_VECTOR_GET(&codecs->payload_mapping_rx, payload); ao2_bump(type); } ast_rwlock_unlock(&codecs->codecs_lock); @@ -814,12 +1054,14 @@ int ast_rtp_codecs_payload_replace_format(struct ast_rtp_codecs *codecs, int pay type->format = format; type->asterisk_format = 1; type->payload = payload; + type->primary_mapping = 1; ast_rwlock_wrlock(&codecs->codecs_lock); - if (payload < AST_VECTOR_SIZE(&codecs->payloads)) { - ao2_cleanup(AST_VECTOR_GET(&codecs->payloads, payload)); + if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { + ao2_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload)); } - AST_VECTOR_REPLACE(&codecs->payloads, payload, type); + 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; @@ -835,8 +1077,8 @@ struct ast_format *ast_rtp_codecs_get_payload_format(struct ast_rtp_codecs *code } ast_rwlock_rdlock(&codecs->codecs_lock); - if (payload < AST_VECTOR_SIZE(&codecs->payloads)) { - type = AST_VECTOR_GET(&codecs->payloads, payload); + if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { + type = AST_VECTOR_GET(&codecs->payload_mapping_tx, payload); if (type && type->asterisk_format) { format = ao2_bump(type->format); } @@ -870,16 +1112,17 @@ unsigned int ast_rtp_codecs_get_framing(struct ast_rtp_codecs *codecs) void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, struct ast_format_cap *astformats, int *nonastformats) { - int i; + int idx; ast_format_cap_remove_by_type(astformats, AST_MEDIA_TYPE_UNKNOWN); *nonastformats = 0; ast_rwlock_rdlock(&codecs->codecs_lock); - for (i = 0; i < AST_VECTOR_SIZE(&codecs->payloads); i++) { + + for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_tx); ++idx) { struct ast_rtp_payload_type *type; - type = AST_VECTOR_GET(&codecs->payloads, i); + type = AST_VECTOR_GET(&codecs->payload_mapping_tx, idx); if (!type) { continue; } @@ -890,7 +1133,6 @@ void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, struct ast_fo *nonastformats |= type->rtp_code; } } - if (codecs->framing) { ast_format_cap_set_framing(astformats, codecs->framing); } @@ -898,59 +1140,161 @@ void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, struct ast_fo ast_rwlock_unlock(&codecs->codecs_lock); } +/*! + * \internal + * \brief Find the static payload type mapping for the format. + * \since 14.0.0 + * + * \param asterisk_format Non-zero if the given Asterisk format is present + * \param format Asterisk format to look for + * \param code The non-Asterisk format code to look for + * + * \retval Numerical payload type + * \retval -1 if not found. + */ +static int find_static_payload_type(int asterisk_format, const struct ast_format *format, int code) +{ + int idx; + int payload = -1; + + if (!asterisk_format) { + ast_rwlock_rdlock(&static_RTP_PT_lock); + for (idx = 0; idx < AST_RTP_MAX_PT; ++idx) { + if (static_RTP_PT[idx] + && !static_RTP_PT[idx]->asterisk_format + && static_RTP_PT[idx]->rtp_code == code) { + payload = idx; + break; + } + } + ast_rwlock_unlock(&static_RTP_PT_lock); + } else if (format) { + ast_rwlock_rdlock(&static_RTP_PT_lock); + for (idx = 0; idx < AST_RTP_MAX_PT; ++idx) { + if (static_RTP_PT[idx] + && static_RTP_PT[idx]->asterisk_format + && ast_format_cmp(format, static_RTP_PT[idx]->format) + != AST_FORMAT_CMP_NOT_EQUAL) { + payload = idx; + break; + } + } + ast_rwlock_unlock(&static_RTP_PT_lock); + } + + return payload; +} + int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code) { struct ast_rtp_payload_type *type; - int i; + int idx; int payload = -1; - ast_rwlock_rdlock(&codecs->codecs_lock); - for (i = 0; i < AST_VECTOR_SIZE(&codecs->payloads); i++) { - type = AST_VECTOR_GET(&codecs->payloads, i); - if (!type) { - continue; + if (!asterisk_format) { + ast_rwlock_rdlock(&codecs->codecs_lock); + for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_rx); ++idx) { + type = AST_VECTOR_GET(&codecs->payload_mapping_rx, idx); + if (!type) { + continue; + } + + if (!type->asterisk_format + && type->rtp_code == code) { + if (type->primary_mapping) { + payload = idx; + break; + } + if (payload == -1) { + payload = idx; + } + } } + ast_rwlock_unlock(&codecs->codecs_lock); + } else if (format) { + ast_rwlock_rdlock(&codecs->codecs_lock); + for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_rx); ++idx) { + type = AST_VECTOR_GET(&codecs->payload_mapping_rx, idx); + if (!type) { + continue; + } - if ((asterisk_format && format && ast_format_cmp(format, type->format) == AST_FORMAT_CMP_EQUAL) - || (!asterisk_format && type->rtp_code == code)) { - payload = i; - break; + if (type->asterisk_format + && ast_format_cmp(format, type->format) == AST_FORMAT_CMP_EQUAL) { + if (type->primary_mapping) { + payload = idx; + break; + } + if (payload == -1) { + payload = idx; + } + } } + ast_rwlock_unlock(&codecs->codecs_lock); } - ast_rwlock_unlock(&codecs->codecs_lock); if (payload < 0) { - ast_rwlock_rdlock(&static_RTP_PT_lock); - for (i = 0; i < AST_RTP_MAX_PT; i++) { - if (!static_RTP_PT[i]) { + payload = find_static_payload_type(asterisk_format, format, code); + } + + return payload; +} + +int ast_rtp_codecs_payload_code_tx(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code) +{ + struct ast_rtp_payload_type *type; + int idx; + int payload = -1; + + if (!asterisk_format) { + ast_rwlock_rdlock(&codecs->codecs_lock); + for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_tx); ++idx) { + type = AST_VECTOR_GET(&codecs->payload_mapping_tx, idx); + if (!type) { continue; } - if (static_RTP_PT[i]->asterisk_format && asterisk_format && format && - (ast_format_cmp(format, static_RTP_PT[i]->format) != AST_FORMAT_CMP_NOT_EQUAL)) { - payload = i; + + if (!type->asterisk_format + && type->rtp_code == code) { + payload = idx; break; - } else if (!static_RTP_PT[i]->asterisk_format && !asterisk_format && - (static_RTP_PT[i]->rtp_code == code)) { - payload = i; + } + } + ast_rwlock_unlock(&codecs->codecs_lock); + } else if (format) { + ast_rwlock_rdlock(&codecs->codecs_lock); + for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_tx); ++idx) { + type = AST_VECTOR_GET(&codecs->payload_mapping_tx, idx); + if (!type) { + continue; + } + + if (type->asterisk_format + && ast_format_cmp(format, type->format) == AST_FORMAT_CMP_EQUAL) { + payload = idx; break; } } - ast_rwlock_unlock(&static_RTP_PT_lock); + ast_rwlock_unlock(&codecs->codecs_lock); + } + + if (payload < 0) { + payload = find_static_payload_type(asterisk_format, format, code); } return payload; } -int ast_rtp_codecs_find_payload_code(struct ast_rtp_codecs *codecs, int code) +int ast_rtp_codecs_find_payload_code(struct ast_rtp_codecs *codecs, int payload) { struct ast_rtp_payload_type *type; int res = -1; ast_rwlock_rdlock(&codecs->codecs_lock); - if (code < AST_VECTOR_SIZE(&codecs->payloads)) { - type = AST_VECTOR_GET(&codecs->payloads, code); + if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { + type = AST_VECTOR_GET(&codecs->payload_mapping_tx, payload); if (type) { - res = type->payload; + res = payload; } } ast_rwlock_unlock(&codecs->codecs_lock); @@ -1192,13 +1536,13 @@ void ast_rtp_instance_early_bridge_make_compatible(struct ast_channel *c_dst, st goto done; } - ast_rtp_codecs_payloads_copy(&instance_src->codecs, &instance_dst->codecs, instance_dst); + ast_rtp_codecs_payloads_xover(&instance_src->codecs, &instance_dst->codecs, instance_dst); if (vinstance_dst && vinstance_src) { - ast_rtp_codecs_payloads_copy(&vinstance_src->codecs, &vinstance_dst->codecs, vinstance_dst); + ast_rtp_codecs_payloads_xover(&vinstance_src->codecs, &vinstance_dst->codecs, vinstance_dst); } if (tinstance_dst && tinstance_src) { - ast_rtp_codecs_payloads_copy(&tinstance_src->codecs, &tinstance_dst->codecs, tinstance_dst); + ast_rtp_codecs_payloads_xover(&tinstance_src->codecs, &tinstance_dst->codecs, tinstance_dst); } if (glue_dst->update_peer(c_dst, instance_src, vinstance_src, tinstance_src, cap_src, 0)) { @@ -1772,6 +2116,7 @@ static void add_static_payload(int map, struct ast_format *format, int rtp_code) type->rtp_code = rtp_code; } type->payload = map; + type->primary_mapping = 1; ao2_cleanup(static_RTP_PT[map]); static_RTP_PT[map] = type; } diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index cca19698c8cc7166193b5fdd299001894c9a0005..545e21634042a195cc2be6f2c6cba011625806de 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -2690,7 +2690,7 @@ static int ast_rtp_dtmf_begin(struct ast_rtp_instance *instance, char digit) } /* Grab the payload that they expect the RFC2833 packet to be received in */ - payload = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance), 0, NULL, AST_RTP_DTMF); + payload = ast_rtp_codecs_payload_code_tx(ast_rtp_instance_get_codecs(instance), 0, NULL, AST_RTP_DTMF); rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000)); rtp->send_duration = 160; @@ -3417,10 +3417,8 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr } /* Grab the subclass and look up the payload we are going to use */ - codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance), - 1, - frame->subclass.format, - 0); + codec = ast_rtp_codecs_payload_code_tx(ast_rtp_instance_get_codecs(instance), + 1, frame->subclass.format, 0); if (codec < 0) { ast_log(LOG_WARNING, "Don't know how to send format %s packets with RTP\n", ast_format_get_name(frame->subclass.format)); @@ -4206,7 +4204,8 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int } /* Otherwise adjust bridged payload to match */ - bridged_payload = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance1), payload_type->asterisk_format, payload_type->format, payload_type->rtp_code); + bridged_payload = ast_rtp_codecs_payload_code_tx(ast_rtp_instance_get_codecs(instance1), + payload_type->asterisk_format, payload_type->format, payload_type->rtp_code); /* If no codec could be matched between instance and instance1, then somehow things were made incompatible while we were still bridged. Bail. */ if (bridged_payload < 0) { @@ -5012,7 +5011,7 @@ static int ast_rtp_sendcng(struct ast_rtp_instance *instance, int level) return -1; } - payload = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance), 0, NULL, AST_RTP_CN); + payload = ast_rtp_codecs_payload_code_tx(ast_rtp_instance_get_codecs(instance), 0, NULL, AST_RTP_CN); level = 127 - (level & 0x7f); diff --git a/res/res_rtp_multicast.c b/res/res_rtp_multicast.c index 887eed229864f258be51e18d9d88b431eb1a9e75..192f3d13735f0ab92206a0e59296071565717bf2 100644 --- a/res/res_rtp_multicast.c +++ b/res/res_rtp_multicast.c @@ -247,7 +247,9 @@ static int multicast_rtp_write(struct ast_rtp_instance *instance, struct ast_fra } /* Grab the actual payload number for when we create the RTP packet */ - if ((codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance), 1, frame->subclass.format, 0)) < 0) { + codec = ast_rtp_codecs_payload_code_tx(ast_rtp_instance_get_codecs(instance), + 1, frame->subclass.format, 0); + if (codec < 0) { return -1; }