Reduce memory consumption significantly for users of the RTP engine API by storing...
authorJoshua Colp <jcolp@digium.com>
Tue, 7 Aug 2012 13:07:58 +0000 (13:07 +0000)
committerJoshua Colp <jcolp@digium.com>
Tue, 7 Aug 2012 13:07:58 +0000 (13:07 +0000)
Review: https://reviewboard.asterisk.org/r/2052/

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370832 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_motif.c
channels/chan_sip.c
include/asterisk/rtp_engine.h
main/rtp_engine.c
res/res_rtp_asterisk.c

index 52d15d0..8c4c11a 100644 (file)
@@ -1869,7 +1869,11 @@ static int jingle_interpret_description(struct jingle_session *session, iks *des
                return -1;
        }
 
-       ast_rtp_codecs_payloads_clear(&codecs, NULL);
+       if (ast_rtp_codecs_payloads_initialize(&codecs)) {
+               jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
+               ast_log(LOG_ERROR, "Could not initialize codecs for negotiation on session '%s'\n", session->sid);
+               return -1;
+       }
 
        /* Iterate the codecs updating the relevant RTP instance as we go */
        for (codec = iks_child(description); codec; codec = iks_next(codec)) {
@@ -1894,10 +1898,12 @@ static int jingle_interpret_description(struct jingle_session *session, iks *des
        if (ast_format_cap_is_empty(session->jointcap)) {
                /* We have no compatible codecs, so terminate the session appropriately */
                jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
+               ast_rtp_codecs_payloads_destroy(&codecs);
                return -1;
        }
 
        ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(*rtp), *rtp);
+       ast_rtp_codecs_payloads_destroy(&codecs);
 
        return 0;
 }
index b002254..b65390a 100644 (file)
@@ -9450,7 +9450,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 
        int peernoncodeccapability = 0, vpeernoncodeccapability = 0, tpeernoncodeccapability = 0;
 
-       struct ast_rtp_codecs *newaudiortp = NULL, *newvideortp = NULL, *newtextrtp = NULL;
+       struct ast_rtp_codecs newaudiortp = { 0, }, newvideortp = { 0, }, newtextrtp = { 0, };
        struct ast_format_cap *newjointcapability = ast_format_cap_alloc_nolock(); /* Negotiated capability */
        struct ast_format_cap *newpeercapability = ast_format_cap_alloc_nolock();
        int newnoncodeccapability;
@@ -9487,8 +9487,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                goto process_sdp_cleanup;
        }
 
-       if (!(newaudiortp = ast_calloc(1, sizeof(*newaudiortp))) || !(newvideortp = ast_calloc(1, sizeof(*newvideortp))) ||
-           !(newtextrtp = ast_calloc(1, sizeof(*newtextrtp)))) {
+       if (ast_rtp_codecs_payloads_initialize(&newaudiortp) || ast_rtp_codecs_payloads_initialize(&newvideortp) ||
+           ast_rtp_codecs_payloads_initialize(&newtextrtp)) {
                res = -1;
                goto process_sdp_cleanup;
        }
@@ -9532,11 +9532,11 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                        if (process_sdp_a_sendonly(value, &sendonly)) {
                                processed = TRUE;
                        }
-                       else if (process_sdp_a_audio(value, p, newaudiortp, &last_rtpmap_codec))
+                       else if (process_sdp_a_audio(value, p, &newaudiortp, &last_rtpmap_codec))
                                processed = TRUE;
-                       else if (process_sdp_a_video(value, p, newvideortp, &last_rtpmap_codec))
+                       else if (process_sdp_a_video(value, p, &newvideortp, &last_rtpmap_codec))
                                processed = TRUE;
-                       else if (process_sdp_a_text(value, p, newtextrtp, red_fmtp, &red_num_gen, red_data_pt, &last_rtpmap_codec))
+                       else if (process_sdp_a_text(value, p, &newtextrtp, red_fmtp, &red_num_gen, red_data_pt, &last_rtpmap_codec))
                                processed = TRUE;
                        else if (process_sdp_a_image(value, p))
                                processed = TRUE;
@@ -9650,7 +9650,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                                                ast_verbose("Found RTP audio format %d\n", codec);
                                        }
 
