<p>Jenkins2 <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/6936">View Change</a></p><div style="white-space:pre-wrap">Approvals:
George Joseph: Looks good to me, but someone else must approve
Kevin Harwell: Looks good to me, approved
Jenkins2: Approved for Submit
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">core / pjsip: Add support for grouping streams together.<br><br>In WebRTC streams (or media tracks in their world) can be grouped<br>together using the mslabel. This informs the browser that each<br>should be synchronized with each other.<br><br>This change extends the stream API so this information can<br>be stored with streams. The PJSIP support has been extended<br>to use the mslabel to determine grouped streams and store<br>this association on the streams. Finally when creating the<br>SDP the group information is used to cause each media stream<br>to use the same mslabel.<br><br>ASTERISK-27379<br><br>Change-Id: Id6299aa031efe46254edbdc7973c534d54d641ad<br>---<br>M include/asterisk/res_pjsip_session.h<br>M include/asterisk/stream.h<br>M main/cli.c<br>M main/stream.c<br>M res/res_pjsip_sdp_rtp.c<br>M res/res_pjsip_session.c<br>6 files changed, 121 insertions(+), 15 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h<br>index 70f9468..de6589a 100644<br>--- a/include/asterisk/res_pjsip_session.h<br>+++ b/include/asterisk/res_pjsip_session.h<br>@@ -111,6 +111,8 @@<br> char label[AST_UUID_STR_LEN];<br> /*! \brief The underlying session has been changed in some fashion */<br> unsigned int changed;<br>+ /*! \brief Remote media stream label */<br>+ char *remote_mslabel;<br> };<br> <br> /*!<br>diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h<br>index 4027231..bbde73d 100644<br>--- a/include/asterisk/stream.h<br>+++ b/include/asterisk/stream.h<br>@@ -465,4 +465,25 @@<br> void ast_stream_topology_map(const struct ast_stream_topology *topology,<br> struct ast_vector_int *types, struct ast_vector_int *v0, struct ast_vector_int *v1);<br> <br>+/*!<br>+ * \brief Get the stream group that a stream is part of<br>+ *<br>+ * \param stream The stream<br>+ *<br>+ * \return the numerical stream group (-1 if not in a group)<br>+ *<br>+ * \since 15.2.0<br>+ */<br>+int ast_stream_get_group(const struct ast_stream *stream);<br>+<br>+/*!<br>+ * \brief Set the stream group for a stream<br>+ *<br>+ * \param stream The stream<br>+ * \param group The group the stream is part of<br>+ *<br>+ * \since 15.2.0<br>+ */<br>+void ast_stream_set_group(struct ast_stream *stream, int group);<br>+<br> #endif /* _AST_STREAM_H */<br>diff --git a/main/cli.c b/main/cli.c<br>index ef86e25..d9aab85 100644<br>--- a/main/cli.c<br>+++ b/main/cli.c<br>@@ -1690,10 +1690,12 @@<br> "Name: %s\n"<br> " Type: %s\n"<br> " State: %s\n"<br>+ " Group: %d\n"<br> " Formats: %s\n",<br> ast_stream_get_name(stream),<br> ast_codec_media_type2str(ast_stream_get_type(stream)),<br> ast_stream_state2str(ast_stream_get_state(stream)),<br>+ ast_stream_get_group(stream),<br> ast_format_cap_get_names(ast_stream_get_formats(stream), &codec_buf)<br> );<br> }<br>diff --git a/main/stream.c b/main/stream.c<br>index 093cd54..72d8599 100644<br>--- a/main/stream.c<br>+++ b/main/stream.c<br>@@ -67,6 +67,11 @@<br> ast_stream_data_free_fn data_free_fn[AST_STREAM_DATA_SLOT_MAX];<br> <br> /*!<br>+ * \brief The group that the stream is part of<br>+ */<br>+ int group;<br>+<br>+ /*!<br> * \brief Name for the stream within the context of the channel it is on<br> */<br> char name[0];<br>@@ -90,6 +95,7 @@<br> <br> stream->type = type;<br> stream->state = AST_STREAM_STATE_INACTIVE;<br>+ stream->group = -1;<br> strcpy(stream->name, S_OR(name, "")); /* Safe */<br> <br> return stream;<br>@@ -115,6 +121,7 @@<br> <br> memcpy(new_stream, stream, sizeof(*new_stream));<br> strcpy(new_stream->name, stream_name); /* Safe */<br>+ new_stream->group = -1;<br> if (new_stream->formats) {<br> ao2_ref(new_stream->formats, +1);<br> }<br>@@ -271,14 +278,16 @@<br> }<br> <br> for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {<br>- struct ast_stream *stream =<br>- ast_stream_clone(AST_VECTOR_GET(&topology->streams, i), NULL);<br>+ struct ast_stream *existing = AST_VECTOR_GET(&topology->streams, i);<br>+ struct ast_stream *stream = ast_stream_clone(existing, NULL);<br> <br> if (!stream || AST_VECTOR_APPEND(&new_topology->streams, stream)) {<br> ast_stream_free(stream);<br> ast_stream_topology_free(new_topology);<br> return NULL;<br> }<br>+<br>+ ast_stream_set_group(stream, ast_stream_get_group(existing));<br> }<br> <br> return new_topology;<br>@@ -563,3 +572,17 @@<br> AST_VECTOR_REPLACE(v1, index, i);<br> }<br> }<br>+<br>+int ast_stream_get_group(const struct ast_stream *stream)<br>+{<br>+ ast_assert(stream != NULL);<br>+<br>+ return stream->group;<br>+}<br>+<br>+void ast_stream_set_group(struct ast_stream *stream, int group)<br>+{<br>+ ast_assert(stream != NULL);<br>+<br>+ stream->group = group;<br>+}<br>diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c<br>index 604fd42..a877582 100644<br>--- a/res/res_pjsip_sdp_rtp.c<br>+++ b/res/res_pjsip_sdp_rtp.c<br>@@ -1052,20 +1052,11 @@<br> }<br> <br> if (ast_strlen_zero(session_media->mslabel)) {<br>- if (ast_sip_session_is_pending_stream_default(session, stream)) {<br>- int index;<br>+ /* If this stream is grouped with another then use its media stream label if possible */<br>+ if (ast_stream_get_group(stream) != -1) {<br>+ struct ast_sip_session_media *group_session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, ast_stream_get_group(stream));<br> <br>- /* If this is a default stream we group them together under the same stream, but as different tracks */<br>- for (index = 0; index < AST_VECTOR_SIZE(&session->pending_media_state->sessions); ++index) {<br>- struct ast_sip_session_media *other_session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index);<br>-<br>- if (session_media == other_session_media) {<br>- continue;<br>- }<br>-<br>- ast_copy_string(session_media->mslabel, other_session_media->mslabel, sizeof(session_media->mslabel));<br>- break;<br>- }<br>+ ast_copy_string(session_media->mslabel, group_session_media->mslabel, sizeof(session_media->mslabel));<br> }<br> <br> if (ast_strlen_zero(session_media->mslabel)) {<br>diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c<br>index 37ff531..4724d46 100644<br>--- a/res/res_pjsip_session.c<br>+++ b/res/res_pjsip_session.c<br>@@ -399,6 +399,7 @@<br> }<br> <br> ast_free(session_media->mid);<br>+ ast_free(session_media->remote_mslabel);<br> }<br> <br> struct ast_sip_session_media *ast_sip_session_media_state_add(struct ast_sip_session *session,<br>@@ -553,6 +554,70 @@<br> return 0;<br> }<br> <br>+static void set_remote_mslabel_and_stream_group(struct ast_sip_session *session,<br>+ struct ast_sip_session_media *session_media,<br>+ const pjmedia_sdp_session *sdp,<br>+ const struct pjmedia_sdp_media *stream,<br>+ struct ast_stream *asterisk_stream)<br>+{<br>+ int index;<br>+<br>+ ast_free(session_media->remote_mslabel);<br>+ session_media->remote_mslabel = NULL;<br>+<br>+ for (index = 0; index < stream->attr_count; ++index) {<br>+ pjmedia_sdp_attr *attr = stream->attr[index];<br>+ char attr_value[pj_strlen(&attr->value) + 1];<br>+ char *ssrc_attribute_name, *ssrc_attribute_value = NULL;<br>+ char *msid, *tmp = attr_value;<br>+ static const pj_str_t STR_msid = { "msid", 4 };<br>+ static const pj_str_t STR_ssrc = { "ssrc", 4 };<br>+<br>+ if (!pj_strcmp(&attr->name, &STR_msid)) {<br>+ ast_copy_pj_str(attr_value, &attr->value, sizeof(attr_value));<br>+ msid = strsep(&tmp, " ");<br>+ session_media->remote_mslabel = ast_strdup(msid);<br>+ break;<br>+ } else if (!pj_strcmp(&attr->name, &STR_ssrc)) {<br>+ ast_copy_pj_str(attr_value, &attr->value, sizeof(attr_value));<br>+<br>+ if ((ssrc_attribute_name = strchr(attr_value, ' '))) {<br>+ /* This has an actual attribute */<br>+ *ssrc_attribute_name++ = '\0';<br>+ ssrc_attribute_value = strchr(ssrc_attribute_name, ':');<br>+ if (ssrc_attribute_value) {<br>+ /* Values are actually optional according to the spec */<br>+ *ssrc_attribute_value++ = '\0';<br>+ }<br>+<br>+ if (!strcasecmp(ssrc_attribute_name, "mslabel") && !ast_strlen_zero(ssrc_attribute_value)) {<br>+ session_media->remote_mslabel = ast_strdup(ssrc_attribute_value);<br>+ break;<br>+ }<br>+ }<br>+ }<br>+ }<br>+<br>+ if (ast_strlen_zero(session_media->remote_mslabel)) {<br>+ return;<br>+ }<br>+<br>+ /* Iterate through the existing streams looking for a match and if so then group this with it */<br>+ for (index = 0; index < AST_VECTOR_SIZE(&session->pending_media_state->sessions); ++index) {<br>+ struct ast_sip_session_media *group_session_media;<br>+<br>+ group_session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index);<br>+<br>+ if (ast_strlen_zero(group_session_media->remote_mslabel) ||<br>+ strcmp(group_session_media->remote_mslabel, session_media->remote_mslabel)) {<br>+ continue;<br>+ }<br>+<br>+ ast_stream_set_group(asterisk_stream, index);<br>+ break;<br>+ }<br>+}<br>+<br> static void remove_stream_from_bundle(struct ast_sip_session_media *session_media,<br> struct ast_stream *stream)<br> {<br>@@ -630,6 +695,7 @@<br> }<br> <br> set_mid_and_bundle_group(session, session_media, sdp, remote_stream);<br>+ set_remote_mslabel_and_stream_group(session, session_media, sdp, remote_stream, stream);<br> <br> if (session_media->handler) {<br> handler = session_media->handler;<br>@@ -730,6 +796,7 @@<br> ast_copy_pj_str(media, &local->media[index]->desc.media, sizeof(media));<br> <br> set_mid_and_bundle_group(session, session_media, remote, remote->media[index]);<br>+ set_remote_mslabel_and_stream_group(session, session_media, remote, remote->media[index], asterisk_stream);<br> <br> handler = session_media->handler;<br> if (handler) {<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/6936">change 6936</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/6936"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 15 </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: Id6299aa031efe46254edbdc7973c534d54d641ad </div>
<div style="display:none"> Gerrit-Change-Number: 6936 </div>
<div style="display:none"> Gerrit-PatchSet: 3 </div>
<div style="display:none"> Gerrit-Owner: Joshua Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins2 </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Sean Bright <sean.bright@gmail.com> </div>