[Asterisk-code-review] res pjsip: Add "webrtc" configuration option (asterisk[master])

Kevin Harwell asteriskteam at digium.com
Tue Jul 11 09:50:46 CDT 2017


Kevin Harwell has uploaded this change for review. ( https://gerrit.asterisk.org/5988


Change subject: res_pjsip: Add "webrtc" configuration option
......................................................................

res_pjsip: Add "webrtc" configuration option

This patch creates a new configuration option called "webrtc". When enabled it
defaults and enables the following options that are needed in order for webrtc
to work in Asterisk:

  rtcp-mux, use_avpf, ice_support, and use_received_transport equal enabled
  if media_encryption=unset/none, then media_encryption=dtls
  if media_encryption=dtls and dtls_verify=unset/none,
      then dtls_verify=fingerprint
  if media_encryption=dtls, then dtls_setup=actpass (Note, overwrites
      any already specified value)

When "webrtc" is enabled, this patch also parses the "msid" media level
attribute from an SDP. It will also appropriately add it onto the outgoing
session when applicable.

Lastly, when "webrtc" is enabled h264 RTCP FIR feedback frames are now sent.

ASTERISK-27119 #close

Change-Id: I5ec02e07c5d5b9ad86a34fdf31bf2f9da9aac6fd
---
M channels/chan_pjsip.c
M configs/samples/pjsip.conf.sample
M include/asterisk/res_pjsip.h
M include/asterisk/res_pjsip_session.h
M res/res_pjsip.c
M res/res_pjsip.exports.in
M res/res_pjsip/pjsip_configuration.c
M res/res_pjsip_sdp_rtp.c
M res/res_pjsip_session.c
9 files changed, 165 insertions(+), 1 deletion(-)



  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/88/5988/1

diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c
index fc59c90..6cfbe91 100644
--- a/channels/chan_pjsip.c
+++ b/channels/chan_pjsip.c
@@ -1597,7 +1597,9 @@
 				/* FIXME: Only use this for VP8. Additional work would have to be done to
 				 * fully support other video codecs */
 
-				if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), ast_format_vp8) != AST_FORMAT_CMP_NOT_EQUAL) {
+				if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), ast_format_vp8) != AST_FORMAT_CMP_NOT_EQUAL ||
+					(channel->session->endpoint->media.webrtc &&
+					 ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), ast_format_vp8) != AST_FORMAT_CMP_NOT_EQUAL)) {
 					/* FIXME Fake RTP write, this will be sent as an RTCP packet. Ideally the
 					 * RTP engine would provide a way to externally write/schedule RTCP
 					 * packets */
diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample
index c05938e..aa412f9 100644
--- a/configs/samples/pjsip.conf.sample
+++ b/configs/samples/pjsip.conf.sample
@@ -790,6 +790,15 @@
                     ; (default: 1)
 ;max_video_streams= ; The maximum number of allowed negotiated video streams
                     ; (default: 1)
+;webrtc= ; When set to "yes" this also enables the following values that are needed
+         ; for webrtc: rtcp-mux, use_avpf, ice_support, and use_received_transport.
+         ; The following configuration settings also get defaulted as follows:
+         ;     if media_encryption=unset/none, then media_encryption=dtls
+         ;     if media_encryption=dtls and dtls_verify=unset/none,
+         ;         then dtls_verify=fingerprint
+         ;     if media_encryption=dtls, then dtls_setup=actpass (Note,
+         ;         overwrites any already specified value)
+         ; Default for this option is "no"
 
 ;==========================AUTH SECTION OPTIONS=========================
 ;[auth]
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index 2cd27d3..5dcc6c4 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -688,6 +688,8 @@
 	unsigned int max_audio_streams;
 	/*! Maximum number of video streams to offer/accept */
 	unsigned int max_video_streams;
+	/*! Enable webrtc settings and defaults */
+	unsigned int webrtc;
 };
 
 /*!
@@ -2059,6 +2061,24 @@
 void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size);
 
 /*!
+ * \brief Create and copy a pj_str_t into a standard character buffer.
+ *
+ * pj_str_t is not NULL-terminated. Any place that expects a NULL-
+ * terminated string needs to have the pj_str_t copied into a separate
+ * buffer.
+ *
+ * Copies the pj_str_t contents into a newly allocated buffer pointed to
+ * by dest. NULL-terminates the buffer.
+ *
+ * \note Caller is responsible for freeing the allocated memory.
+ *
+ * \param dest [out] The destination buffer
+ * \param src The pj_str_t to copy
+ * \retval Number of characters copied or negative value on error
+ */
+int ast_copy_pj_str2(char **dest, const pj_str_t *src);
+
+/*!
  * \brief Get the looked-up endpoint on an out-of dialog request or response
  *
  * The function may ONLY be called on out-of-dialog requests or responses. For
diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h
index e298e1f..62f5391 100644
--- a/include/asterisk/res_pjsip_session.h
+++ b/include/asterisk/res_pjsip_session.h
@@ -99,6 +99,8 @@
 	ast_sip_session_media_write_cb write_callback;
 	/*! \brief The stream number to place into any resulting frames */
 	int stream_num;