-                                       ast_rtp_codecs_payloads_set_m_type(newaudiortp, NULL, codec);
+                                       ast_rtp_codecs_payloads_set_m_type(&newaudiortp, NULL, codec);
                                }
                        } else {
                                ast_log(LOG_WARNING, "Rejecting audio media offer due to invalid or unsupported syntax: %s\n", m);
@@ -9722,7 +9722,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                                        if (debug) {
                                                ast_verbose("Found RTP video format %d\n", codec);
                                        }
-                                       ast_rtp_codecs_payloads_set_m_type(newvideortp, NULL, codec);
+                                       ast_rtp_codecs_payloads_set_m_type(&newvideortp, NULL, codec);
                                }
                        } else {
                                ast_log(LOG_WARNING, "Rejecting video media offer due to invalid or unsupported syntax: %s\n", m);
@@ -9786,7 +9786,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                                        if (debug) {
                                                ast_verbose("Found RTP text format %d\n", codec);
                                        }
-                                       ast_rtp_codecs_payloads_set_m_type(newtextrtp, NULL, codec);
+                                       ast_rtp_codecs_payloads_set_m_type(&newtextrtp, NULL, codec);
                                }
                        } else {
                                ast_log(LOG_WARNING, "Rejecting text stream offer due to invalid or unsupported syntax: %s\n", m);
@@ -9904,7 +9904,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                                        } else if (!processed_crypto && process_crypto(p, p->rtp, &p->srtp, value)) {
                                                processed_crypto = TRUE;
                                                processed = TRUE;
-                                       } else if (process_sdp_a_audio(value, p, newaudiortp, &last_rtpmap_codec)) {
+                                       } else if (process_sdp_a_audio(value, p, &newaudiortp, &last_rtpmap_codec)) {
                                                processed = TRUE;
                                        }
                                }
@@ -9915,7 +9915,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                                        } else if (!processed_crypto && process_crypto(p, p->vrtp, &p->vsrtp, value)) {
                                                processed_crypto = TRUE;
                                                processed = TRUE;
-                                       } else if (process_sdp_a_video(value, p, newvideortp, &last_rtpmap_codec)) {
+                                       } else if (process_sdp_a_video(value, p, &newvideortp, &last_rtpmap_codec)) {
                                                processed = TRUE;
                                        }
                                }
@@ -9923,7 +9923,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                                else if (text) {
                                        if (process_sdp_a_ice(value, p, p->trtp)) {
                                                processed = TRUE;
-                                       } if (process_sdp_a_text(value, p, newtextrtp, red_fmtp, &red_num_gen, red_data_pt, &last_rtpmap_codec)) {
+                                       } if (process_sdp_a_text(value, p, &newtextrtp, red_fmtp, &red_num_gen, red_data_pt, &last_rtpmap_codec)) {
                                                processed = TRUE;
                                        } else if (!processed_crypto && process_crypto(p, p->trtp, &p->tsrtp, value)) {
                                                processed_crypto = TRUE;
@@ -9996,9 +9996,9 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
        }
 
        /* Now gather all of the codecs that we are asked for: */
-       ast_rtp_codecs_payload_formats(newaudiortp, peercapability, &peernoncodeccapability);
-       ast_rtp_codecs_payload_formats(newvideortp, vpeercapability, &vpeernoncodeccapability);
-       ast_rtp_codecs_payload_formats(newtextrtp, tpeercapability, &tpeernoncodeccapability);
+       ast_rtp_codecs_payload_formats(&newaudiortp, peercapability, &peernoncodeccapability);
+       ast_rtp_codecs_payload_formats(&newvideortp, vpeercapability, &vpeernoncodeccapability);
+       ast_rtp_codecs_payload_formats(&newtextrtp, tpeercapability, &tpeernoncodeccapability);
 
        ast_format_cap_append(newpeercapability, peercapability);
        ast_format_cap_append(newpeercapability, vpeercapability);
@@ -10061,7 +10061,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                                            ast_sockaddr_stringify(sa));
                        }
 
