diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 48741f8bb50cbcb9aec3c7140d9d37f3dccd4455..22b0f41c9a25061c80b152c03dfea03629b55fc4 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -2789,56 +2789,6 @@ static pj_bool_t session_reinvite_on_rx_request(pjsip_rx_data *rdata) } if (!sdp_info->sdp) { - const pjmedia_sdp_session *local; - int i; - - ast_queue_unhold(session->channel); - - pjmedia_sdp_neg_get_active_local(session->inv_session->neg, &local); - if (!local) { - return PJ_FALSE; - } - - /* - * Some devices indicate hold with deferred SDP reinvites (i.e. no SDP in the reinvite). - * When hold is initially indicated, we - * - Receive an INVITE with no SDP - * - Send a 200 OK with SDP, indicating sendrecv in the media streams - * - Receive an ACK with SDP, indicating sendonly in the media streams - * - * At this point, the pjmedia negotiator saves the state of the media direction so that - * if we are to send any offers, we'll offer recvonly in the media streams. This is - * problematic if the device is attempting to unhold, though. If the device unholds - * by sending a reinvite with no SDP, then we will respond with a 200 OK with recvonly. - * According to RFC 3264, if an offerer offers recvonly, then the answerer MUST respond - * with sendonly or inactive. The result of this is that the stream is not off hold. - * - * Therefore, in this case, when we receive a reinvite while the stream is on hold, we - * need to be sure to offer sendrecv. This way, the answerer can respond with sendrecv - * in order to get the stream off hold. If this is actually a different purpose reinvite - * (like a session timer refresh), then the answerer can respond to our sendrecv with - * sendonly, keeping the stream on hold. - */ - for (i = 0; i < local->media_count; ++i) { - pjmedia_sdp_media *m = local->media[i]; - pjmedia_sdp_attr *recvonly; - pjmedia_sdp_attr *inactive; - pjmedia_sdp_attr *sendonly; - - recvonly = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "recvonly", NULL); - inactive = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "inactive", NULL); - sendonly = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "sendonly", NULL); - if (recvonly || inactive || sendonly) { - pjmedia_sdp_attr *to_remove = recvonly ?: inactive ?: sendonly; - pjmedia_sdp_attr *sendrecv; - - pjmedia_sdp_attr_remove(&m->attr_count, m->attr, to_remove); - - sendrecv = pjmedia_sdp_attr_create(session->inv_session->pool, "sendrecv", NULL); - pjmedia_sdp_media_add_attr(m, sendrecv); - } - } - return PJ_FALSE; } @@ -5288,12 +5238,70 @@ static void session_inv_on_rx_offer(pjsip_inv_session *inv, const pjmedia_sdp_se SCOPE_EXIT_RTN("%s: create_local_sdp failed\n", ast_sip_session_get_name(session)); } -#if 0 static void session_inv_on_create_offer(pjsip_inv_session *inv, pjmedia_sdp_session **p_offer) { - /* XXX STUB */ + struct ast_sip_session *session = inv->mod_data[session_module.id]; + const pjmedia_sdp_session *previous_sdp = NULL; + pjmedia_sdp_session *offer; + int i; + + if (inv->neg) { + if (pjmedia_sdp_neg_was_answer_remote(inv->neg)) { + pjmedia_sdp_neg_get_active_remote(inv->neg, &previous_sdp); + } else { + pjmedia_sdp_neg_get_active_local(inv->neg, &previous_sdp); + } + } + + offer = create_local_sdp(inv, session, previous_sdp); + if (!offer) { + return; + } + + ast_queue_unhold(session->channel); + + /* + * Some devices indicate hold with deferred SDP reinvites (i.e. no SDP in the reinvite). + * When hold is initially indicated, we + * - Receive an INVITE with no SDP + * - Send a 200 OK with SDP, indicating sendrecv in the media streams + * - Receive an ACK with SDP, indicating sendonly in the media streams + * + * At this point, the pjmedia negotiator saves the state of the media direction so that + * if we are to send any offers, we'll offer recvonly in the media streams. This is + * problematic if the device is attempting to unhold, though. If the device unholds + * by sending a reinvite with no SDP, then we will respond with a 200 OK with recvonly. + * According to RFC 3264, if an offerer offers recvonly, then the answerer MUST respond + * with sendonly or inactive. The result of this is that the stream is not off hold. + * + * Therefore, in this case, when we receive a reinvite while the stream is on hold, we + * need to be sure to offer sendrecv. This way, the answerer can respond with sendrecv + * in order to get the stream off hold. If this is actually a different purpose reinvite + * (like a session timer refresh), then the answerer can respond to our sendrecv with + * sendonly, keeping the stream on hold. + */ + for (i = 0; i < offer->media_count; ++i) { + pjmedia_sdp_media *m = offer->media[i]; + pjmedia_sdp_attr *recvonly; + pjmedia_sdp_attr *inactive; + pjmedia_sdp_attr *sendonly; + + recvonly = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "recvonly", NULL); + inactive = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "inactive", NULL); + sendonly = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "sendonly", NULL); + if (recvonly || inactive || sendonly) { + pjmedia_sdp_attr *to_remove = recvonly ?: inactive ?: sendonly; + pjmedia_sdp_attr *sendrecv; + + pjmedia_sdp_attr_remove(&m->attr_count, m->attr, to_remove); + + sendrecv = pjmedia_sdp_attr_create(session->inv_session->pool, "sendrecv", NULL); + pjmedia_sdp_media_add_attr(m, sendrecv); + } + } + + *p_offer = offer; } -#endif static void session_inv_on_media_update(pjsip_inv_session *inv, pj_status_t status) { @@ -5422,6 +5430,7 @@ static pjsip_inv_callback inv_callback = { .on_new_session = session_inv_on_new_session, .on_tsx_state_changed = session_inv_on_tsx_state_changed, .on_rx_offer = session_inv_on_rx_offer, + .on_create_offer = session_inv_on_create_offer, .on_media_update = session_inv_on_media_update, .on_redirected = session_inv_on_redirected, };