[asterisk-commits] kharwell: branch kharwell/pimp_sip_diversion r387581 - in /team/kharwell/pimp...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri May 3 11:26:34 CDT 2013


Author: kharwell
Date: Fri May  3 11:26:27 2013
New Revision: 387581

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=387581
Log:
SIP Media negotiations

Added a dialplan function GULP_MEDIA_OFFER that accepts a codec type (example:
'audio') and allows overriding, or re-ordering, of an endpoints codecs
prior to dialing (e.g. using a pre-dial handler).  This adds functionality
for outbound requests only.

; sets the outgoing codecs to be ulaw,g722
Example: Set(GULP_MEDIA_OFFER(audio)=ulaw,g722)

Note that using this function and setting new media offers completely
overrides what is specified on the endpoint.  Currently it is allowed to
even list a codec that was not previously specified on the endpoint.

The code allows for un/registering of media offer types that can be
associated with the function itself.  This allows for future expansion of
other types, for example T.38.  Types 'audio' and 'video' are currently
supported.

(closes issue ASTERISK-21186)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2445/
........

Merged revisions 387580 from http://svn.asterisk.org/svn/asterisk/team/group/pimp_my_sip

Modified:
    team/kharwell/pimp_sip_diversion/   (props changed)
    team/kharwell/pimp_sip_diversion/channels/chan_gulp.c
    team/kharwell/pimp_sip_diversion/include/asterisk/res_sip_session.h
    team/kharwell/pimp_sip_diversion/res/res_sip_sdp_rtp.c
    team/kharwell/pimp_sip_diversion/res/res_sip_session.c
    team/kharwell/pimp_sip_diversion/res/res_sip_session.exports.in

Propchange: team/kharwell/pimp_sip_diversion/
------------------------------------------------------------------------------
--- pimp_sip_diversion-integrated (original)
+++ pimp_sip_diversion-integrated Fri May  3 11:26:27 2013
@@ -1,1 +1,1 @@
-/team/group/pimp_my_sip:1-387576
+/team/group/pimp_my_sip:1-387580

Modified: team/kharwell/pimp_sip_diversion/channels/chan_gulp.c
URL: http://svnview.digium.com/svn/asterisk/team/kharwell/pimp_sip_diversion/channels/chan_gulp.c?view=diff&rev=387581&r1=387580&r2=387581
==============================================================================
--- team/kharwell/pimp_sip_diversion/channels/chan_gulp.c (original)
+++ team/kharwell/pimp_sip_diversion/channels/chan_gulp.c Fri May  3 11:26:27 2013
@@ -77,6 +77,19 @@
 			<para>Returns a properly formatted dial string for dialing all contacts on an AOR.</para>
 		</description>
 	</function>
+	<function name="GULP_MEDIA_OFFER" language="en_US">
+		<synopsis>
+			Media and codec offerings to be set on an outbound SIP channel prior to dialing.
+		</synopsis>
+		<syntax>
+			<parameter name="media" required="true">
+				<para>types of media offered</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Returns the codecs offered based upon the media choice</para>
+		</description>
+	</function>
  ***/
 
 static const char desc[] = "Gulp SIP Channel";
@@ -247,6 +260,105 @@
 	.read = gulp_dial_contacts,
 };
 
