mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-04 03:50:31 +00:00
core / pjsip: Add support for grouping streams together.
In WebRTC streams (or media tracks in their world) can be grouped together using the mslabel. This informs the browser that each should be synchronized with each other. This change extends the stream API so this information can be stored with streams. The PJSIP support has been extended to use the mslabel to determine grouped streams and store this association on the streams. Finally when creating the SDP the group information is used to cause each media stream to use the same mslabel. ASTERISK-27379 Change-Id: Id6299aa031efe46254edbdc7973c534d54d641ad
This commit is contained in:
@@ -111,6 +111,8 @@ struct ast_sip_session_media {
|
|||||||
char label[AST_UUID_STR_LEN];
|
char label[AST_UUID_STR_LEN];
|
||||||
/*! \brief The underlying session has been changed in some fashion */
|
/*! \brief The underlying session has been changed in some fashion */
|
||||||
unsigned int changed;
|
unsigned int changed;
|
||||||
|
/*! \brief Remote media stream label */
|
||||||
|
char *remote_mslabel;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@@ -476,4 +476,25 @@ struct ast_stream *ast_stream_topology_get_first_stream_by_type(
|
|||||||
void ast_stream_topology_map(const struct ast_stream_topology *topology,
|
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);
|
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 */
|
#endif /* _AST_STREAM_H */
|
||||||
|
@@ -1690,10 +1690,12 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
|
|||||||
"Name: %s\n"
|
"Name: %s\n"
|
||||||
" Type: %s\n"
|
" Type: %s\n"
|
||||||
" State: %s\n"
|
" State: %s\n"
|
||||||
|
" Group: %d\n"
|
||||||
" Formats: %s\n",
|
" Formats: %s\n",
|
||||||
ast_stream_get_name(stream),
|
ast_stream_get_name(stream),
|
||||||
ast_codec_media_type2str(ast_stream_get_type(stream)),
|
ast_codec_media_type2str(ast_stream_get_type(stream)),
|
||||||
ast_stream_state2str(ast_stream_get_state(stream)),
|
ast_stream_state2str(ast_stream_get_state(stream)),
|
||||||
|
ast_stream_get_group(stream),
|
||||||
ast_format_cap_get_names(ast_stream_get_formats(stream), &codec_buf)
|
ast_format_cap_get_names(ast_stream_get_formats(stream), &codec_buf)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -66,6 +66,11 @@ struct ast_stream {
|
|||||||
*/
|
*/
|
||||||
ast_stream_data_free_fn data_free_fn[AST_STREAM_DATA_SLOT_MAX];
|
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
|
* \brief Name for the stream within the context of the channel it is on
|
||||||
*/
|
*/
|
||||||
@@ -90,6 +95,7 @@ struct ast_stream *ast_stream_alloc(const char *name, enum ast_media_type type)
|
|||||||
|
|
||||||
stream->type = type;
|
stream->type = type;
|
||||||
stream->state = AST_STREAM_STATE_INACTIVE;
|
stream->state = AST_STREAM_STATE_INACTIVE;
|
||||||
|
stream->group = -1;
|
||||||
strcpy(stream->name, S_OR(name, "")); /* Safe */
|
strcpy(stream->name, S_OR(name, "")); /* Safe */
|
||||||
|
|
||||||
return stream;
|
return stream;
|
||||||
@@ -115,6 +121,7 @@ struct ast_stream *ast_stream_clone(const struct ast_stream *stream, const char
|
|||||||
|
|
||||||
memcpy(new_stream, stream, sizeof(*new_stream));
|
memcpy(new_stream, stream, sizeof(*new_stream));
|
||||||
strcpy(new_stream->name, stream_name); /* Safe */
|
strcpy(new_stream->name, stream_name); /* Safe */
|
||||||
|
new_stream->group = -1;
|
||||||
if (new_stream->formats) {
|
if (new_stream->formats) {
|
||||||
ao2_ref(new_stream->formats, +1);
|
ao2_ref(new_stream->formats, +1);
|
||||||
}
|
}
|
||||||
@@ -288,14 +295,16 @@ struct ast_stream_topology *ast_stream_topology_clone(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {
|
for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {
|
||||||
struct ast_stream *stream =
|
struct ast_stream *existing = AST_VECTOR_GET(&topology->streams, i);
|
||||||
ast_stream_clone(AST_VECTOR_GET(&topology->streams, i), NULL);
|
struct ast_stream *stream = ast_stream_clone(existing, NULL);
|
||||||
|
|
||||||
if (!stream || AST_VECTOR_APPEND(&new_topology->streams, stream)) {
|
if (!stream || AST_VECTOR_APPEND(&new_topology->streams, stream)) {
|
||||||
ast_stream_free(stream);
|
ast_stream_free(stream);
|
||||||
ast_stream_topology_free(new_topology);
|
ast_stream_topology_free(new_topology);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ast_stream_set_group(stream, ast_stream_get_group(existing));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_topology;
|
return new_topology;
|
||||||
@@ -580,3 +589,17 @@ void ast_stream_topology_map(const struct ast_stream_topology *topology,
|
|||||||
AST_VECTOR_REPLACE(v1, index, i);
|
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;
|
||||||
|
}
|
||||||
|
@@ -1052,20 +1052,11 @@ static void add_msid_to_stream(struct ast_sip_session *session,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ast_strlen_zero(session_media->mslabel)) {
|
if (ast_strlen_zero(session_media->mslabel)) {
|
||||||
if (ast_sip_session_is_pending_stream_default(session, stream)) {
|
/* If this stream is grouped with another then use its media stream label if possible */
|
||||||
int index;
|
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));
|
||||||
|
|
||||||
/* If this is a default stream we group them together under the same stream, but as different tracks */
|
ast_copy_string(session_media->mslabel, group_session_media->mslabel, sizeof(session_media->mslabel));
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
ast_copy_string(session_media->mslabel, other_session_media->mslabel, sizeof(session_media->mslabel));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ast_strlen_zero(session_media->mslabel)) {
|
if (ast_strlen_zero(session_media->mslabel)) {
|
||||||
|
@@ -399,6 +399,7 @@ static void session_media_dtor(void *obj)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ast_free(session_media->mid);
|
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,
|
struct ast_sip_session_media *ast_sip_session_media_state_add(struct ast_sip_session *session,
|
||||||
@@ -553,6 +554,70 @@ static int set_mid_and_bundle_group(struct ast_sip_session *session,
|
|||||||
return 0;
|
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,
|
static void remove_stream_from_bundle(struct ast_sip_session_media *session_media,
|
||||||
struct ast_stream *stream)
|
struct ast_stream *stream)
|
||||||
{
|
{
|
||||||
@@ -630,6 +695,7 @@ static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sd
|
|||||||
}
|
}
|
||||||
|
|
||||||
set_mid_and_bundle_group(session, session_media, sdp, remote_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) {
|
if (session_media->handler) {
|
||||||
handler = session_media->handler;
|
handler = session_media->handler;
|
||||||
@@ -730,6 +796,7 @@ static int handle_negotiated_sdp_session_media(struct ast_sip_session_media *ses
|
|||||||
ast_copy_pj_str(media, &local->media[index]->desc.media, sizeof(media));
|
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_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;
|
handler = session_media->handler;
|
||||||
if (handler) {
|
if (handler) {
|
||||||
|
Reference in New Issue
Block a user