+	/*! \brief RTP/Media streams association identifier */
+	char *msid;
 };
 
 /*!
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index 8923540..b061b8f 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -1002,6 +1002,18 @@
 						streams allowed for the endpoint.
 					</para></description>
 				</configOption>
+				<configOption name="webrtc" default="no">
+					<synopsis>Defaults and enables some options that are relevant to WebRTC</synopsis>
+					<description><para>
+						When set to "yes" this also enables the following values that are needed in
+						order for basic WebRTC support to work: rtcp-mux, use_avpf, ice_support, and
+						use_received_transport. The following configuration settings also get defaulted
+						as follows:</para>
+						<para>if media_encryption=unset/none, then media_encryption=dtls</para>
+						<para>if media_encryption=dtls and dtls_verify=unset/none, then dtls_verify=fingerprint</para>
+						<para>if media_encryption=dtls, then dtls_setup=actpass (Note, overwrites any already specified value)</para>
+					</description>
+				</configOption>
 			</configObject>
 			<configObject name="auth">
 				<synopsis>Authentication type</synopsis>
@@ -4228,6 +4240,18 @@
 	dest[chars_to_copy] = '\0';
 }
 
+int ast_copy_pj_str2(char **dest, const pj_str_t *src)
+{
+	int res = ast_asprintf(dest, "%.*s", (int)pj_strlen(src), pj_strbuf(src));
+
+	if (res < 0) {
+		*dest = NULL;
+	}
+
+	return res;
+}
+
+
 int ast_sip_is_content_type(pjsip_media_type *content_type, char *type, char *subtype)
 {
 	pjsip_media_type compare;
diff --git a/res/res_pjsip.exports.in b/res/res_pjsip.exports.in
index 8b62abb..4adecd4 100644
--- a/res/res_pjsip.exports.in
+++ b/res/res_pjsip.exports.in
@@ -2,6 +2,7 @@
 	global:
 		LINKER_SYMBOL_PREFIXast_sip_*;
 		LINKER_SYMBOL_PREFIXast_copy_pj_str;
+		LINKER_SYMBOL_PREFIXast_copy_pj_str2;
 		LINKER_SYMBOL_PREFIXast_pjsip_rdata_get_endpoint;
 	local:
 		*;
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index 372b01b..00c9755 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -1332,6 +1332,28 @@
 		return -1;
 	}
 
+	/*
+	 * If webrtc has been enabled then enable those attributes, and default
+	 * some, that are needed in order for webrtc to work.
+	 */
+	endpoint->media.rtcp_mux |= endpoint->media.webrtc;
+	endpoint->media.rtp.use_avpf |= endpoint->media.webrtc;
+	endpoint->media.rtp.ice_support |= endpoint->media.webrtc;
+	endpoint->media.rtp.use_received_transport |= endpoint->media.webrtc;
+
+	if (endpoint->media.webrtc) {
+		if (endpoint->media.rtp.encryption == AST_SIP_MEDIA_ENCRYPT_NONE) {
+			endpoint->media.rtp.encryption = AST_SIP_MEDIA_ENCRYPT_DTLS;
+			endpoint->media.rtp.dtls_cfg.enabled = 1;
+		}
+		if (endpoint->media.rtp.dtls_cfg.enabled) {
+			endpoint->media.rtp.dtls_cfg.default_setup = AST_RTP_DTLS_SETUP_ACTPASS;
+			if (endpoint->media.rtp.dtls_cfg.verify == AST_RTP_DTLS_VERIFY_NONE) {
+				endpoint->media.rtp.dtls_cfg.verify = AST_RTP_DTLS_VERIFY_FINGERPRINT;
+			}
+		}
+	}
+
 	return 0;
 }
 
@@ -1954,6 +1976,7 @@
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "notify_early_inuse_ringing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, notify_early_inuse_ringing));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_audio_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_audio_streams));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_video_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_video_streams));
+	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "webrtc", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.webrtc));
 
 	if (ast_sip_initialize_sorcery_transport()) {
 		ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c
index a491308..4599194 100644
--- a/res/res_pjsip_sdp_rtp.c
+++ b/res/res_pjsip_sdp_rtp.c
@@ -940,6 +940,65 @@
 	}
 }
 
