diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 32291e54c22766ae1622b95841e9cc2db884ad70..729f453f925ae8bc6a7cb862d29ba2fa92f4a128 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -223,17 +223,6 @@ static void chan_pjsip_get_codec(struct ast_channel *chan, struct ast_format_cap ast_format_cap_append_from_cap(result, channel->session->endpoint->media.codecs, AST_MEDIA_TYPE_UNKNOWN); } -static int send_direct_media_request(void *data) -{ - struct ast_sip_session *session = data; - int res; - - res = ast_sip_session_refresh(session, NULL, NULL, NULL, - session->endpoint->media.direct_media.method, 1); - ao2_ref(session, -1); - return res; -} - /*! \brief Destructor function for \ref transport_info_data */ static void transport_info_destroy(void *obj) { @@ -302,6 +291,83 @@ static int check_for_rtp_changes(struct ast_channel *chan, struct ast_rtp_instan return changed; } +struct rtp_direct_media_data { + struct ast_channel *chan; + struct ast_rtp_instance *rtp; + struct ast_rtp_instance *vrtp; + struct ast_format_cap *cap; + struct ast_sip_session *session; +}; + +static void rtp_direct_media_data_destroy(void *data) +{ + struct rtp_direct_media_data *cdata = data; + + ao2_cleanup(cdata->session); + ao2_cleanup(cdata->cap); + ao2_cleanup(cdata->vrtp); + ao2_cleanup(cdata->rtp); + ao2_cleanup(cdata->chan); +} + +static struct rtp_direct_media_data *rtp_direct_media_data_create( + struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, + const struct ast_format_cap *cap, struct ast_sip_session *session) +{ + struct rtp_direct_media_data *cdata = ao2_alloc(sizeof(*cdata), rtp_direct_media_data_destroy); + + if (!cdata) { + return NULL; + } + + cdata->chan = ao2_bump(chan); + cdata->rtp = ao2_bump(rtp); + cdata->vrtp = ao2_bump(vrtp); + cdata->cap = ao2_bump((struct ast_format_cap *)cap); + cdata->session = ao2_bump(session); + + return cdata; +} + +static int send_direct_media_request(void *data) +{ + struct rtp_direct_media_data *cdata = data; + struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(cdata->chan); + struct chan_pjsip_pvt *pvt = channel->pvt; + int changed = 0; + int res = 0; + + if (pvt->media[SIP_MEDIA_AUDIO]) { + changed |= check_for_rtp_changes( + cdata->chan, cdata->rtp, pvt->media[SIP_MEDIA_AUDIO], 1); + } + if (pvt->media[SIP_MEDIA_VIDEO]) { + changed |= check_for_rtp_changes( + cdata->chan, cdata->vrtp, pvt->media[SIP_MEDIA_VIDEO], 3); + } + + if (direct_media_mitigate_glare(cdata->session)) { + ast_debug(4, "Disregarding setting RTP on %s: mitigating re-INVITE glare\n", ast_channel_name(cdata->chan)); + return 0; + } + + if (cdata->cap && ast_format_cap_count(cdata->cap) && + !ast_format_cap_identical(cdata->session->direct_media_cap, cdata->cap)) { + ast_format_cap_remove_by_type(cdata->session->direct_media_cap, AST_MEDIA_TYPE_UNKNOWN); + ast_format_cap_append_from_cap(cdata->session->direct_media_cap, cdata->cap, AST_MEDIA_TYPE_UNKNOWN); + changed = 1; + } + + if (changed) { + ast_debug(4, "RTP changed on %s; initiating direct media update\n", ast_channel_name(cdata->chan)); + res = ast_sip_session_refresh(cdata->session, NULL, NULL, NULL, + cdata->session->endpoint->media.direct_media.method, 1); + } + + ao2_ref(cdata, -1); + return res; +} + /*! \brief Function called by RTP engine to change where the remote party should send media */ static int chan_pjsip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, @@ -311,9 +377,8 @@ static int chan_pjsip_set_rtp_peer(struct ast_channel *chan, int nat_active) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan); - struct chan_pjsip_pvt *pvt = channel->pvt; struct ast_sip_session *session = channel->session; - int changed = 0; + struct rtp_direct_media_data *cdata; /* Don't try to do any direct media shenanigans on early bridges */ if ((rtp || vrtp || tpeer) && !ast_channel_is_bridged(chan)) { @@ -326,31 +391,14 @@ static int chan_pjsip_set_rtp_peer(struct ast_channel *chan, return 0; } - if (pvt->media[SIP_MEDIA_AUDIO]) { - changed |= check_for_rtp_changes(chan, rtp, pvt->media[SIP_MEDIA_AUDIO], 1); - } - if (pvt->media[SIP_MEDIA_VIDEO]) { - changed |= check_for_rtp_changes(chan, vrtp, pvt->media[SIP_MEDIA_VIDEO], 3); - } - - if (direct_media_mitigate_glare(session)) { - ast_debug(4, "Disregarding setting RTP on %s: mitigating re-INVITE glare\n", ast_channel_name(chan)); + cdata = rtp_direct_media_data_create(chan, rtp, vrtp, cap, session); + if (!cdata) { return 0; } - if (cap && ast_format_cap_count(cap) && !ast_format_cap_identical(session->direct_media_cap, cap)) { - ast_format_cap_remove_by_type(session->direct_media_cap, AST_MEDIA_TYPE_UNKNOWN); - ast_format_cap_append_from_cap(session->direct_media_cap, cap, AST_MEDIA_TYPE_UNKNOWN); - changed = 1; - } - - if (changed) { - ao2_ref(session, +1); - - ast_debug(4, "RTP changed on %s; initiating direct media update\n", ast_channel_name(chan)); - if (ast_sip_push_task(session->serializer, send_direct_media_request, session)) { - ao2_cleanup(session); - } + if (ast_sip_push_task(session->serializer, send_direct_media_request, cdata)) { + ast_log(LOG_ERROR, "Unable to send direct media request for channel %s\n", ast_channel_name(chan)); + ao2_ref(cdata, -1); } return 0;