void ast_stream_topology_map(const struct ast_stream_topology *topology,
struct ast_vector_int *types, struct ast_vector_int *v0, struct ast_vector_int *v1);
+/*!
+ * \brief Get the stream group that a stream is part of
+ *
+ * \param stream The stream
+ *
+ * \return the numerical stream group (-1 if not in a group)
+ *
+ * \since 15.2.0
+ */
+int ast_stream_get_group(const struct ast_stream *stream);
+
+/*!
+ * \brief Set the stream group for a stream
+ *
+ * \param stream The stream
+ * \param group The group the stream is part of
+ *
+ * \since 15.2.0
+ */
+void ast_stream_set_group(struct ast_stream *stream, int group);
+
#endif /* _AST_STREAM_H */
*/
ast_stream_data_free_fn data_free_fn[AST_STREAM_DATA_SLOT_MAX];
+ /*!
+ * \brief The group that the stream is part of
+ */
+ int group;
+
/*!
* \brief Name for the stream within the context of the channel it is on
*/
stream->type = type;
stream->state = AST_STREAM_STATE_INACTIVE;
+ stream->group = -1;
strcpy(stream->name, S_OR(name, "")); /* Safe */
return stream;
memcpy(new_stream, stream, sizeof(*new_stream));
strcpy(new_stream->name, stream_name); /* Safe */
+ new_stream->group = -1;
if (new_stream->formats) {
ao2_ref(new_stream->formats, +1);
}
}
for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {
- struct ast_stream *stream =
- ast_stream_clone(AST_VECTOR_GET(&topology->streams, i), NULL);
+ struct ast_stream *existing = AST_VECTOR_GET(&topology->streams, i);
+ struct ast_stream *stream = ast_stream_clone(existing, NULL);
if (!stream || AST_VECTOR_APPEND(&new_topology->streams, stream)) {
ast_stream_free(stream);
ast_stream_topology_free(new_topology);
return NULL;
}
+
+ ast_stream_set_group(stream, ast_stream_get_group(existing));
}
return new_topology;
AST_VECTOR_REPLACE(v1, index, i);
}
}
+
+int ast_stream_get_group(const struct ast_stream *stream)
+{
+ ast_assert(stream != NULL);
+
+ return stream->group;
+}
+
+void ast_stream_set_group(struct ast_stream *stream, int group)
+{
+ ast_assert(stream != NULL);
+
+ stream->group = group;
+}
}
if (ast_strlen_zero(session_media->mslabel)) {
- if (ast_sip_session_is_pending_stream_default(session, stream)) {
- int index;
-
- /* If this is a default stream we group them together under the same stream, but as different tracks */
- for (index = 0; index < AST_VECTOR_SIZE(&session->pending_media_state->sessions); ++index) {
- struct ast_sip_session_media *other_session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index);
-
- if (session_media == other_session_media) {
- continue;
- }
+ /* If this stream is grouped with another then use its media stream label if possible */
+ if (ast_stream_get_group(stream) != -1) {
+ struct ast_sip_session_media *group_session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, ast_stream_get_group(stream));
- ast_copy_string(session_media->mslabel, other_session_media->mslabel, sizeof(session_media->mslabel));
- break;
- }
+ ast_copy_string(session_media->mslabel, group_session_media->mslabel, sizeof(session_media->mslabel));
}
if (ast_strlen_zero(session_media->mslabel)) {
}
ast_free(session_media->mid);
+ ast_free(session_media->remote_mslabel);
}
struct ast_sip_session_media *ast_sip_session_media_state_add(struct ast_sip_session *session,
return 0;
}
+static void set_remote_mslabel_and_stream_group(struct ast_sip_session *session,
+ struct ast_sip_session_media *session_media,
+ const pjmedia_sdp_session *sdp,
+ const struct pjmedia_sdp_media *stream,
+ struct ast_stream *asterisk_stream)
+{
+ int index;
+
+ ast_free(session_media->remote_mslabel);
+ session_media->remote_mslabel = NULL;
+
+ for (index = 0; index < stream->attr_count; ++index) {
+ pjmedia_sdp_attr *attr = stream->attr[index];
+ char attr_value[pj_strlen(&attr->value) + 1];
+ char *ssrc_attribute_name, *ssrc_attribute_value = NULL;
+ char *msid, *tmp = attr_value;
+ static const pj_str_t STR_msid = { "msid", 4 };
+ static const pj_str_t STR_ssrc = { "ssrc", 4 };
+
+ if (!pj_strcmp(&attr->name, &STR_msid)) {
+ ast_copy_pj_str(attr_value, &attr->value, sizeof(attr_value));
+ msid = strsep(&tmp, " ");
+ session_media->remote_mslabel = ast_strdup(msid);
+ break;
+ } else if (!pj_strcmp(&attr->name, &STR_ssrc)) {
+ ast_copy_pj_str(attr_value, &attr->value, sizeof(attr_value));
+
+ if ((ssrc_attribute_name = strchr(attr_value, ' '))) {
+ /* This has an actual attribute */
+ *ssrc_attribute_name++ = '\0';
+ ssrc_attribute_value = strchr(ssrc_attribute_name, ':');
+ if (ssrc_attribute_value) {
+ /* Values are actually optional according to the spec */
+ *ssrc_attribute_value++ = '\0';
+ }
+
+ if (!strcasecmp(ssrc_attribute_name, "mslabel") && !ast_strlen_zero(ssrc_attribute_value)) {
+ session_media->remote_mslabel = ast_strdup(ssrc_attribute_value);
+ break;
+ }
+ }
+ }
+ }
+
+ if (ast_strlen_zero(session_media->remote_mslabel)) {
+ return;
+ }
+
+ /* Iterate through the existing streams looking for a match and if so then group this with it */
+ for (index = 0; index < AST_VECTOR_SIZE(&session->pending_media_state->sessions); ++index) {
+ struct ast_sip_session_media *group_session_media;
+
+ group_session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index);
+
+ if (ast_strlen_zero(group_session_media->remote_mslabel) ||
+ strcmp(group_session_media->remote_mslabel, session_media->remote_mslabel)) {
+ continue;
+ }
+
+ ast_stream_set_group(asterisk_stream, index);
+ break;
+ }
+}
+
static void remove_stream_from_bundle(struct ast_sip_session_media *session_media,
struct ast_stream *stream)
{
}
set_mid_and_bundle_group(session, session_media, sdp, remote_stream);
+ set_remote_mslabel_and_stream_group(session, session_media, sdp, remote_stream, stream);
if (session_media->handler) {
handler = session_media->handler;
ast_copy_pj_str(media, &local->media[index]->desc.media, sizeof(media));
set_mid_and_bundle_group(session, session_media, remote, remote->media[index]);
+ set_remote_mslabel_and_stream_group(session, session_media, remote, remote->media[index], asterisk_stream);
handler = session_media->handler;
if (handler) {