diff options
-rw-r--r-- | apps/app_voicemail.c | 24 | ||||
-rw-r--r-- | formats/format_g729.c | 2 | ||||
-rw-r--r-- | include/asterisk/sdp_state.h | 4 | ||||
-rw-r--r-- | include/asterisk/stream.h | 28 | ||||
-rw-r--r-- | main/pbx_app.c | 7 | ||||
-rw-r--r-- | main/sdp_state.c | 56 | ||||
-rw-r--r-- | main/stream.c | 35 | ||||
-rw-r--r-- | tests/test_stream.c | 227 |
8 files changed, 353 insertions, 30 deletions
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 8f50e1106..a95168013 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -13134,10 +13134,25 @@ static void imap_logout(const char *mailbox_id) return; } + ast_mutex_lock(&vms->lock); vms->mailstream = mail_close(vms->mailstream); + ast_mutex_unlock(&vms->lock); + vmstate_delete(vms); } +static void imap_close_subscribed_mailboxes(void) +{ + struct mwi_sub *mwi_sub; + + AST_RWLIST_RDLOCK(&mwi_subs); + AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) { + if (!ast_strlen_zero(mwi_sub->mailbox)) { + imap_logout(mwi_sub->mailbox); + } + } + AST_RWLIST_UNLOCK(&mwi_subs); +} #endif static int handle_unsubscribe(void *datap) @@ -13591,7 +13606,11 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY); strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY); - /* Free all the users structure */ +#ifdef IMAP_STORAGE + imap_close_subscribed_mailboxes(); +#endif + + /* Free all the users structure */ free_vm_users(); /* Free all the zones structure */ @@ -14985,6 +15004,9 @@ static int unload_module(void) ast_unload_realtime("voicemail"); ast_unload_realtime("voicemail_data"); +#ifdef IMAP_STORAGE + imap_close_subscribed_mailboxes(); +#endif free_vm_users(); free_vm_zones(); return res; diff --git a/formats/format_g729.c b/formats/format_g729.c index 1e523062e..91dc855f1 100644 --- a/formats/format_g729.c +++ b/formats/format_g729.c @@ -19,7 +19,7 @@ /*! \file * * \brief Save to raw, headerless G729 data. - * \note This is not an encoder/decoder. The codec fo g729 is only + * \note This is not an encoder/decoder. The codec for g729 is only * available with a commercial license from Digium, due to patent * restrictions. Check http://www.digium.com for information. * \arg Extensions: g729 diff --git a/include/asterisk/sdp_state.h b/include/asterisk/sdp_state.h index c2122fbce..b8209e1d5 100644 --- a/include/asterisk/sdp_state.h +++ b/include/asterisk/sdp_state.h @@ -146,6 +146,10 @@ const void *ast_sdp_state_get_local_sdp_impl(struct ast_sdp_state *sdp_state); * \param sdp_state * \param sdp * + * \note It is assumed that the passed in SDP has been checked for sanity + * already. e.g., There are no syntax errors, a c= line is reachable for + * each m= line, etc... + * * \retval 0 Success * \retval non-0 Failure * diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h index fcee3e47b..00169a3f1 100644 --- a/include/asterisk/stream.h +++ b/include/asterisk/stream.h @@ -359,6 +359,25 @@ int ast_stream_topology_set_stream(struct ast_stream_topology *topology, unsigned int position, struct ast_stream *stream); /*! + * \brief Delete a specified stream from the given topology. + * \since 15.0.0 + * + * \param topology The topology of streams. + * \param position The topology position to delete. + * + * \note Deleting a stream will completely remove it from the topology + * as if it never existed in it. i.e., Any following stream positions + * will shift down so there is no gap. + * + * \retval 0 on success. + * \retval -1 on failure. + * + * \return Nothing + */ +int ast_stream_topology_del_stream(struct ast_stream_topology *topology, + unsigned int position); + +/*! * \brief A helper function that, given a format capabilities structure, * creates a topology and separates the media types in format_cap into * separate streams. @@ -382,8 +401,11 @@ struct ast_stream_topology *ast_stream_topology_create_from_format_cap( struct ast_format_cap *cap); /*! - * \brief A helper function that, given a stream topology, creates a format - * capabilities structure containing all formats from all streams. + * \brief Create a format capabilities structure representing the topology. + * + * \details + * A helper function that, given a stream topology, creates a format + * capabilities structure containing all formats from all active streams. * * \param topology The topology of streams * @@ -398,7 +420,7 @@ struct ast_format_cap *ast_format_cap_from_stream_topology( struct ast_stream_topology *topology); /*! - * \brief Gets the first stream of a specific type from the topology + * \brief Gets the first active stream of a specific type from the topology * * \param topology The topology of streams * \param type The media type diff --git a/main/pbx_app.c b/main/pbx_app.c index e0609db70..ec6bc7589 100644 --- a/main/pbx_app.c +++ b/main/pbx_app.c @@ -394,6 +394,11 @@ int ast_unregister_application(const char *app) struct ast_app *cur; int cmp; + /* Anticipate need for conlock in unreference_cached_app(), in order to avoid + * possible deadlock with pbx_extension_helper()/pbx_findapp() + */ + ast_rdlock_contexts(); + AST_RWLIST_WRLOCK(&apps); AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) { cmp = strcasecmp(app, cur->name); @@ -416,6 +421,8 @@ int ast_unregister_application(const char *app) AST_RWLIST_TRAVERSE_SAFE_END; AST_RWLIST_UNLOCK(&apps); + ast_unlock_contexts(); + return cur ? 0 : -1; } diff --git a/main/sdp_state.c b/main/sdp_state.c index 00f147f47..0f06bf9e3 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -875,6 +875,7 @@ static void update_ice(const struct ast_sdp_state *state, struct ast_rtp_instanc { struct ast_rtp_engine_ice *ice; const struct ast_sdp_a_line *attr; + const struct ast_sdp_a_line *attr_rtcp_mux; unsigned int attr_i; /* If ICE support is not enabled or available exit early */ @@ -902,10 +903,12 @@ static void update_ice(const struct ast_sdp_state *state, struct ast_rtp_instanc return; } - if (ast_sdp_m_find_attribute(remote_m_line, "ice-lite", -1)) { + if (ast_sdp_find_attribute(remote_sdp, "ice-lite", -1)) { ice->ice_lite(rtp); } + attr_rtcp_mux = ast_sdp_m_find_attribute(remote_m_line, "rtcp-mux", -1); + /* Find all of the candidates */ for (attr_i = 0; attr_i < ast_sdp_m_get_a_count(remote_m_line); ++attr_i) { char foundation[32]; @@ -931,9 +934,9 @@ static void update_ice(const struct ast_sdp_state *state, struct ast_rtp_instanc continue; } - if (ast_sdp_options_get_rtcp_mux(options) - && ast_sdp_m_find_attribute(remote_m_line, "rtcp-mux", -1) - && candidate.id > 1) { + if (candidate.id > 1 + && attr_rtcp_mux + && ast_sdp_options_get_rtcp_mux(options)) { /* Remote side may have offered RTP and RTCP candidates. However, if we're using RTCP MUX, * then we should ignore RTCP candidates. */ @@ -997,11 +1000,32 @@ static void update_rtp_after_merge(const struct ast_sdp_state *state, const struct ast_sdp *remote_sdp, const struct ast_sdp_m_line *remote_m_line) { + struct ast_sdp_c_line *c_line; + struct ast_sockaddr *addrs; + if (!rtp) { /* This is a dummy stream */ return; } + c_line = remote_m_line->c_line; + if (!c_line) { + c_line = remote_sdp->c_line; + } + /* + * There must be a c= line somewhere but that would be an error by + * the far end that should have been caught by a validation check + * before we processed the SDP. + */ + ast_assert(c_line != NULL); + + if (ast_sockaddr_resolve(&addrs, c_line->address, PARSE_PORT_FORBID, AST_AF_UNSPEC) > 0) { + /* Apply connection information to the RTP instance */ + ast_sockaddr_set_port(addrs, remote_m_line->port); + ast_rtp_instance_set_remote_address(rtp->instance, addrs); + ast_free(addrs); + } + if (ast_sdp_options_get_rtcp_mux(options) && ast_sdp_m_find_attribute(remote_m_line, "rtcp-mux", -1)) { ast_rtp_instance_set_prop(rtp->instance, AST_RTP_PROPERTY_RTCP, @@ -1011,9 +1035,7 @@ static void update_rtp_after_merge(const struct ast_sdp_state *state, AST_RTP_INSTANCE_RTCP_STANDARD); } - if (ast_sdp_options_get_ice(options) == AST_SDP_ICE_ENABLED_STANDARD) { - update_ice(state, rtp->instance, options, remote_sdp, remote_m_line); - } + update_ice(state, rtp->instance, options, remote_sdp, remote_m_line); } /*! @@ -1066,12 +1088,19 @@ static void update_udptl_after_merge(const struct ast_sdp_state *state, struct s } } - c_line = remote_sdp->c_line; - if (remote_m_line->c_line) { - c_line = remote_m_line->c_line; + c_line = remote_m_line->c_line; + if (!c_line) { + c_line = remote_sdp->c_line; } + /* + * There must be a c= line somewhere but that would be an error by + * the far end that should have been caught by a validation check + * before we processed the SDP. + */ + ast_assert(c_line != NULL); if (ast_sockaddr_resolve(&addrs, c_line->address, PARSE_PORT_FORBID, AST_AF_UNSPEC) > 0) { + /* Apply connection information to the UDPTL instance */ ast_sockaddr_set_port(addrs, remote_m_line->port); ast_udptl_set_peer(udptl->instance, addrs); ast_free(addrs); @@ -1734,13 +1763,16 @@ static struct ast_sdp *sdp_create_from_state(const struct ast_sdp_state *sdp_sta if (!c_line) { goto error; } - s_line = ast_sdp_s_alloc(options->sdpsession); if (!s_line) { goto error; } + t_line = ast_sdp_t_alloc(0, 0); + if (!t_line) { + goto error; + } - sdp = ast_sdp_alloc(o_line, c_line, s_line, NULL); + sdp = ast_sdp_alloc(o_line, c_line, s_line, t_line); if (!sdp) { goto error; } diff --git a/main/stream.c b/main/stream.c index fb146931d..20179f331 100644 --- a/main/stream.c +++ b/main/stream.c @@ -349,6 +349,29 @@ int ast_stream_topology_set_stream(struct ast_stream_topology *topology, return AST_VECTOR_REPLACE(&topology->streams, position, stream); } +int ast_stream_topology_del_stream(struct ast_stream_topology *topology, + unsigned int position) +{ + struct ast_stream *stream; + + ast_assert(topology != NULL); + + if (AST_VECTOR_SIZE(&topology->streams) <= position) { + return -1; + } + + stream = AST_VECTOR_REMOVE_ORDERED(&topology->streams, position); + ast_stream_free(stream); + + /* Fix up higher stream position indices */ + for (; position < AST_VECTOR_SIZE(&topology->streams); ++position) { + stream = AST_VECTOR_GET(&topology->streams, position); + stream->position = position; + } + + return 0; +} + struct ast_stream_topology *ast_stream_topology_create_from_format_cap( struct ast_format_cap *cap) { @@ -414,9 +437,11 @@ struct ast_format_cap *ast_format_cap_from_stream_topology( } for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) { - struct ast_stream *stream = AST_VECTOR_GET(&topology->streams, i); + struct ast_stream *stream; - if (!stream->formats) { + stream = AST_VECTOR_GET(&topology->streams, i); + if (!stream->formats + || stream->state == AST_STREAM_STATE_REMOVED) { continue; } @@ -435,9 +460,11 @@ struct ast_stream *ast_stream_topology_get_first_stream_by_type( ast_assert(topology != NULL); for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) { - struct ast_stream *stream = AST_VECTOR_GET(&topology->streams, i); + struct ast_stream *stream; - if (stream->type == type) { + stream = AST_VECTOR_GET(&topology->streams, i); + if (stream->type == type + && stream->state != AST_STREAM_STATE_REMOVED) { return stream; } } diff --git a/tests/test_stream.c b/tests/test_stream.c index a2a970181..fdb988584 100644 --- a/tests/test_stream.c +++ b/tests/test_stream.c @@ -529,6 +529,146 @@ AST_TEST_DEFINE(stream_topology_set_stream) return AST_TEST_PASS; } +static int check_stream_positions(struct ast_test *test, const struct ast_stream_topology *topology) +{ + const struct ast_stream *stream; + int idx; + int pos; + enum ast_media_type type; + + for (idx = 0; idx < ast_stream_topology_get_count(topology); ++idx) { + stream = ast_stream_topology_get_stream(topology, idx); + pos = ast_stream_get_position(stream); + if (idx != pos) { + type = ast_stream_get_type(stream); + ast_test_status_update(test, "Failed: '%s' stream says it is at position %d instead of %d\n", + ast_codec_media_type2str(type), pos, idx); + return -1; + } + } + return 0; +} + +AST_TEST_DEFINE(stream_topology_del_stream) +{ + RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free); + struct ast_stream *stream; + enum ast_media_type type; + int idx; + + switch (cmd) { + case TEST_INIT: + info->name = "stream_topology_del_stream"; + info->category = "/main/stream/"; + info->summary = "stream topology stream delete unit test"; + info->description = + "Test that deleting streams at a specific position in a topology works"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + topology = ast_stream_topology_alloc(); + if (!topology) { + ast_test_status_update(test, "Failed to create media stream topology\n"); + return AST_TEST_FAIL; + } + + /* Create streams */ + for (type = AST_MEDIA_TYPE_UNKNOWN; type < AST_MEDIA_TYPE_END; ++type) { + stream = ast_stream_alloc(ast_codec_media_type2str(type), type); + if (!stream) { + ast_test_status_update(test, "Failed to create '%s' stream for testing stream topology\n", + ast_codec_media_type2str(type)); + return AST_TEST_FAIL; + } + if (ast_stream_topology_append_stream(topology, stream) == -1) { + ast_test_status_update(test, "Failed to append '%s' stream to topology\n", + ast_codec_media_type2str(type)); + ast_stream_free(stream); + return AST_TEST_FAIL; + } + } + + /* Check initial stream positions and types for sanity. */ + type = AST_MEDIA_TYPE_UNKNOWN; + for (idx = 0; idx < ast_stream_topology_get_count(topology); ++idx, ++type) { + stream = ast_stream_topology_get_stream(topology, idx); + if (type != ast_stream_get_type(stream)) { + ast_test_status_update(test, "Initial topology types failed: Expected:%s Got:%s\n", + ast_codec_media_type2str(type), + ast_codec_media_type2str(ast_stream_get_type(stream))); + return AST_TEST_FAIL; + } + } + if (check_stream_positions(test, topology)) { + ast_test_status_update(test, "Initial topology positions failed.\n"); + return AST_TEST_FAIL; + } + + /* Try to delete outside of topology size */ + if (!ast_stream_topology_del_stream(topology, ast_stream_topology_get_count(topology))) { + ast_test_status_update(test, "Deleting stream outside of topology succeeded!\n"); + return AST_TEST_FAIL; + } + + /* Try to delete the last topology stream */ + if (ast_stream_topology_del_stream(topology, ast_stream_topology_get_count(topology) - 1)) { + ast_test_status_update(test, "Failed deleting last stream of topology.\n"); + return AST_TEST_FAIL; + } + if (check_stream_positions(test, topology)) { + ast_test_status_update(test, "Last stream delete topology positions failed.\n"); + return AST_TEST_FAIL; + } + stream = ast_stream_topology_get_stream(topology, ast_stream_topology_get_count(topology) - 1); + type = ast_stream_get_type(stream); + if (type != AST_MEDIA_TYPE_END - 2) { + ast_test_status_update(test, "Last stream delete types failed: Expected:%s Got:%s\n", + ast_codec_media_type2str(AST_MEDIA_TYPE_END - 2), + ast_codec_media_type2str(type)); + return AST_TEST_FAIL; + } + + /* Try to delete the second stream in the topology */ + if (ast_stream_topology_del_stream(topology, 1)) { + ast_test_status_update(test, "Failed deleting second stream in topology.\n"); + return AST_TEST_FAIL; + } + if (check_stream_positions(test, topology)) { + ast_test_status_update(test, "Second stream delete topology positions failed.\n"); + return AST_TEST_FAIL; + } + stream = ast_stream_topology_get_stream(topology, 1); + type = ast_stream_get_type(stream); + if (type != AST_MEDIA_TYPE_UNKNOWN + 2) { + ast_test_status_update(test, "Second stream delete types failed: Expected:%s Got:%s\n", + ast_codec_media_type2str(AST_MEDIA_TYPE_UNKNOWN + 2), + ast_codec_media_type2str(type)); + return AST_TEST_FAIL; + } + + /* Try to delete the first stream in the topology */ + if (ast_stream_topology_del_stream(topology, 0)) { + ast_test_status_update(test, "Failed deleting first stream in topology.\n"); + return AST_TEST_FAIL; + } + if (check_stream_positions(test, topology)) { + ast_test_status_update(test, "First stream delete topology positions failed.\n"); + return AST_TEST_FAIL; + } + stream = ast_stream_topology_get_stream(topology, 0); + type = ast_stream_get_type(stream); + if (type != AST_MEDIA_TYPE_UNKNOWN + 2) { + ast_test_status_update(test, "First stream delete types failed: Expected:%s Got:%s\n", + ast_codec_media_type2str(AST_MEDIA_TYPE_UNKNOWN + 2), + ast_codec_media_type2str(type)); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + AST_TEST_DEFINE(stream_topology_create_from_format_cap) { RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free); @@ -615,7 +755,12 @@ AST_TEST_DEFINE(stream_topology_create_from_format_cap) AST_TEST_DEFINE(stream_topology_get_first_stream_by_type) { RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free); - struct ast_stream *first_stream, *second_stream, *third_stream, *fourth_stream; + struct ast_stream *first_stream; + struct ast_stream *second_stream; + struct ast_stream *third_stream; + struct ast_stream *fourth_stream; + struct ast_stream *fifth_stream; + struct ast_stream *sixth_stream; switch (cmd) { case TEST_INIT: @@ -640,6 +785,7 @@ AST_TEST_DEFINE(stream_topology_get_first_stream_by_type) ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n"); return AST_TEST_FAIL; } + ast_stream_set_state(first_stream, AST_STREAM_STATE_REMOVED); if (ast_stream_topology_append_stream(topology, first_stream) == -1) { ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); @@ -659,9 +805,9 @@ AST_TEST_DEFINE(stream_topology_get_first_stream_by_type) return AST_TEST_FAIL; } - third_stream = ast_stream_alloc("video", AST_MEDIA_TYPE_VIDEO); + third_stream = ast_stream_alloc("audio3", AST_MEDIA_TYPE_AUDIO); if (!third_stream) { - ast_test_status_update(test, "Failed to create a video stream for testing stream topology\n"); + ast_test_status_update(test, "Failed to create a third audio stream for testing stream topology\n"); return AST_TEST_FAIL; } @@ -671,11 +817,12 @@ AST_TEST_DEFINE(stream_topology_get_first_stream_by_type) return AST_TEST_FAIL; } - fourth_stream = ast_stream_alloc("video2", AST_MEDIA_TYPE_VIDEO); + fourth_stream = ast_stream_alloc("video", AST_MEDIA_TYPE_VIDEO); if (!fourth_stream) { - ast_test_status_update(test, "Failed to create a second video stream for testing stream topology\n"); + ast_test_status_update(test, "Failed to create a video stream for testing stream topology\n"); return AST_TEST_FAIL; } + ast_stream_set_state(fourth_stream, AST_STREAM_STATE_REMOVED); if (ast_stream_topology_append_stream(topology, fourth_stream) == -1) { ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); @@ -683,12 +830,36 @@ AST_TEST_DEFINE(stream_topology_get_first_stream_by_type) return AST_TEST_FAIL; } - if (ast_stream_topology_get_first_stream_by_type(topology, AST_MEDIA_TYPE_AUDIO) != first_stream) { + fifth_stream = ast_stream_alloc("video2", AST_MEDIA_TYPE_VIDEO); + if (!fifth_stream) { + ast_test_status_update(test, "Failed to create a second video stream for testing stream topology\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_append_stream(topology, fifth_stream) == -1) { + ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); + ast_stream_free(fifth_stream); + return AST_TEST_FAIL; + } + + sixth_stream = ast_stream_alloc("video3", AST_MEDIA_TYPE_VIDEO); + if (!sixth_stream) { + ast_test_status_update(test, "Failed to create a third video stream for testing stream topology\n"); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_append_stream(topology, sixth_stream) == -1) { + ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); + ast_stream_free(sixth_stream); + return AST_TEST_FAIL; + } + + if (ast_stream_topology_get_first_stream_by_type(topology, AST_MEDIA_TYPE_AUDIO) != second_stream) { ast_test_status_update(test, "Retrieved first audio stream from topology but it is not the correct one\n"); return AST_TEST_FAIL; } - if (ast_stream_topology_get_first_stream_by_type(topology, AST_MEDIA_TYPE_VIDEO) != third_stream) { + if (ast_stream_topology_get_first_stream_by_type(topology, AST_MEDIA_TYPE_VIDEO) != fifth_stream) { ast_test_status_update(test, "Retrieved first video stream from topology but it is not the correct one\n"); return AST_TEST_FAIL; } @@ -1778,6 +1949,8 @@ AST_TEST_DEFINE(format_cap_from_stream_topology) RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); RAII_VAR(struct ast_format_cap *, stream_caps, NULL, ao2_cleanup); struct ast_stream_topology *topology; + struct ast_stream *stream; + struct ast_format_cap *new_cap; switch (cmd) { case TEST_INIT: @@ -1798,12 +1971,12 @@ AST_TEST_DEFINE(format_cap_from_stream_topology) } if (ast_format_cap_append(caps, ast_format_ulaw, 0)) { - ast_test_status_update(test, "Failed to append a ulaw format to capabilities for channel nativeformats\n"); + ast_test_status_update(test, "Failed to append ulaw format to capabilities\n"); return AST_TEST_FAIL; } if (ast_format_cap_append(caps, ast_format_h264, 0)) { - ast_test_status_update(test, "Failed to append an h264 format to capabilities for channel nativeformats\n"); + ast_test_status_update(test, "Failed to append h264 format to capabilities\n"); return AST_TEST_FAIL; } @@ -1813,6 +1986,40 @@ AST_TEST_DEFINE(format_cap_from_stream_topology) return AST_TEST_FAIL; } + /* + * Append declined stream with formats that should not be included + * in combined topology caps. + */ + stream = ast_stream_alloc("audio", AST_MEDIA_TYPE_AUDIO); + if (!stream) { + ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n"); + ast_stream_topology_free(topology); + return AST_TEST_FAIL; + } + ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED); + new_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!new_cap) { + ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n"); + ast_stream_free(stream); + ast_stream_topology_free(topology); + return AST_TEST_FAIL; + } + if (ast_format_cap_append(new_cap, ast_format_alaw, 0)) { + ast_test_status_update(test, "Failed to append alaw format to capabilities\n"); + ao2_cleanup(new_cap); + ast_stream_free(stream); + ast_stream_topology_free(topology); + return AST_TEST_FAIL; + } + ast_stream_set_formats(stream, new_cap); + ao2_cleanup(new_cap); + if (ast_stream_topology_append_stream(topology, stream) == -1) { + ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n"); + ast_stream_free(stream); + ast_stream_topology_free(topology); + return AST_TEST_FAIL; + } + stream_caps = ast_format_cap_from_stream_topology(topology); if (!stream_caps) { ast_test_status_update(test, "Failed to create a format capabilities from a stream topology\n"); @@ -1933,6 +2140,7 @@ static int unload_module(void) AST_TEST_UNREGISTER(stream_topology_clone); AST_TEST_UNREGISTER(stream_topology_append_stream); AST_TEST_UNREGISTER(stream_topology_set_stream); + AST_TEST_UNREGISTER(stream_topology_del_stream); AST_TEST_UNREGISTER(stream_topology_create_from_format_cap); AST_TEST_UNREGISTER(stream_topology_get_first_stream_by_type); AST_TEST_UNREGISTER(stream_topology_create_from_channel_nativeformats); @@ -1961,6 +2169,7 @@ static int load_module(void) AST_TEST_REGISTER(stream_topology_clone); AST_TEST_REGISTER(stream_topology_append_stream); AST_TEST_REGISTER(stream_topology_set_stream); + AST_TEST_REGISTER(stream_topology_del_stream); AST_TEST_REGISTER(stream_topology_create_from_format_cap); AST_TEST_REGISTER(stream_topology_get_first_stream_by_type); AST_TEST_REGISTER(stream_topology_create_from_channel_nativeformats); |