[Asterisk-code-review] res_pjsip_session: Always produce offer on re-INVITE without SDP. (asterisk[master])

Joshua Colp asteriskteam at digium.com
Wed Feb 17 08:53:14 CST 2021


Joshua Colp has uploaded this change for review. ( https://gerrit.asterisk.org/c/asterisk/+/15447 )


Change subject: res_pjsip_session: Always produce offer on re-INVITE without SDP.
......................................................................

res_pjsip_session: Always produce offer on re-INVITE without SDP.

When PJSIP receives a re-INVITE without an SDP offer the INVITE
session library will first call the on_create_offer callback and
if unavailable then use the active negotiated SDP as the offer.

In some cases this would result in a different SDP then was
previously used without an incremented SDP version number. The two
known cases are:

1. Sending an initial INVITE with a set of codecs and having the
remote side answer with a subset. The active negotiated SDP would
have the pruned list but would not have an incremented SDP version
number.

2. Using re-INVITE for unhold. We would modify the active negotiated
SDP but would not increment the SDP version.

To solve these, and potential other unknown cases, the on_create_offer
callback has now been implemented which produces a fresh offer with
incremented SDP version number. This better fits within the model
provided by the INVITE session library.

ASTERISK-28452

Change-Id: I2d81048d54edcb80fe38fdbb954a86f0a58281a1
---
M res/res_pjsip_session.c
1 file changed, 62 insertions(+), 53 deletions(-)



  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/47/15447/1

diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index d841aca..d953dc0 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -2782,56 +2782,6 @@
 	}
 
 	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;
 	}
 
@@ -5281,12 +5231,70 @@
 	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)
 {
@@ -5415,6 +5423,7 @@
 	.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,
 };

-- 
To view, visit https://gerrit.asterisk.org/c/asterisk/+/15447
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Change-Id: I2d81048d54edcb80fe38fdbb954a86f0a58281a1
Gerrit-Change-Number: 15447
Gerrit-PatchSet: 1
Gerrit-Owner: Joshua Colp <jcolp at sangoma.com>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20210217/6b90359a/attachment.html>


More information about the asterisk-code-review mailing list