+static int media_offer_read_av(struct ast_sip_session *session, char *buf,
+			       size_t len, enum ast_format_type media_type)
+{
+	int i, size = 0;
+	struct ast_format fmt;
+	const char *name;
+
+	for (i = 0; ast_codec_pref_index(&session->override_prefs, i, &fmt); ++i) {
+		if (AST_FORMAT_GET_TYPE(fmt.id) != media_type) {
+			continue;
+		}
+
+		name = ast_getformatname(&fmt);
+
+		if (ast_strlen_zero(name)) {
+			ast_log(LOG_WARNING, "GULP_MEDIA_OFFER unrecognized format %s\n", name);
+			continue;
+		}
+
+		/* add one since we'll include a comma */
+		size = strlen(name) + 1;
+		len -= size;
+		if ((len) < 0) {
+			break;
+		}
+
+		/* no reason to use strncat here since we have already ensured buf has
+                   enough space, so strcat can be safely used */
+		strcat(buf, name);
+		strcat(buf, ",");
+	}
+
+	if (size) {
+		/* remove the extra comma */
+		buf[strlen(buf) - 1] = '\0';
+	}
+	return 0;
+}
+
+struct media_offer_data {
+	struct ast_sip_session *session;
+	enum ast_format_type media_type;
+	const char *value;
+};
+
+static int media_offer_write_av(void *obj)
+{
+	struct media_offer_data *data = obj;
+	int i;
+	struct ast_format fmt;
+	/* remove all of the given media type first */
+	for (i = 0; ast_codec_pref_index(&data->session->override_prefs, i, &fmt); ++i) {
+		if (AST_FORMAT_GET_TYPE(fmt.id) == data->media_type) {
+			ast_codec_pref_remove(&data->session->override_prefs, &fmt);
+		}
+	}
+	ast_format_cap_remove_bytype(data->session->req_caps, data->media_type);
+	ast_parse_allow_disallow(&data->session->override_prefs, data->session->req_caps, data->value, 1);
+
+	return 0;
+}
+
+static int media_offer_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+	struct gulp_pvt *pvt = ast_channel_tech_pvt(chan);
+
+	if (!strcmp(data, "audio")) {
+		return media_offer_read_av(pvt->session, buf, len, AST_FORMAT_TYPE_AUDIO);
+	} else if (!strcmp(data, "video")) {
+		return media_offer_read_av(pvt->session, buf, len, AST_FORMAT_TYPE_VIDEO);
+	}
+
+	return 0;
+}
+
+static int media_offer_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
+{
+	struct gulp_pvt *pvt = ast_channel_tech_pvt(chan);
+
+	struct media_offer_data mdata = {
+		.session = pvt->session,
+		.value = value
+	};
+
+	if (!strcmp(data, "audio")) {
+		mdata.media_type = AST_FORMAT_TYPE_AUDIO;
+	} else if (!strcmp(data, "video")) {
+		mdata.media_type = AST_FORMAT_TYPE_VIDEO;
+	}
+
+	return ast_sip_push_task_synchronous(pvt->session->serializer, media_offer_write_av, &mdata);
+}
+
+static struct ast_custom_function media_offer_function = {
+	.name = "GULP_MEDIA_OFFER",
+	.read = media_offer_read,
+	.write = media_offer_write
+};
+
 /*! \brief Function called by RTP engine to get local audio RTP peer */
 static enum ast_rtp_glue_result gulp_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
 {
@@ -935,16 +1047,17 @@
 static int call(void *data)
 {
 	struct ast_sip_session *session = data;
-	pjsip_tx_data *packet;
-
-	if (pjsip_inv_invite(session->inv_session, &packet) != PJ_SUCCESS) {
+	pjsip_tx_data *tdata;
+
+	int res = ast_sip_session_create_invite(session, &tdata);
+
+	if (res) {
 		ast_queue_hangup(session->channel);
 	} else {
-		ast_sip_session_send_request(session, packet);
-	}
-
+		ast_sip_session_send_request(session, tdata);
+	}
 	ao2_ref(session, -1);
-	return 0;
+	return res;
 }
 
 /*! \brief Function called by core to actually start calling a remote party */
@@ -1476,6 +1589,10 @@
 		goto end;
 	}
 
