diff options
-rw-r--r-- | bridges/bridge_simple.c | 38 | ||||
-rw-r--r-- | include/asterisk/bridge.h | 3 | ||||
-rw-r--r-- | include/asterisk/bridge_channel.h | 27 | ||||
-rw-r--r-- | include/asterisk/bridge_technology.h | 19 | ||||
-rw-r--r-- | include/asterisk/channel.h | 13 | ||||
-rw-r--r-- | include/asterisk/channel_internal.h | 2 | ||||
-rw-r--r-- | include/asterisk/stream.h | 23 | ||||
-rw-r--r-- | main/bridge.c | 11 | ||||
-rw-r--r-- | main/bridge_channel.c | 59 | ||||
-rw-r--r-- | main/channel.c | 5 | ||||
-rw-r--r-- | main/channel_internal_api.c | 12 | ||||
-rw-r--r-- | main/stream.c | 45 | ||||
-rw-r--r-- | tests/test_stream.c | 97 |
13 files changed, 348 insertions, 6 deletions
diff --git a/bridges/bridge_simple.c b/bridges/bridge_simple.c index 35544f84f..47f41cbb3 100644 --- a/bridges/bridge_simple.c +++ b/bridges/bridge_simple.c @@ -42,6 +42,10 @@ #include "asterisk/bridge.h" #include "asterisk/bridge_technology.h" #include "asterisk/frame.h" +#include "asterisk/stream.h" + +static void simple_bridge_stream_topology_changed(struct ast_bridge *bridge, + struct ast_bridge_channel *bridge_channel); static int simple_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) { @@ -56,7 +60,13 @@ static int simple_bridge_join(struct ast_bridge *bridge, struct ast_bridge_chann return 0; } - return ast_channel_make_compatible(c0, c1); + if (ast_channel_make_compatible(c0, c1)) { + return -1; + } + + /* Align stream topologies */ + simple_bridge_stream_topology_changed(bridge, NULL); + return 0; } static int simple_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame) @@ -70,8 +80,34 @@ static struct ast_bridge_technology simple_bridge = { .preference = AST_BRIDGE_PREFERENCE_BASE_1TO1MIX, .join = simple_bridge_join, .write = simple_bridge_write, + .stream_topology_changed = simple_bridge_stream_topology_changed, }; +static void simple_bridge_stream_topology_changed(struct ast_bridge *bridge, + struct ast_bridge_channel *bridge_channel) +{ + struct ast_channel *c0 = AST_LIST_FIRST(&bridge->channels)->chan; + struct ast_channel *c1 = AST_LIST_LAST(&bridge->channels)->chan; + struct ast_stream_topology *t0 = ast_channel_get_stream_topology(c0); + struct ast_stream_topology *t1 = ast_channel_get_stream_topology(c1); + + /* + * The bridge_channel should only be NULL after both channels join + * the bridge and their topologies are being aligned. + */ + if (bridge_channel && ast_channel_get_stream_topology_change_source( + bridge_channel->chan) == &simple_bridge) { + return; + } + + /* Align topologies according to size or first channel to join */ + if (ast_stream_topology_get_count(t0) < ast_stream_topology_get_count(t1)) { + ast_channel_request_stream_topology_change(c0, t1, &simple_bridge); + } else { + ast_channel_request_stream_topology_change(c1, t0, &simple_bridge); + } +} + static int unload_module(void) { ast_bridge_technology_unregister(&simple_bridge); diff --git a/include/asterisk/bridge.h b/include/asterisk/bridge.h index ffe08da13..a9b01a6bb 100644 --- a/include/asterisk/bridge.h +++ b/include/asterisk/bridge.h @@ -323,6 +323,9 @@ struct ast_bridge { /*! Immutable bridge UUID. */ AST_STRING_FIELD(uniqueid); ); + + /*! Type mapping used for media routing */ + struct ast_vector_int media_types; }; /*! \brief Bridge base class virtual method table. */ diff --git a/include/asterisk/bridge_channel.h b/include/asterisk/bridge_channel.h index a7971df27..dd72f3275 100644 --- a/include/asterisk/bridge_channel.h +++ b/include/asterisk/bridge_channel.h @@ -183,6 +183,12 @@ struct ast_bridge_channel { unsigned int padding:30; }; }; + struct { + /*! An index mapping of where a channel's media needs to be routed */ + struct ast_vector_int to_bridge; + /*! An index mapping of where a bridge's media needs to be routed */ + struct ast_vector_int to_channel; + } stream_map; }; /*! @@ -704,6 +710,27 @@ void ast_bridge_channel_feature_digit_add(struct ast_bridge_channel *bridge_chan */ void ast_bridge_channel_feature_digit(struct ast_bridge_channel *bridge_channel, int digit); +/*! + * \brief Maps a channel's stream topology to and from the bridge + * \since 15.0.0 + * + * When a channel joins a bridge or its associated stream topology is updated, each stream + * in the topology needs to be mapped according to its media type to the bridge. Calling + * this method creates a mapping of each stream on the channel indexed to the bridge's + * supported media types and vice versa (i.e. bridge's media types indexed to channel + * streams). + * + * The first channel to join the bridge creates the initial order for the bridge's media + * types (e.g. a one to one mapping is made). Subsequently added channels are mapped to + * that order adding more media types if/when the newly added channel has more streams + * and/or media types specified by the bridge. + * + * \param bridge_channel Channel to map + * + * \return Nothing + */ +void ast_bridge_channel_stream_map(struct ast_bridge_channel *bridge_channel); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/include/asterisk/bridge_technology.h b/include/asterisk/bridge_technology.h index 843d93ccf..09b0fc0e8 100644 --- a/include/asterisk/bridge_technology.h +++ b/include/asterisk/bridge_technology.h @@ -158,6 +158,25 @@ struct ast_bridge_technology { * \note On entry, bridge is already locked. */ int (*write)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame); + /*! + * \brief Callback for when a request has been made to change a stream topology on a channel + * + * This is called when a bridge receives a request to change the topology on the channel. A bridge + * technology should define a handler for this callback if it needs to update internals or intercept + * the request and not pass it on to other channels. This can be done by returning a nonzero value. + * + * \retval 0 Frame accepted by the bridge. + * \retval -1 Frame rejected. + */ + int (*stream_topology_request_change)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel); + /*! + * \brief Callback for when a stream topology changes on the channel + * + * This is called when a bridge receives an indication that a topology has been changed on a channel + * and the new topology has been mapped to the bridge. A bridge technology should define a handler for + * this callback if it needs to update internals due to a channel's topology changing. + */ + void (*stream_topology_changed)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel); /*! TRUE if the bridge technology is currently suspended. */ unsigned int suspended:1; /*! Module this bridge technology belongs to. It is used for reference counting bridges using the technology. */ diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 128cd3056..889d3ff07 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -4904,6 +4904,7 @@ int ast_channel_is_multistream(struct ast_channel *chan); * * \param chan The channel to change * \param topology The new stream topology + * \param change_source The source that initiated the change * * \pre chan is locked * @@ -4918,7 +4919,8 @@ int ast_channel_is_multistream(struct ast_channel *chan); * \note This interface is provided for applications and resources to request that the topology change. * It is not for use by the channel driver itself. */ -int ast_channel_request_stream_topology_change(struct ast_channel *chan, struct ast_stream_topology *topology); +int ast_channel_request_stream_topology_change(struct ast_channel *chan, + struct ast_stream_topology *topology, void *change_source); /*! * \brief Provide notice to a channel that the stream topology has changed @@ -4936,4 +4938,13 @@ int ast_channel_request_stream_topology_change(struct ast_channel *chan, struct */ int ast_channel_stream_topology_changed(struct ast_channel *chan, struct ast_stream_topology *topology); +/*! + * \brief Retrieve the source that initiated the last stream topology change + * + * \param chan The channel + * + * \retval The channel's stream topology change source + */ +void *ast_channel_get_stream_topology_change_source(struct ast_channel *chan); + #endif /* _ASTERISK_CHANNEL_H */ diff --git a/include/asterisk/channel_internal.h b/include/asterisk/channel_internal.h index 3de2b14aa..dd791a416 100644 --- a/include/asterisk/channel_internal.h +++ b/include/asterisk/channel_internal.h @@ -29,5 +29,7 @@ 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_set_stream_topology_change_source( + struct ast_channel *chan, void *change_source); 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 1e07407a9..1bb34b72a 100644 --- a/include/asterisk/stream.h +++ b/include/asterisk/stream.h @@ -27,6 +27,7 @@ #define _AST_STREAM_H_ #include "asterisk/codec.h" +#include "asterisk/vector.h" /*! * \brief Forward declaration for a stream, as it is opaque @@ -43,6 +44,11 @@ struct ast_format_cap; */ struct ast_stream_topology; +/*! + * \brief A mapping of two topologies. + */ +struct ast_stream_topology_map; + typedef void (*ast_stream_data_free_fn)(void *); /*! @@ -405,4 +411,21 @@ struct ast_stream *ast_stream_topology_get_first_stream_by_type( const struct ast_stream_topology *topology, enum ast_media_type type); +/*! + * \brief Map a given topology's streams to the given types. + * + * \note The given vectors in which mapping values are placed are reset by + * this function. This means if those vectors already contain mapping + * values they will be lost. + * + * \param topology The topology to map + * \param types The media types to be mapped + * \param v0 Index mapping of topology to types + * \param v1 Index mapping of types to topology + * + * \since 15 + */ +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); + #endif /* _AST_STREAM_H */ diff --git a/main/bridge.c b/main/bridge.c index d40c3ec9a..9d9a3118b 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -440,6 +440,13 @@ static void bridge_channel_complete_join(struct ast_bridge *bridge, struct ast_b } bridge_channel->just_joined = 0; + + /* + * When a channel joins the bridge its streams need to be mapped to the bridge's + * media types vector. This way all streams map to the same media type index for + * a given channel. + */ + ast_bridge_channel_stream_map(bridge_channel); } /*! @@ -689,6 +696,8 @@ static void destroy_bridge(void *obj) bridge->technology = NULL; } + AST_VECTOR_FREE(&bridge->media_types); + bridge->callid = 0; cleanup_video_mode(bridge); @@ -744,6 +753,8 @@ struct ast_bridge *bridge_alloc(size_t size, const struct ast_bridge_methods *v_ bridge->v_table = v_table; + AST_VECTOR_INIT(&bridge->media_types, AST_MEDIA_TYPE_END); + return bridge; } diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 89222d365..4f166fff0 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -55,6 +55,7 @@ #include "asterisk/causes.h" #include "asterisk/test.h" #include "asterisk/sem.h" +#include "asterisk/stream.h" /*! * \brief Used to queue an action frame onto a bridge channel and write an action frame into a bridge. @@ -982,6 +983,16 @@ int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, st return 0; } + if (ast_channel_is_multistream(bridge_channel->chan) && + (fr->frametype == AST_FRAME_IMAGE || fr->frametype == AST_FRAME_TEXT || + fr->frametype == AST_FRAME_VIDEO || fr->frametype == AST_FRAME_VOICE)) { + /* Media frames need to be mapped to an appropriate write stream */ + dup->stream_num = AST_VECTOR_GET( + &bridge_channel->stream_map.to_bridge, fr->stream_num); + } else { + dup->stream_num = -1; + } + AST_LIST_INSERT_TAIL(&bridge_channel->wr_queue, dup, frame_list); if (ast_alertpipe_write(bridge_channel->alert_pipe)) { ast_log(LOG_ERROR, "We couldn't write alert pipe for %p(%s)... something is VERY wrong\n", @@ -2249,6 +2260,9 @@ static void bridge_channel_handle_control(struct ast_bridge_channel *bridge_chan /* Should never happen. */ ast_assert(0); break; + case AST_CONTROL_STREAM_TOPOLOGY_CHANGED: + ast_indicate_data(chan, fr->subclass.integer, fr->data.ptr, fr->datalen); + break; default: ast_indicate_data(chan, fr->subclass.integer, fr->data.ptr, fr->datalen); break; @@ -2268,6 +2282,7 @@ static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channe { struct ast_frame *fr; struct sync_payload *sync_payload; + int num; ast_bridge_channel_lock(bridge_channel); @@ -2324,9 +2339,18 @@ static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channe case AST_FRAME_NULL: break; default: + if (fr->stream_num >= (int)AST_VECTOR_SIZE(&bridge_channel->stream_map.to_channel)) { + /* Nowhere to write to, so drop it */ + break; + } + + /* Find what stream number to write to for the channel */ + num = fr->stream_num < 0 ? -1 : + AST_VECTOR_GET(&bridge_channel->stream_map.to_channel, fr->stream_num); + /* Write the frame to the channel. */ bridge_channel->activity = BRIDGE_CHANNEL_THREAD_SIMPLE; - ast_write(bridge_channel->chan, fr); + ast_write_stream(bridge_channel->chan, num, fr); break; } bridge_frame_free(fr); @@ -2435,6 +2459,27 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel) case AST_CONTROL_ANSWER: ast_channel_publish_dial(NULL, bridge_channel->chan, NULL, controls[frame->subclass.integer]); break; + case AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE: + if (bridge_channel->bridge->technology->stream_topology_request_change && + bridge_channel->bridge->technology->stream_topology_request_change( + bridge_channel->bridge, bridge_channel)) { + /* Topology change was denied so drop frame */ + bridge_frame_free(frame); + return; + } + break; + case AST_CONTROL_STREAM_TOPOLOGY_CHANGED: + /* + * If a stream topology has changed then the bridge_channel's + * media mapping needs to be updated. + */ + ast_bridge_channel_stream_map(bridge_channel); + + if (bridge_channel->bridge->technology->stream_topology_changed) { + bridge_channel->bridge->technology->stream_topology_changed( + bridge_channel->bridge, bridge_channel); + } + break; default: break; } @@ -2885,6 +2930,9 @@ static void bridge_channel_destroy(void *obj) ao2_cleanup(bridge_channel->write_format); ao2_cleanup(bridge_channel->read_format); + + AST_VECTOR_FREE(&bridge_channel->stream_map.to_bridge); + AST_VECTOR_FREE(&bridge_channel->stream_map.to_channel); } struct ast_bridge_channel *bridge_channel_internal_alloc(struct ast_bridge *bridge) @@ -2905,5 +2953,14 @@ struct ast_bridge_channel *bridge_channel_internal_alloc(struct ast_bridge *brid ao2_ref(bridge_channel->bridge, +1); } + /* The stream_map is initialized later - see ast_bridge_channel_stream_map */ + return bridge_channel; } + +void ast_bridge_channel_stream_map(struct ast_bridge_channel *bridge_channel) +{ + ast_stream_topology_map(ast_channel_get_stream_topology(bridge_channel->chan), + &bridge_channel->bridge->media_types, &bridge_channel->stream_map.to_bridge, + &bridge_channel->stream_map.to_channel); +} diff --git a/main/channel.c b/main/channel.c index e37d66525..dbf235499 100644 --- a/main/channel.c +++ b/main/channel.c @@ -10909,7 +10909,8 @@ enum ast_channel_error ast_channel_errno(void) return ast_channel_internal_errno(); } -int ast_channel_request_stream_topology_change(struct ast_channel *chan, struct ast_stream_topology *topology) +int ast_channel_request_stream_topology_change(struct ast_channel *chan, + struct ast_stream_topology *topology, void *change_source) { ast_assert(chan != NULL); ast_assert(topology != NULL); @@ -10918,6 +10919,8 @@ int ast_channel_request_stream_topology_change(struct ast_channel *chan, struct return -1; } + ast_channel_internal_set_stream_topology_change_source(chan, change_source); + return ast_channel_tech(chan)->indicate(chan, AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE, topology, sizeof(topology)); } diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index 7f32b2196..5e7df8983 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -219,6 +219,7 @@ struct ast_channel { 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 */ + void *stream_topology_change_source; /*!< Source that initiated a stream topology change */ struct ast_stream *default_streams[AST_MEDIA_TYPE_END]; /*!< Default streams indexed by media type */ }; @@ -838,6 +839,17 @@ void ast_channel_internal_set_stream_topology(struct ast_channel *chan, channel_set_default_streams(chan); } +void ast_channel_internal_set_stream_topology_change_source( + struct ast_channel *chan, void *change_source) +{ + chan->stream_topology_change_source = change_source; +} + +void *ast_channel_get_stream_topology_change_source(struct ast_channel *chan) +{ + return chan->stream_topology_change_source; +} + void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value) { diff --git a/main/stream.c b/main/stream.c index 39b6b1b13..0f2393359 100644 --- a/main/stream.c +++ b/main/stream.c @@ -434,3 +434,48 @@ struct ast_stream *ast_stream_topology_get_first_stream_by_type( return NULL; } + +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) +{ + int i; + int nths[AST_MEDIA_TYPE_END] = {0}; + int size = ast_stream_topology_get_count(topology); + + /* + * Clear out any old mappings and initialize the new ones + */ + AST_VECTOR_FREE(v0); + AST_VECTOR_FREE(v1); + + /* + * Both vectors are sized to the topology. The media types vector is always + * guaranteed to be the size of the given topology or greater. + */ + AST_VECTOR_INIT(v0, size); + AST_VECTOR_INIT(v1, size); + + for (i = 0; i < size; ++i) { + struct ast_stream *stream = ast_stream_topology_get_stream(topology, i); + enum ast_media_type type = ast_stream_get_type(stream); + int index = AST_VECTOR_GET_INDEX_NTH(types, ++nths[type], + type, AST_VECTOR_ELEM_DEFAULT_CMP); + + if (index == -1) { + /* + * If a given type is not found for an index level then update the + * media types vector with that type. This keeps the media types + * vector always at the max topology size. + */ + AST_VECTOR_APPEND(types, type); + index = AST_VECTOR_SIZE(types) - 1; + } + + /* + * The mapping is reflexive in the sense that if it maps in one direction + * then the reverse direction maps back to the other's index. + */ + AST_VECTOR_REPLACE(v0, i, index); + AST_VECTOR_REPLACE(v1, index, i); + } +} diff --git a/tests/test_stream.c b/tests/test_stream.c index 7eecf373b..a2a970181 100644 --- a/tests/test_stream.c +++ b/tests/test_stream.c @@ -1592,7 +1592,7 @@ AST_TEST_DEFINE(stream_topology_change_request_from_application_non_multistream) topology = ast_stream_topology_alloc(); ast_test_validate_cleanup(test, topology, res, done); - change_res = ast_channel_request_stream_topology_change(mock_channel, topology); + change_res = ast_channel_request_stream_topology_change(mock_channel, topology, NULL); ast_test_validate_cleanup(test, change_res == -1, res, done); ast_test_validate_cleanup(test, !pvt->indicated_change_request, res, done); @@ -1700,7 +1700,7 @@ AST_TEST_DEFINE(stream_topology_change_request_from_application) topology = ast_stream_topology_alloc(); ast_test_validate_cleanup(test, topology, res, done); - change_res = ast_channel_request_stream_topology_change(mock_channel, topology); + change_res = ast_channel_request_stream_topology_change(mock_channel, topology, NULL); ast_test_validate_cleanup(test, !change_res, res, done); ast_test_validate_cleanup(test, pvt->indicated_change_request, res, done); @@ -1830,6 +1830,97 @@ AST_TEST_DEFINE(format_cap_from_stream_topology) return AST_TEST_PASS; } +#define topology_append_stream(topology, name, type, res, label) \ + do { \ + struct ast_stream *__stream = ast_stream_alloc((name), (type)); \ + ast_test_validate_cleanup(test, __stream, res, label); \ + if (ast_stream_topology_append_stream((topology), __stream) < 0) { \ + ast_stream_free(__stream); \ + res = AST_TEST_FAIL; \ + goto label; \ + } \ + } while(0) + +AST_TEST_DEFINE(stream_topology_map_create) +{ + RAII_VAR(struct ast_stream_topology *, t0, NULL, ast_stream_topology_free); + + struct ast_vector_int types = { NULL }; + struct ast_vector_int v0 = { NULL }; + struct ast_vector_int v1 = { NULL }; + + enum ast_test_result_state res = AST_TEST_PASS; + + switch (cmd) { + case TEST_INIT: + info->name = "stream_topology_map_create"; + info->category = "/main/stream/"; + info->summary = "stream topology map creation unit test"; + info->description = + "Test that creating a stream topology map works"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + ast_test_validate(test, AST_VECTOR_INIT(&types, 5) == 0); + + /* Map a first topology and check that it mapped one to one */ + ast_test_validate_cleanup(test, (t0 = ast_stream_topology_alloc()), res, done); + topology_append_stream(t0, "audio", AST_MEDIA_TYPE_AUDIO, res, done); + topology_append_stream(t0, "video", AST_MEDIA_TYPE_VIDEO, res, done); + + ast_stream_topology_map(t0, &types, &v0, &v1); + ast_test_validate_cleanup(test, AST_VECTOR_SIZE(&types) == 2, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&types, 0) == AST_MEDIA_TYPE_AUDIO, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&types, 1) == AST_MEDIA_TYPE_VIDEO, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v0, 0) == 0, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v0, 1) == 1, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v1, 0) == 0, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v1, 1) == 1, res, done); + + /* Map a second topology and check that it merged */ + ast_stream_topology_free(t0); + ast_test_validate_cleanup(test, (t0 = ast_stream_topology_alloc()), res, done); + topology_append_stream(t0, "video", AST_MEDIA_TYPE_VIDEO, res, done); + topology_append_stream(t0, "audio", AST_MEDIA_TYPE_AUDIO, res, done); + + ast_stream_topology_map(t0, &types, &v0, &v1); + ast_test_validate_cleanup(test, AST_VECTOR_SIZE(&types) == 2, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&types, 0) == AST_MEDIA_TYPE_AUDIO, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&types, 1) == AST_MEDIA_TYPE_VIDEO, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v0, 0) == 1, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v0, 1) == 0, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v1, 0) == 1, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v1, 1) == 0, res, done); + + /* Map a third topology with more streams and check that it merged */ + ast_stream_topology_free(t0); + ast_test_validate_cleanup(test, (t0 = ast_stream_topology_alloc()), res, done); + topology_append_stream(t0, "video", AST_MEDIA_TYPE_VIDEO, res, done); + topology_append_stream(t0, "audio", AST_MEDIA_TYPE_AUDIO, res, done); + topology_append_stream(t0, "audio", AST_MEDIA_TYPE_AUDIO, res, done); + + ast_stream_topology_map(t0, &types, &v0, &v1); + ast_test_validate_cleanup(test, AST_VECTOR_SIZE(&types) == 3, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&types, 0) == AST_MEDIA_TYPE_AUDIO, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&types, 1) == AST_MEDIA_TYPE_VIDEO, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&types, 2) == AST_MEDIA_TYPE_AUDIO, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v0, 0) == 1, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v0, 1) == 0, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v0, 2) == 2, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v1, 0) == 1, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v1, 1) == 0, res, done); + ast_test_validate_cleanup(test, AST_VECTOR_GET(&v1, 2) == 2, res, done); + +done: + AST_VECTOR_FREE(&v1); + AST_VECTOR_FREE(&v0); + AST_VECTOR_FREE(&types); + + return res; +} + static int unload_module(void) { AST_TEST_UNREGISTER(stream_create); @@ -1855,6 +1946,7 @@ static int unload_module(void) AST_TEST_UNREGISTER(stream_topology_change_request_from_application); AST_TEST_UNREGISTER(stream_topology_change_request_from_channel); AST_TEST_UNREGISTER(format_cap_from_stream_topology); + AST_TEST_UNREGISTER(stream_topology_map_create); return 0; } @@ -1882,6 +1974,7 @@ static int load_module(void) AST_TEST_REGISTER(stream_topology_change_request_from_application); AST_TEST_REGISTER(stream_topology_change_request_from_channel); AST_TEST_REGISTER(format_cap_from_stream_topology); + AST_TEST_REGISTER(stream_topology_map_create); return AST_MODULE_LOAD_SUCCESS; } |