From bf2f091bbb2b099d6ca87e5fdd76efe45a209eb7 Mon Sep 17 00:00:00 2001 From: George Joseph <gjoseph@digium.com> Date: Mon, 13 Feb 2017 10:50:47 -0700 Subject: [PATCH] stream: Add stream topology to channel Adds topology set and get to channel. ASTERISK-26790 Change-Id: Ic379ea82a9486fc79dbd8c4d95c29fa3b46424f4 --- include/asterisk/channel.h | 34 +++++++++ include/asterisk/channel_internal.h | 4 ++ include/asterisk/stream.h | 15 ++++ main/channel.c | 9 +++ main/channel_internal_api.c | 103 +++++++++++++++++++++++++++- main/stream.c | 19 +++++ tests/test_voicemail_api.c | 4 +- 7 files changed, 185 insertions(+), 3 deletions(-) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index e5f792f1f4..4170a8af45 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -884,6 +884,10 @@ enum { * world */ AST_CHAN_TP_INTERNAL = (1 << 2), + /*! + * \brief Channels with this particular technology support multiple simultaneous streams + */ + AST_CHAN_TP_MULTISTREAM = (1 << 3), }; /*! \brief ast_channel flags */ @@ -4734,4 +4738,34 @@ enum ast_channel_error ast_channel_errno(void); */ int ast_channel_get_intercept_mode(void); +/*! + * \brief Retrieve the topology of streams on a channel + * + * \param chan The channel to get the stream topology of + * + * \pre chan is locked + * + * \retval non-NULL success + * \retval NULL failure + */ +struct ast_stream_topology *ast_channel_get_stream_topology( + const struct ast_channel *chan); + +/*! + * \brief Set the topology of streams on a channel + * + * \param chan The channel to set the stream topology on + * \param topology The stream topology to set + * + * \pre chan is locked + * + * \note If topology is NULL a new empty topology will be created + * and returned. + * + * \retval non-NULL Success + * \retval NULL failure + */ +struct ast_stream_topology *ast_channel_set_stream_topology( + struct ast_channel *chan, struct ast_stream_topology *topology); + #endif /* _ASTERISK_CHANNEL_H */ diff --git a/include/asterisk/channel_internal.h b/include/asterisk/channel_internal.h index 2316e2f24c..3de2b14aa1 100644 --- a/include/asterisk/channel_internal.h +++ b/include/asterisk/channel_internal.h @@ -27,3 +27,7 @@ int ast_channel_internal_setup_topics(struct ast_channel *chan); void ast_channel_internal_errno_set(enum ast_channel_error error); enum ast_channel_error ast_channel_internal_errno(void); +void ast_channel_internal_set_stream_topology(struct ast_channel *chan, + struct ast_stream_topology *topology); +void ast_channel_internal_swap_stream_topology(struct ast_channel *chan1, + struct ast_channel *chan2); diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h index cffe6ea4cb..9fb4660135 100644 --- a/include/asterisk/stream.h +++ b/include/asterisk/stream.h @@ -316,4 +316,19 @@ int ast_stream_topology_set_stream(struct ast_stream_topology *topology, struct ast_stream_topology *ast_stream_topology_create_from_format_cap( struct ast_format_cap *cap); +/*! + * \brief Gets the first stream of a specific type from the topology + * + * \param topology The topology of streams + * \param type The media type + * + * \retval non-NULL success + * \retval NULL failure + * + * \since 15 + */ +struct ast_stream *ast_stream_topology_get_first_stream_by_type( + const struct ast_stream_topology *topology, + enum ast_media_type type); + #endif /* _AST_STREAM_H */ diff --git a/main/channel.c b/main/channel.c index 2349193365..fa92508ace 100644 --- a/main/channel.c +++ b/main/channel.c @@ -73,6 +73,7 @@ #include "asterisk/test.h" #include "asterisk/stasis_channels.h" #include "asterisk/max_forwards.h" +#include "asterisk/stream.h" /*** DOCUMENTATION ***/ @@ -806,6 +807,7 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char struct ast_timer *timer; struct timeval now; const struct ast_channel_tech *channel_tech; + struct ast_stream_topology *topology; /* If shutting down, don't allocate any new channels */ if (ast_shutting_down()) { @@ -886,6 +888,11 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char return ast_channel_unref(tmp); } + if (!(topology = ast_stream_topology_create())) { + return ast_channel_unref(tmp); + } + ast_channel_internal_set_stream_topology(tmp, topology); + /* Always watch the alertpipe */ ast_channel_set_fd(tmp, AST_ALERT_FD, ast_channel_internal_alert_readfd(tmp)); /* And timing pipe */ @@ -7074,6 +7081,8 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann ast_channel_tech(clonechan)->type, ast_channel_name(clonechan)); } + ast_channel_internal_swap_stream_topology(original, clonechan); + /* * Now, at this point, the "clone" channel is totally F'd up. * We mark it as a zombie so nothing tries to touch it. diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index a0cbe86437..235b99604b 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -46,6 +46,7 @@ #include "asterisk/stasis_channels.h" #include "asterisk/stasis_endpoints.h" #include "asterisk/stringfields.h" +#include "asterisk/stream.h" #include "asterisk/test.h" /*! @@ -221,6 +222,8 @@ struct ast_channel { struct stasis_cp_single *topics; /*!< Topic for all channel's events */ struct stasis_forward *endpoint_forward; /*!< Subscription for event forwarding to endpoint's topic */ struct stasis_forward *endpoint_cache_forward; /*!< Subscription for cache updates to endpoint's topic */ + struct ast_stream_topology *stream_topology; /*!< Stream topology */ + struct ast_stream *default_streams[AST_MEDIA_TYPE_END]; /*!< Default streams indexed by media type */ }; /*! \brief The monotonically increasing integer counter for channel uniqueids */ @@ -825,10 +828,57 @@ struct ast_format_cap *ast_channel_nativeformats(const struct ast_channel *chan) { return chan->nativeformats; } -void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value) + +static void channel_set_default_streams(struct ast_channel *chan) +{ + enum ast_media_type type; + + ast_assert(chan != NULL); + + for (type = AST_MEDIA_TYPE_UNKNOWN; type < AST_MEDIA_TYPE_END; type++) { + if (chan->stream_topology) { + chan->default_streams[type] = + ast_stream_topology_get_first_stream_by_type(chan->stream_topology, type); + } else { + chan->default_streams[type] = NULL; + } + } +} + +void ast_channel_internal_set_stream_topology(struct ast_channel *chan, + struct ast_stream_topology *topology) +{ + ast_stream_topology_destroy(chan->stream_topology); + chan->stream_topology = topology; + channel_set_default_streams(chan); +} + +void ast_channel_nativeformats_set(struct ast_channel *chan, + struct ast_format_cap *value) { + ast_assert(chan != NULL); + ao2_replace(chan->nativeformats, value); + + /* If chan->stream_topology is NULL, the channel is being destroyed + * and topology is destroyed. + */ + if (!chan->stream_topology) { + return; + } + + if (!chan->tech || !(chan->tech->properties & AST_CHAN_TP_MULTISTREAM) || !value) { + struct ast_stream_topology *new_topology; + + if (!value) { + new_topology = ast_stream_topology_create(); + } else { + new_topology = ast_stream_topology_create_from_format_cap(value); + } + ast_channel_internal_set_stream_topology(chan, new_topology); + } } + struct ast_framehook_list *ast_channel_framehooks(const struct ast_channel *chan) { return chan->framehooks; @@ -1637,6 +1687,8 @@ void ast_channel_internal_cleanup(struct ast_channel *chan) stasis_cp_single_unsubscribe(chan->topics); chan->topics = NULL; + + ast_channel_internal_set_stream_topology(chan, NULL); } void ast_channel_internal_finalize(struct ast_channel *chan) @@ -1729,3 +1781,52 @@ enum ast_channel_error ast_channel_internal_errno(void) return *error_code; } + +struct ast_stream_topology *ast_channel_get_stream_topology( + const struct ast_channel *chan) +{ + ast_assert(chan != NULL); + + return chan->stream_topology; +} + +struct ast_stream_topology *ast_channel_set_stream_topology(struct ast_channel *chan, + struct ast_stream_topology *topology) +{ + struct ast_stream_topology *new_topology; + + ast_assert(chan != NULL); + + /* A non-MULTISTREAM channel can't manipulate topology directly */ + ast_assert(chan->tech != NULL && (chan->tech->properties & AST_CHAN_TP_MULTISTREAM)); + + /* Unless the channel is being destroyed, we always want a topology on + * it even if its empty. + */ + if (!topology) { + new_topology = ast_stream_topology_create(); + } else { + new_topology = topology; + } + + if (new_topology) { + ast_channel_internal_set_stream_topology(chan, new_topology); + } + + return new_topology; +} + +void ast_channel_internal_swap_stream_topology(struct ast_channel *chan1, + struct ast_channel *chan2) +{ + struct ast_stream_topology *tmp_topology; + + ast_assert(chan1 != NULL && chan2 != NULL); + + tmp_topology = chan1->stream_topology; + chan1->stream_topology = chan2->stream_topology; + chan2->stream_topology = tmp_topology; + + channel_set_default_streams(chan1); + channel_set_default_streams(chan2); +} diff --git a/main/stream.c b/main/stream.c index 24844c4abe..5112c95936 100644 --- a/main/stream.c +++ b/main/stream.c @@ -337,3 +337,22 @@ struct ast_stream_topology *ast_stream_topology_create_from_format_cap( return topology; } + +struct ast_stream *ast_stream_topology_get_first_stream_by_type( + const struct ast_stream_topology *topology, + enum ast_media_type type) +{ + int i; + + ast_assert(topology != NULL); + + for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) { + struct ast_stream *stream = AST_VECTOR_GET(&topology->streams, i); + + if (stream->type == type) { + return stream; + } + } + + return NULL; +} diff --git a/tests/test_voicemail_api.c b/tests/test_voicemail_api.c index 802b6bf1b1..e46757263f 100644 --- a/tests/test_voicemail_api.c +++ b/tests/test_voicemail_api.c @@ -825,12 +825,12 @@ static struct ast_channel *test_vm_api_create_mock_channel(void) } ast_channel_set_writeformat(mock_channel, ast_format_gsm); - native_formats = ast_channel_nativeformats(mock_channel); - ast_format_cap_append(native_formats, ast_channel_writeformat(mock_channel), 0); ast_channel_set_rawwriteformat(mock_channel, ast_format_gsm); ast_channel_set_readformat(mock_channel, ast_format_gsm); ast_channel_set_rawreadformat(mock_channel, ast_format_gsm); ast_channel_tech_set(mock_channel, &mock_channel_tech); + native_formats = ast_channel_nativeformats(mock_channel); + ast_format_cap_append(native_formats, ast_channel_writeformat(mock_channel), 0); ast_channel_unlock(mock_channel); -- GitLab