+	if (ast_custom_function_register(&media_offer_function)) {
+		ast_log(LOG_WARNING, "Unable to register GULP_MEDIA_OFFER dialplan function\n");
+	}
+
 	if (ast_sip_session_register_supplement(&gulp_supplement)) {
 		ast_log(LOG_ERROR, "Unable to register Gulp supplement\n");
 		goto end;
@@ -1497,6 +1614,7 @@
 	return 0;
 
 end:
+	ast_custom_function_unregister(&media_offer_function);
 	ast_custom_function_unregister(&gulp_dial_contacts_function);
 	ast_channel_unregister(&gulp_tech);
 	ast_rtp_glue_unregister(&gulp_rtp_glue);
@@ -1513,8 +1631,11 @@
 /*! \brief Unload the Gulp channel from Asterisk */
 static int unload_module(void)
 {
+	ast_custom_function_unregister(&media_offer_function);
+
 	ast_sip_session_unregister_supplement(&gulp_supplement);
 	ast_sip_session_unregister_supplement(&pbx_start_supplement);
+
 	ast_custom_function_unregister(&gulp_dial_contacts_function);
 	ast_channel_unregister(&gulp_tech);
 	ast_rtp_glue_unregister(&gulp_rtp_glue);

Modified: team/kharwell/pimp_sip_diversion/include/asterisk/res_sip_session.h
URL: http://svnview.digium.com/svn/asterisk/team/kharwell/pimp_sip_diversion/include/asterisk/res_sip_session.h?view=diff&rev=387581&r1=387580&r2=387581
==============================================================================
--- team/kharwell/pimp_sip_diversion/include/asterisk/res_sip_session.h (original)
+++ team/kharwell/pimp_sip_diversion/include/asterisk/res_sip_session.h Fri May  3 11:26:27 2013
@@ -105,6 +105,8 @@
 	struct ast_party_id id;
 	/* Requested capabilities */
 	struct ast_format_cap *req_caps;
+	/* Codecs overriden by dialplan on an outgoing request */
+	struct ast_codec_pref override_prefs;
 };
 
 typedef int (*ast_sip_session_request_creation_cb)(struct ast_sip_session *session, pjsip_tx_data *tdata);
@@ -456,6 +458,14 @@
 void ast_sip_session_send_request(struct ast_sip_session *session, pjsip_tx_data *tdata);
 
 /*!
+ * \brief Creates an INVITE request.
+ *
+ * \param session Starting session for the INVITE
+ * \param tdata The created request.
+ */
+int ast_sip_session_create_invite(struct ast_sip_session *session, pjsip_tx_data **tdata);
+
+/*!
  * \brief Send a SIP request and get called back when a response is received
  *
  * This will send the request out exactly the same as ast_sip_send_request() does.

Modified: team/kharwell/pimp_sip_diversion/res/res_sip_sdp_rtp.c
URL: http://svnview.digium.com/svn/asterisk/team/kharwell/pimp_sip_diversion/res/res_sip_sdp_rtp.c?view=diff&rev=387581&r1=387580&r2=387581
==============================================================================
--- team/kharwell/pimp_sip_diversion/res/res_sip_sdp_rtp.c (original)
+++ team/kharwell/pimp_sip_diversion/res/res_sip_sdp_rtp.c Fri May  3 11:26:27 2013
@@ -284,6 +284,18 @@
 	return attr;
 }
 
+static int codec_pref_has_type(struct ast_codec_pref *prefs, enum ast_format_type media_type)
+{
+	int i;
+	struct ast_format fmt;
+	for (i = 0; ast_codec_pref_index(prefs, i, &fmt); ++i) {
+		if (AST_FORMAT_GET_TYPE(fmt.id) == media_type) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
 /*! \brief Function which adds ICE attributes to a media stream */
 static void add_ice_to_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media)
 {
@@ -629,7 +641,6 @@
 	int index = 0, min_packet_size = 0, noncodec = (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733) ? AST_RTP_DTMF : 0;
 	int rtp_code;
 	struct ast_format format;
-	struct ast_format compat_format;
 	RAII_VAR(struct ast_format_cap *, caps, NULL, ast_format_cap_destroy);
 	enum ast_format_type media_type = stream_to_media_type(session_media->stream_type);
 	int crypto_res;
@@ -637,7 +648,12 @@
 	int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) &&
 		!ast_format_cap_is_empty(session->direct_media_cap);
 
-	if (!ast_format_cap_has_type(session->endpoint->codecs, media_type)) {
+	int use_override_prefs = session->override_prefs.formats[0].id;
+	struct ast_codec_pref *prefs = use_override_prefs ?
+		&session->override_prefs : &session->endpoint->prefs;
+
+	if ((use_override_prefs && !codec_pref_has_type(&session->override_prefs, media_type)) ||
+	    (!use_override_prefs && !ast_format_cap_has_type(session->endpoint->codecs, media_type))) {
 		/* If no type formats are configured don't add a stream */
 		return 0;
 	} else if (!session_media->rtp && create_rtp(session, session_media, session->endpoint->rtp_ipv6)) {
@@ -689,36 +705,36 @@
 	} else if (ast_format_cap_is_empty(session->req_caps) || !ast_format_cap_has_joint(session->req_caps, session->endpoint->codecs)) {
 		ast_format_cap_copy(caps, session->endpoint->codecs);
 	} else {
-		ast_format_cap_joint_copy(session->endpoint->codecs, session->req_caps, caps);
-	}
-
-	for (index = 0; ast_codec_pref_index(&session->endpoint->prefs, index, &format); ++index) {
+		ast_format_cap_copy(caps, session->req_caps);
+	}
+
+	for (index = 0; ast_codec_pref_index(prefs, index, &format); ++index) {
 		struct ast_codec_pref *pref = &ast_rtp_instance_get_codecs(session_media->rtp)->pref;
 
 		if (AST_FORMAT_GET_TYPE(format.id) != media_type) {
 			continue;
 		}
 
-		if (!ast_format_cap_get_compatible_format(caps, &format, &compat_format)) {
+		if (!use_override_prefs && !ast_format_cap_get_compatible_format(caps, &format, &format)) {
 			continue;
 		}
 
-		if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media->rtp), 1, &compat_format, 0)) == -1) {
+		if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media->rtp), 1, &format, 0)) == -1) {
 			return -1;
 		}
 
