summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bridges/bridge_simple.c38
-rw-r--r--include/asterisk/bridge.h3
-rw-r--r--include/asterisk/bridge_channel.h27
-rw-r--r--include/asterisk/bridge_technology.h19
-rw-r--r--include/asterisk/channel.h13
-rw-r--r--include/asterisk/channel_internal.h2
-rw-r--r--include/asterisk/stream.h23
-rw-r--r--main/bridge.c11
-rw-r--r--main/bridge_channel.c59
-rw-r--r--main/channel.c5
-rw-r--r--main/channel_internal_api.c12
-rw-r--r--main/stream.c45
-rw-r--r--tests/test_stream.c97
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;
}