-                       ast_rtp_codecs_payloads_copy(newaudiortp, ast_rtp_instance_get_codecs(p->rtp), p->rtp);
+                       ast_rtp_codecs_payloads_copy(&newaudiortp, ast_rtp_instance_get_codecs(p->rtp), p->rtp);
                        /* Ensure RTCP is enabled since it may be inactive
                           if we're coming back from a T.38 session */
                        ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_RTCP, 1);
@@ -10108,7 +10108,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                                ast_verbose("Peer video RTP is at port %s\n",
                                            ast_sockaddr_stringify(vsa));
                        }
-                       ast_rtp_codecs_payloads_copy(newvideortp, ast_rtp_instance_get_codecs(p->vrtp), p->vrtp);
+                       ast_rtp_codecs_payloads_copy(&newvideortp, ast_rtp_instance_get_codecs(p->vrtp), p->vrtp);
                } else {
                        ast_rtp_instance_stop(p->vrtp);
                        if (debug)
@@ -10132,7 +10132,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                        } else {
                                p->red = 0;
                        }
-                       ast_rtp_codecs_payloads_copy(newtextrtp, ast_rtp_instance_get_codecs(p->trtp), p->trtp);
+                       ast_rtp_codecs_payloads_copy(&newtextrtp, ast_rtp_instance_get_codecs(p->trtp), p->trtp);
                } else {
                        ast_rtp_instance_stop(p->trtp);
                        if (debug)
@@ -10250,15 +10250,9 @@ process_sdp_cleanup:
        if (res) {
                offered_media_list_destroy(p);
        }
-       if (newtextrtp) {
-               ast_free(newtextrtp);
-       }
-       if (newvideortp) {
-               ast_free(newvideortp);
-       }
-       if (newaudiortp) {
-               ast_free(newaudiortp);
-       }
+       ast_rtp_codecs_payloads_destroy(&newtextrtp);
+       ast_rtp_codecs_payloads_destroy(&newvideortp);
+       ast_rtp_codecs_payloads_destroy(&newaudiortp);
        ast_format_cap_destroy(peercapability);
        ast_format_cap_destroy(vpeercapability);
        ast_format_cap_destroy(tpeercapability);
index bd47e42..dad2a60 100644 (file)
@@ -431,10 +431,10 @@ struct ast_rtp_engine {
 
 /*! Structure that represents codec and packetization information */
 struct ast_rtp_codecs {
+       /*! Payloads present */
+       struct ao2_container *payloads;
        /*! Codec packetization preferences */
        struct ast_codec_pref pref;
-       /*! Payloads present */
-       struct ast_rtp_payload_type payloads[AST_RTP_MAX_PT];
 };
 
 /*! Structure that represents the glue that binds an RTP instance to a channel */
@@ -945,6 +945,41 @@ int ast_rtp_instance_get_prop(struct ast_rtp_instance *instance, enum ast_rtp_pr
 struct ast_rtp_codecs *ast_rtp_instance_get_codecs(struct ast_rtp_instance *instance);
 
 /*!
+ * \brief Initialize an RTP codecs structure
+ *
+ * \param codecs The codecs structure to initialize
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ *
+ * Example usage:
+ *
+ * \code
+ * struct ast_rtp_codecs codecs;
+ * ast_rtp_codecs_payloads_initialize(&codecs);
+ * \endcode
+ *
+ * \since 11
+ */
+int ast_rtp_codecs_payloads_initialize(struct ast_rtp_codecs *codecs);
+
+/*!
+ * \brief Destroy the contents of an RTP codecs structure (but not the structure itself)
+ *
+ * \param codecs The codecs structure to destroy the contents of
+ *
+ * Example usage:
+ *
+ * \code
+ * struct ast_rtp_codecs codecs;
+ * ast_rtp_codecs_payloads_destroy(&codecs);
+ * \endcode
+ *
+ * \since 11
+ */
+void ast_rtp_codecs_payloads_destroy(struct ast_rtp_codecs *codecs);
+
+/*!
  * \brief Clear payload information from an RTP instance
  *
  * \param codecs The codecs structure that payloads will be cleared from
index 68cdfd3..46b75be 100644 (file)
@@ -218,6 +218,8 @@ static void instance_destructor(void *obj)
                res_srtp->destroy(instance->srtp);
        }
 
+       ast_rtp_codecs_payloads_destroy(&instance->codecs);
+
        /* Drop our engine reference */
        ast_module_unref(instance->engine->mod);
 
@@ -273,6 +275,11 @@ struct ast_rtp_instance *ast_rtp_instance_new(const char *engine_name,
        ast_sockaddr_copy(&instance->local_address, sa);
        ast_sockaddr_copy(&address, sa);
 
+       if (ast_rtp_codecs_payloads_initialize(&instance->codecs)) {
+               ao2_ref(instance, -1);
+               return NULL;
+       }
+
        ast_debug(1, "Using engine '%s' for RTP instance '%p'\n", engine->name, instance);
 
        /* And pass it off to the engine to setup */
@@ -411,18 +418,48 @@ struct ast_rtp_codecs *ast_rtp_instance_get_codecs(struct ast_rtp_instance *inst
        return &instance->codecs;
 }
 
+static int rtp_payload_type_hash(const void *obj, const int flags)
+{
+       const struct ast_rtp_payload_type *type = obj;
+       const int *rtp_code = obj;
+
+       return (flags & OBJ_KEY) ? *rtp_code : type->rtp_code;
+}
+
+static int rtp_payload_type_cmp(void *obj, void *arg, int flags)
+{
+       struct ast_rtp_payload_type *type1 = obj, *type2 = arg;
+       const int *rtp_code = arg;
+
+       return (type1->rtp_code == (OBJ_KEY ? *rtp_code : type2->rtp_code)) ? CMP_MATCH | CMP_STOP : 0;
+}
+
+int ast_rtp_codecs_payloads_initialize(struct ast_rtp_codecs *codecs)
+{
+       if (!(codecs->payloads = ao2_container_alloc(AST_RTP_MAX_PT, rtp_payload_type_hash, rtp_payload_type_cmp))) {
+               return -1;
+       }
+
+       return 0;
+}
+
+void ast_rtp_codecs_payloads_destroy(struct ast_rtp_codecs *codecs)
+{
+       ao2_cleanup(codecs->payloads);
+}
+
 void ast_rtp_codecs_payloads_clear(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance)
 {
-       int i;
+       ast_rtp_codecs_payloads_destroy(codecs);
 
-       for (i = 0; i < AST_RTP_MAX_PT; i++) {
-               codecs->payloads[i].asterisk_format = 0;
-               codecs->payloads[i].rtp_code = 0;
-               ast_format_clear(&codecs->payloads[i].format);
-               if (instance && instance->engine && instance->engine->payload_set) {
+       if (instance && instance->engine && instance->engine->payload_set) {
+               int i;
+               for (i = 0; i < AST_RTP_MAX_PT; i++) {
                        instance->engine->payload_set(instance, i, 0, NULL, 0);
                }
        }
+
+       ast_rtp_codecs_payloads_initialize(codecs);
 }
 
 void ast_rtp_codecs_payloads_default(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance)
@@ -432,13 +469,27 @@ void ast_rtp_codecs_payloads_default(struct ast_rtp_codecs *codecs, struct ast_r
        ast_rwlock_rdlock(&static_RTP_PT_lock);
        for (i = 0; i < AST_RTP_MAX_PT; i++) {
                if (static_RTP_PT[i].rtp_code || static_RTP_PT[i].asterisk_format) {
+                       struct ast_rtp_payload_type *type;
+
+                       if (!(type = ao2_alloc(sizeof(*type), NULL))) {
+                               /* Unfortunately if this occurs the payloads container will not contain all possible default payloads
+                                * but we err on the side of doing what we can in the hopes that the extreme memory conditions which
+                                * caused this to occur will go away.
+                                */
+                               continue;
+                       }
+
+                       type->asterisk_format = static_RTP_PT[i].asterisk_format;
+                       type->rtp_code = static_RTP_PT[i].rtp_code;
+                       ast_format_copy(&type->format, &static_RTP_PT[i].format);
+
+                       ao2_link_flags(codecs->payloads, type, OBJ_NOLOCK);
 
-                       codecs->payloads[i].asterisk_format = static_RTP_PT[i].asterisk_format;
-                       codecs->payloads[i].rtp_code = static_RTP_PT[i].rtp_code;
-                       ast_format_copy(&codecs->payloads[i].format, &static_RTP_PT[i].format);
                        if (instance && instance->engine && instance->engine->payload_set) {
-                               instance->engine->payload_set(instance, i, codecs->payloads[i].asterisk_format, &codecs->payloads[i].format, codecs->payloads[i].rtp_code);
+                               instance->engine->payload_set(instance, i, type->asterisk_format, &type->format, type->rtp_code);
                        }
+
+                       ao2_ref(type, -1);
                }
        }
        ast_rwlock_unlock(&static_RTP_PT_lock);
@@ -447,38 +498,57 @@ void ast_rtp_codecs_payloads_default(struct ast_rtp_codecs *codecs, struct ast_r
 void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance)
 {
        int i;
+       struct ast_rtp_payload_type *type;
 
        for (i = 0; i < AST_RTP_MAX_PT; i++) {
-               if (src->payloads[i].rtp_code || src->payloads[i].asterisk_format) {
-                       ast_debug(2, "Copying payload %d from %p to %p\n", i, src, dest);
-                       dest->payloads[i].asterisk_format = src->payloads[i].asterisk_format;
-                       dest->payloads[i].rtp_code = src->payloads[i].rtp_code;
-                       ast_format_copy(&dest->payloads[i].format, &src->payloads[i].format);
-                       if (instance && instance->engine && instance->engine->payload_set) {
-                               instance->engine->payload_set(instance, i, dest->payloads[i].asterisk_format, &dest->payloads[i].format, dest->payloads[i].rtp_code);
-                       }
+               struct ast_rtp_payload_type *new_type;
+
+               if (!(type = ao2_find(src->payloads, &i, OBJ_KEY | OBJ_NOLOCK))) {
+                       continue;
+               }
+
+               if (!(new_type = ao2_alloc(sizeof(*new_type), NULL))) {
+                       continue;
                }
+
+               ast_debug(2, "Copying payload %d from %p to %p\n", i, src, dest);
+
+               *new_type = *type;
+
+               ao2_link_flags(dest->payloads, new_type, OBJ_NOLOCK);
+
+               ao2_ref(new_type, -1);
+
+               if (instance && instance->engine && instance->engine->payload_set) {
+                       instance->engine->payload_set(instance, i, type->asterisk_format, &type->format, type->rtp_code);
+               }
+
+               ao2_ref(type, -1);
        }
 }
 
 void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload)
 {
+       struct ast_rtp_payload_type *type;
 
        ast_rwlock_rdlock(&static_RTP_PT_lock);
-       if (payload < 0 || payload >= AST_RTP_MAX_PT || (!static_RTP_PT[payload].rtp_code && !static_RTP_PT[payload].asterisk_format)) {
+       if (payload < 0 || payload >= AST_RTP_MAX_PT || !(type = ao2_find(codecs->payloads, &payload, OBJ_KEY | OBJ_NOLOCK))) {
                ast_rwlock_unlock(&static_RTP_PT_lock);
                return;
        }
 
-       codecs->payloads[payload].asterisk_format = static_RTP_PT[payload].asterisk_format;
-       codecs->payloads[payload].rtp_code = static_RTP_PT[payload].rtp_code;
-       ast_format_copy(&codecs->payloads[payload].format, &static_RTP_PT[payload].format);
+       type->asterisk_format = static_RTP_PT[payload].asterisk_format;
+       type->rtp_code = static_RTP_PT[payload].rtp_code;
+       ast_format_copy(&type->format, &static_RTP_PT[payload].format);
 
        ast_debug(1, "Setting payload %d based on m type on %p\n", payload, codecs);
 
        if (instance && instance->engine && instance->engine->payload_set) {
-               instance->engine->payload_set(instance, payload, codecs->payloads[payload].asterisk_format, &codecs->payloads[payload].format, codecs->payloads[payload].rtp_code);
+               instance->engine->payload_set(instance, payload, type->asterisk_format, &type->format, type->rtp_code);
        }
+
+       ao2_ref(type, -1);
+
        ast_rwlock_unlock(&static_RTP_PT_lock);
 }
 
@@ -496,6 +566,7 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs,
        ast_rwlock_rdlock(&mime_types_lock);
        for (i = 0; i < mime_types_len; ++i) {
                const struct ast_rtp_mime_type *t = &ast_rtp_mime_types[i];
+               struct ast_rtp_payload_type *type;
 
                if (strcasecmp(mimesubtype, t->subtype)) {
                        continue;
@@ -514,16 +585,26 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs,
                }
 
                found = 1;
-               codecs->payloads[pt] = t->payload_type;
+
+               if (!(type = ao2_find(codecs->payloads, &pt, OBJ_KEY | OBJ_NOLOCK))) {
+                       if (!(type = ao2_alloc(sizeof(*type), NULL))) {
+                               continue;
+                       }
+                       ao2_link_flags(codecs->payloads, type, OBJ_NOLOCK);
+               }
+
+               *type = t->payload_type;
 
                if ((t->payload_type.format.id == AST_FORMAT_G726) && t->payload_type.asterisk_format && (options & AST_RTP_OPT_G726_NONSTANDARD)) {
-                       ast_format_set(&codecs->payloads[pt].format, AST_FORMAT_G726_AAL2, 0);
+                       ast_format_set(&type->format, AST_FORMAT_G726_AAL2, 0);
                }
 
                if (instance && instance->engine && instance->engine->payload_set) {
-                       instance->engine->payload_set(instance, pt, codecs->payloads[i].asterisk_format, &codecs->payloads[i].format, codecs->payloads[i].rtp_code);
+                       instance->engine->payload_set(instance, pt, type->asterisk_format, &type->format, type->rtp_code);
                }
 
+               ao2_ref(type, -1);
+
                break;
        }
        ast_rwlock_unlock(&mime_types_lock);
@@ -544,9 +625,7 @@ 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);
 
-       codecs->payloads[payload].asterisk_format = 0;
-       codecs->payloads[payload].rtp_code = 0;
-       ast_format_clear(&codecs->payloads[payload].format);
+       ao2_find(codecs->payloads, &payload, OBJ_KEY | OBJ_NOLOCK | OBJ_NODATA | OBJ_UNLINK);
 
        if (instance && instance->engine && instance->engine->payload_set) {
                instance->engine->payload_set(instance, payload, 0, NULL, 0);
@@ -555,15 +634,16 @@ void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp
 
 struct ast_rtp_payload_type ast_rtp_codecs_payload_lookup(struct ast_rtp_codecs *codecs, int payload)
 {
-       struct ast_rtp_payload_type result = { .asterisk_format = 0, };
+       struct ast_rtp_payload_type result = { .asterisk_format = 0, }, *type;
 
        if (payload < 0 || payload >= AST_RTP_MAX_PT) {
                return result;
        }
 
-       result.asterisk_format = codecs->payloads[payload].asterisk_format;
-       result.rtp_code = codecs->payloads[payload].rtp_code;
-       ast_format_copy(&result.format, &codecs->payloads[payload].format);
+       if ((type = ao2_find(codecs->payloads, &payload, OBJ_KEY | OBJ_NOLOCK))) {
+               result = *type;
+               ao2_ref(type, -1);
+       }
 
        if (!result.rtp_code && !result.asterisk_format) {
                ast_rwlock_rdlock(&static_RTP_PT_lock);
@@ -577,46 +657,78 @@ struct ast_rtp_payload_type ast_rtp_codecs_payload_lookup(struct ast_rtp_codecs
 
 struct ast_format *ast_rtp_codecs_get_payload_format(struct ast_rtp_codecs *codecs, int payload)
 {
+       struct ast_rtp_payload_type *type;
+       struct ast_format *format;
+
        if (payload < 0 || payload >= AST_RTP_MAX_PT) {
                return NULL;
        }
-       if (!codecs->payloads[payload].asterisk_format) {
+
+       if (!(type = ao2_find(codecs->payloads, &payload, OBJ_KEY | OBJ_NOLOCK))) {
                return NULL;
        }
-       return &codecs->payloads[payload].format;
+
+       format = type->asterisk_format ? &type->format : NULL;
+
+       ao2_ref(type, -1);
+
+       return format;
 }
 
-void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, struct ast_format_cap *astformats, int *nonastformats)
+static int rtp_payload_type_add_ast(void *obj, void *arg, int flags)
 {
-       int i;
+       struct ast_rtp_payload_type *type = obj;
+       struct ast_format_cap *astformats = arg;
+
+       if (type->asterisk_format) {
+               ast_format_cap_add(astformats, &type->format);
+       }
+
+       return 0;
+}
 
+static int rtp_payload_type_add_nonast(void *obj, void *arg, int flags)
+{
+       struct ast_rtp_payload_type *type = obj;
+       int *nonastformats = arg;
+
+       if (!type->asterisk_format) {
+               *nonastformats |= type->rtp_code;
+       }
+
+       return 0;
+}
+
+void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, struct ast_format_cap *astformats, int *nonastformats)
+{
        ast_format_cap_remove_all(astformats);
        *nonastformats = 0;
 
-       for (i = 0; i < AST_RTP_MAX_PT; i++) {
-               if (codecs->payloads[i].rtp_code || codecs->payloads[i].asterisk_format) {
-                       ast_debug(1, "Incorporating payload %d on %p\n", i, codecs);
-               }
-               if (codecs->payloads[i].asterisk_format) {
-                       ast_format_cap_add(astformats, &codecs->payloads[i].format);
-               } else {
-                       *nonastformats |= codecs->payloads[i].rtp_code;
-               }
-       }
+       ao2_callback(codecs->payloads, OBJ_NODATA | OBJ_MULTIPLE | OBJ_NOLOCK, rtp_payload_type_add_ast, astformats);
+       ao2_callback(codecs->payloads, OBJ_NODATA | OBJ_MULTIPLE | OBJ_NOLOCK, rtp_payload_type_add_nonast, nonastformats);
+}
+
+static int rtp_payload_type_find_format(void *obj, void *arg, int flags)
+{
+       struct ast_rtp_payload_type *type = obj;
+       struct ast_format *format = arg;
+
+       return (type->asterisk_format && (ast_format_cmp(&type->format, format) != AST_FORMAT_CMP_NOT_EQUAL)) ? CMP_MATCH | CMP_STOP : 0;
 }
 
 int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code)
 {
-       int i;
-       int res = -1;
-       for (i = 0; i < AST_RTP_MAX_PT; i++) {
-               if (codecs->payloads[i].asterisk_format && asterisk_format && format &&
-                       (ast_format_cmp(format, &codecs->payloads[i].format) != AST_FORMAT_CMP_NOT_EQUAL)) {
-                       return i;
-               } else if (!codecs->payloads[i].asterisk_format && !asterisk_format &&
-                       (codecs->payloads[i].rtp_code == code)) {
-                       return i;
-               }
+       struct ast_rtp_payload_type *type;
+       int i, res = -1;
+
+       if (asterisk_format && format && (type = ao2_callback(codecs->payloads, OBJ_NOLOCK, rtp_payload_type_find_format, (void*)format))) {
+               res = type->rtp_code;
+               ao2_ref(type, -1);
+               return res;
+       } else if (!asterisk_format && (type = ao2_find(codecs->payloads, &code, OBJ_NOLOCK | OBJ_KEY))) {
+               res = type->rtp_code;
+               ao2_ref(type, -1);
+               return res;
        }
 
        ast_rwlock_rdlock(&static_RTP_PT_lock);
index 97e63b4..bdb4a25 100644 (file)
@@ -2774,8 +2774,8 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int
        }
 
        /* If the payload coming in is not one of the negotiated ones then send it to the core, this will cause formats to change and the bridge to break */
-       if (!(ast_rtp_instance_get_codecs(instance1)->payloads[bridged_payload].rtp_code) &&
-       !(ast_rtp_instance_get_codecs(instance1)->payloads[bridged_payload].asterisk_format)) {
+       if (!ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance1), 0, NULL, bridged_payload) &&
+           !ast_rtp_codecs_get_payload_format(ast_rtp_instance_get_codecs(instance1), bridged_payload)) {
                return -1;
        }