-		if (!(attr = generate_rtpmap_attr(media, pool, rtp_code, 1, &compat_format, 0))) {
+		if (!(attr = generate_rtpmap_attr(media, pool, rtp_code, 1, &format, 0))) {
 			continue;
 		}
 
 		media->attr[media->attr_count++] = attr;
 
-		if ((attr = generate_fmtp_attr(pool, &compat_format, rtp_code))) {
+		if ((attr = generate_fmtp_attr(pool, &format, rtp_code))) {
 			media->attr[media->attr_count++] = attr;
 		}
 
 		if (pref && media_type != AST_FORMAT_TYPE_VIDEO) {
-			struct ast_format_list fmt = ast_codec_pref_getsize(pref, &compat_format);
+			struct ast_format_list fmt = ast_codec_pref_getsize(pref, &format);
 			if (fmt.cur_ms && ((fmt.cur_ms < min_packet_size) || !min_packet_size)) {
 				min_packet_size = fmt.cur_ms;
 			}

Modified: team/kharwell/pimp_sip_diversion/res/res_sip_session.c
URL: http://svnview.digium.com/svn/asterisk/team/kharwell/pimp_sip_diversion/res/res_sip_session.c?view=diff&rev=387581&r1=387580&r2=387581
==============================================================================
--- team/kharwell/pimp_sip_diversion/res/res_sip_session.c (original)
+++ team/kharwell/pimp_sip_diversion/res/res_sip_session.c Fri May  3 11:26:27 2013
@@ -809,6 +809,22 @@
 	ast_sip_session_send_request_with_cb(session, tdata, NULL);
 }
 
+int ast_sip_session_create_invite(struct ast_sip_session *session, pjsip_tx_data **tdata)
+{
+	pjmedia_sdp_session *offer;
+
+	if (!(offer = create_local_sdp(session->inv_session, session, NULL))) {
+		pjsip_inv_terminate(session->inv_session, 500, PJ_FALSE);
+		return -1;
+	}
+
+	pjsip_inv_set_local_sdp(session->inv_session, offer);
+	if (pjsip_inv_invite(session->inv_session, tdata) != PJ_SUCCESS) {
+		return -1;
+	}
+	return 0;
+}
+
 /*!
  * \brief Called when the PJSIP core loads us
  *
@@ -1011,7 +1027,6 @@
 	pjsip_dialog *dlg;
 	struct pjsip_inv_session *inv_session;
 	RAII_VAR(struct ast_sip_session *, session, NULL, ao2_cleanup);
-	pjmedia_sdp_session *offer;
 
 	/* If no location has been provided use the AOR list from the endpoint itself */
 	location = S_OR(location, endpoint->aors);
@@ -1053,13 +1068,10 @@
 	}
 
 	ast_format_cap_copy(session->req_caps, req_caps);
-	if ((pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS) ||
-	    !(offer = create_local_sdp(inv_session, session, NULL))) {
+	if ((pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS)) {
 		pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
 		return NULL;
 	}
-
-	pjsip_inv_set_local_sdp(inv_session, offer);
 
 	ao2_ref(session, +1);
 	return session;

Modified: team/kharwell/pimp_sip_diversion/res/res_sip_session.exports.in
URL: http://svnview.digium.com/svn/asterisk/team/kharwell/pimp_sip_diversion/res/res_sip_session.exports.in?view=diff&rev=387581&r1=387580&r2=387581
==============================================================================
--- team/kharwell/pimp_sip_diversion/res/res_sip_session.exports.in (original)
+++ team/kharwell/pimp_sip_diversion/res/res_sip_session.exports.in Fri May  3 11:26:27 2013
@@ -12,6 +12,7 @@
 		LINKER_SYMBOL_PREFIXast_sip_session_refresh;
 		LINKER_SYMBOL_PREFIXast_sip_session_send_response;
 		LINKER_SYMBOL_PREFIXast_sip_session_send_request;
+		LINKER_SYMBOL_PREFIXast_sip_session_create_invite;
 		LINKER_SYMBOL_PREFIXast_sip_session_create_outgoing;
 	local:
 		*;




More information about the asterisk-commits mailing list