+static void process_msid_attribute(struct ast_sip_session *session,
+	struct ast_sip_session_media *session_media, pjmedia_sdp_media *media)
+{
+	pjmedia_sdp_attr *attr;
+
+	if (!session->endpoint->media.webrtc) {
+		return;
+	}
+
+	attr = pjmedia_sdp_media_find_attr2(media, "msid", NULL);
+	if (attr) {
+		ast_free(session_media->msid);
+		ast_copy_pj_str2(&session_media->msid, &attr->value);
+	}
+}
+
+static void add_msid_to_stream(struct ast_sip_session *session,
+	struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media)
+{
+	pj_str_t stmp;
+	pjmedia_sdp_attr *attr;
+
+	if (!session->endpoint->media.webrtc) {
+		return;
+	}
+
+	if (ast_strlen_zero(session_media->msid)) {
+		char uuid1[AST_UUID_STR_LEN], uuid2[AST_UUID_STR_LEN];
+
+		if (ast_asprintf(&session_media->msid, "{%s} {%s}",
+			ast_uuid_generate_str(uuid1, sizeof(uuid1)),
+			ast_uuid_generate_str(uuid2, sizeof(uuid2))) < 0) {
+			session_media->msid = NULL;
+			return;
+		}
+	}
+
+	attr = pjmedia_sdp_attr_create(pool, "msid", pj_cstr(&stmp, session_media->msid));
+	pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr);
+}
+
+static void add_rtcp_fb_to_stream(struct ast_sip_session *session,
+	struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media)
+{
+	pj_str_t stmp;
+	pjmedia_sdp_attr *attr;
+
+	if (!session->endpoint->media.webrtc || session_media->type != AST_MEDIA_TYPE_VIDEO) {
+		return;
+	}
+
+	/*
+	 * For now just automatically add it the stream even though it hasn't
+	 * necessarily been negotiated.
+	 */
+	attr = pjmedia_sdp_attr_create(pool, "rtcp-fb", pj_cstr(&stmp, "* ccm fir"));
+	pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr);
+}
+
 /*! \brief Function which negotiates an incoming media stream */
 static int negotiate_incoming_sdp_stream(struct ast_sip_session *session,
 	struct ast_sip_session_media *session_media, const pjmedia_sdp_session *sdp,
@@ -982,9 +1041,12 @@
 	}
 
 	session_media->remote_rtcp_mux = (pjmedia_sdp_media_find_attr2(stream, "rtcp-mux", NULL) != NULL);
+
 	set_ice_components(session, session_media);
 
 	enable_rtcp(session, session_media, stream);
+
+	process_msid_attribute(session, session_media, stream);
 
 	res = setup_media_encryption(session, session_media, sdp, stream);
 	if (res) {
@@ -1013,6 +1075,7 @@
 	if (set_caps(session, session_media, stream, 1, asterisk_stream)) {
 		return 0;
 	}
+
 	return 1;
 }
 
@@ -1365,6 +1428,9 @@
 		pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr);
 	}
 
+	add_msid_to_stream(session, session_media, pool, media);
+	add_rtcp_fb_to_stream(session, session_media, pool, media);
+
 	/* Add the media stream to the SDP */
 	sdp->media[sdp->media_count++] = media;
 
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index ecda499..8692ddd 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -371,6 +371,8 @@
 	if (session_media->srtp) {
 		ast_sdp_srtp_destroy(session_media->srtp);
 	}
+
+	ast_free(session_media->msid);
 }
 
 struct ast_sip_session_media *ast_sip_session_media_state_add(struct ast_sip_session *session,
@@ -3482,6 +3484,21 @@
 		}
 	}
 
+	/*
+	 * Add session level attributes. TODO This functionality should not be done here, but
+	 * instead should probably be done through something like a registered callback handler
+	 * at the SDP parsing level.
+	 */
+	if (session->endpoint->media.webrtc) {
+		pj_str_t stmp;
+		pjmedia_sdp_attr *attr;
+
+		attr = pjmedia_sdp_attr_create(inv->pool_prov, "msid-semantic", pj_cstr(&stmp, "WMS *"));
+		if (attr) {
+			pjmedia_sdp_attr_add(&local->attr_count, local->attr, attr);
+		}
+	}
+
 	for (i = 0; i < ast_stream_topology_get_count(session->pending_media_state->topology); ++i) {
 		struct ast_sip_session_media *session_media;
 		struct ast_stream *stream;

-- 
To view, visit https://gerrit.asterisk.org/5988
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I5ec02e07c5d5b9ad86a34fdf31bf2f9da9aac6fd
Gerrit-Change-Number: 5988
Gerrit-PatchSet: 1
Gerrit-Owner: Kevin Harwell <kharwell at digium.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20170711/dfca424a/attachment-0001.html>


More information about the asterisk-code-review mailing list