summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bridges/bridge_softmix.c3
-rw-r--r--configs/sorcery.conf.sample2
-rw-r--r--funcs/func_frame_trace.c4
-rw-r--r--include/asterisk/bridge_channel.h22
-rw-r--r--include/asterisk/frame.h6
-rw-r--r--include/asterisk/sorcery.h39
-rw-r--r--main/bridge_channel.c264
-rw-r--r--main/channel.c2
-rw-r--r--main/frame.c8
-rw-r--r--main/sorcery.c47
-rw-r--r--res/res_mwi_external.c6
-rw-r--r--res/res_pjsip/config_system.c2
-rw-r--r--res/res_pjsip/pjsip_configuration.c2
-rw-r--r--res/res_stasis_playback.c46
-rw-r--r--tests/test_sorcery.c40
-rw-r--r--tests/test_sorcery_astdb.c2
-rw-r--r--tests/test_sorcery_realtime.c2
17 files changed, 383 insertions, 114 deletions
diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c
index 271f8564e..e2ab2135f 100644
--- a/bridges/bridge_softmix.c
+++ b/bridges/bridge_softmix.c
@@ -661,6 +661,9 @@ static int softmix_bridge_write(struct ast_bridge *bridge, struct ast_bridge_cha
case AST_FRAME_BRIDGE_ACTION:
res = ast_bridge_queue_everyone_else(bridge, bridge_channel, frame);
break;
+ case AST_FRAME_BRIDGE_ACTION_SYNC:
+ ast_log(LOG_ERROR, "Synchronous bridge action written to a softmix bridge.\n");
+ ast_assert(0);
default:
ast_debug(3, "Frame type %d unsupported\n", frame->frametype);
/* "Accept" the frame and discard it. */
diff --git a/configs/sorcery.conf.sample b/configs/sorcery.conf.sample
index ee1300360..7406214fb 100644
--- a/configs/sorcery.conf.sample
+++ b/configs/sorcery.conf.sample
@@ -41,7 +41,7 @@
;
; The following object mappings are used by the unit test to test certain functionality of sorcery.
;
-[test_sorcery]
+[test_sorcery_section]
test=memory
[test_sorcery_cache]
diff --git a/funcs/func_frame_trace.c b/funcs/func_frame_trace.c
index 17f7c8965..bdbc596e6 100644
--- a/funcs/func_frame_trace.c
+++ b/funcs/func_frame_trace.c
@@ -392,6 +392,10 @@ static void print_frame(struct ast_frame *frame)
ast_verbose("FrameType: Bridge\n");
ast_verbose("SubClass: %d\n", frame->subclass.integer);
break;
+ case AST_FRAME_BRIDGE_ACTION_SYNC:
+ ast_verbose("Frametype: Synchronous Bridge\n");
+ ast_verbose("Subclass: %d\n", frame->subclass.integer);
+ break;
}
ast_verbose("Src: %s\n", ast_strlen_zero(frame->src) ? "NOT PRESENT" : frame->src);
diff --git a/include/asterisk/bridge_channel.h b/include/asterisk/bridge_channel.h
index 73c657019..c8aaf8906 100644
--- a/include/asterisk/bridge_channel.h
+++ b/include/asterisk/bridge_channel.h
@@ -529,6 +529,28 @@ int ast_bridge_channel_write_playfile(struct ast_bridge_channel *bridge_channel,
int ast_bridge_channel_queue_playfile(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class);
/*!
+ * \brief Synchronously queue a bridge action play file frame onto the bridge channel.
+ * \since 12.2.0
+ *
+ * \param bridge_channel Which channel to put the frame onto.
+ * \param custom_play Call this function to play the playfile. (NULL if normal sound file to play)
+ * \param playfile Sound filename to play.
+ * \param moh_class MOH class to request bridge peers to hear while file is played.
+ * NULL if no MOH.
+ * Empty if default MOH class.
+ *
+ * This function will block until the queued frame has been destroyed. This will happen
+ * either if an error occurs or if the queued playback finishes.
+ *
+ * \note No locks may be held when calling this function.
+ *
+ * \retval 0 The playback was successfully queued.
+ * \retval -1 The playback could not be queued.
+ */
+int ast_bridge_channel_queue_playfile_sync(struct ast_bridge_channel *bridge_channel,
+ ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class);
+
+/*!
* \brief Custom callback run on a bridge channel.
*
* \param bridge_channel Which channel to operate on.
diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h
index 53383834f..846832aff 100644
--- a/include/asterisk/frame.h
+++ b/include/asterisk/frame.h
@@ -122,6 +122,12 @@ enum ast_frame_type {
AST_FRAME_DTMF_BEGIN,
/*! Internal bridge module action. */
AST_FRAME_BRIDGE_ACTION,
+ /*! Internal synchronous bridge module action.
+ * Synchronous bridge actions may be queued onto bridge
+ * channels, but they absolutely must not ever be written
+ * directly into bridges.
+ */
+ AST_FRAME_BRIDGE_ACTION_SYNC,
};
#define AST_FRAME_DTMF AST_FRAME_DTMF_END
diff --git a/include/asterisk/sorcery.h b/include/asterisk/sorcery.h
index 026fb4074..22616d5b4 100644
--- a/include/asterisk/sorcery.h
+++ b/include/asterisk/sorcery.h
@@ -39,7 +39,11 @@
* object types to their respective wizards (object storage modules). If the developer would like
* to allow the user to configure this using the sorcery.conf configuration file the
* \ref ast_sorcery_apply_config API call can be used to read in the configuration file and apply the
- * mappings. If the storage of the object types are such that a default wizard can be used this can
+ * mappings. \ref ast_sorcery_open will automatically call \ref ast_sorcery_apply_config to allow
+ * for configuration of objects using the same category name as the module that is opening the
+ * sorcery instance. Direct calls to \ref ast_sorcery_apply_config should only be performed if a
+ * module wishes to allow for additional configuration sections in sorcery.conf to be used.
+ * If the storage of the object types are such that a default wizard can be used this can
* be applied using the \ref ast_sorcery_apply_default API call. Note that the default mappings will not
* override configured mappings. They are only used in the case where no configured mapping exists.
*
@@ -322,6 +326,9 @@ int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface);
*
* \param module The module name (AST_MODULE)
*
+ * When called, this will automatically also call __ast_sorcery_apply_config()
+ * with the module name as the configuration section.
+ *
* \retval non-NULL success
* \retval NULL if allocation failed
*/
@@ -343,6 +350,17 @@ struct ast_sorcery *__ast_sorcery_open(const char *module);
*/
struct ast_sorcery *ast_sorcery_retrieve_by_module_name(const char *module);
+enum ast_sorcery_apply_result {
+ /*! Sorcery wizard failed to apply. */
+ AST_SORCERY_APPLY_FAIL = -1,
+ /*! Sorcery wizard applied successfully. */
+ AST_SORCERY_APPLY_SUCCESS = 0,
+ /*! Sorcery wizard has already been applied to the object type. */
+ AST_SORCERY_APPLY_DUPLICATE = 1,
+ /*! Default sorcery wizard is unnecessary since a wizard has already been applied to the object type. */
+ AST_SORCERY_APPLY_DEFAULT_UNNECESSARY = 2,
+};
+
/*!
* \brief Apply configured wizard mappings
*
@@ -350,10 +368,17 @@ struct ast_sorcery *ast_sorcery_retrieve_by_module_name(const char *module);
* \param name Name of the category to use within the configuration file, normally the module name
* \param module The module name (AST_MODULE)
*
- * \retval 0 success
- * \retval -1 failure
+ * This function is called automatically by __ast_sorcery_open() using the module name as the
+ * configuration category. The only reason you should call this function is if your module
+ * wishes to apply configuration from additional sections of sorcery.conf.
+ *
+ * If a configuration section attempts to apply the same sorcery wizard to an object type
+ * more than once, the wizard will only be applied one time.
+ *
+ * \return What happened when attempting to apply the default.
*/
-int __ast_sorcery_apply_config(struct ast_sorcery *sorcery, const char *name, const char *module);
+enum ast_sorcery_apply_result __ast_sorcery_apply_config(struct ast_sorcery *sorcery,
+ const char *name, const char *module);
#define ast_sorcery_apply_config(sorcery, name) \
__ast_sorcery_apply_config((sorcery), (name), AST_MODULE)
@@ -367,14 +392,14 @@ int __ast_sorcery_apply_config(struct ast_sorcery *sorcery, const char *name, co
* \param name Name of the wizard to use
* \param data Data to be passed to wizard
*
- * \retval 0 success
- * \retval -1 failure
+ * \return What occurred when applying the default
*
* \note This should be called *after* applying configuration sourced mappings
*
* \note Only a single default can exist per object type
*/
-int __ast_sorcery_apply_default(struct ast_sorcery *sorcery, const char *type, const char *module, const char *name, const char *data);
+enum ast_sorcery_apply_result __ast_sorcery_apply_default(struct ast_sorcery *sorcery,
+ const char *type, const char *module, const char *name, const char *data);
#define ast_sorcery_apply_default(sorcery, type, name, data) \
__ast_sorcery_apply_default((sorcery), (type), AST_MODULE, (name), (data))
diff --git a/main/bridge_channel.c b/main/bridge_channel.c
index 06da4eeed..75008fe18 100644
--- a/main/bridge_channel.c
+++ b/main/bridge_channel.c
@@ -35,6 +35,7 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <signal.h>
+#include <semaphore.h>
#include "asterisk/heap.h"
#include "asterisk/astobj2.h"
@@ -70,6 +71,142 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
*/
typedef int (*ast_bridge_channel_post_action_data)(struct ast_bridge_channel *bridge_channel, enum bridge_channel_action_type action, const void *data, size_t datalen);
+/*!
+ * \brief Counter used for assigning synchronous bridge action IDs
+ */
+static int sync_ids;
+
+/*!
+ * \brief Frame payload for synchronous bridge actions.
+ *
+ * The payload serves as a wrapper around the actual payload of the
+ * frame, with the addition of an id used to find the associated
+ * bridge_sync object.
+ */
+struct sync_payload {
+ /*! Unique ID for this synchronous action */
+ unsigned int id;
+ /*! Actual frame data to process */
+ unsigned char data[0];
+};
+
+/*!
+ * \brief Synchronous bridge action object.
+ *
+ * Synchronous bridge actions require the ability for one thread to wait
+ * and for another thread to indicate that the action has completed. This
+ * structure facilitates that goal by providing synchronization structures.
+ */
+struct bridge_sync {
+ /*! Unique ID of this synchronization object. Corresponds with ID in synchronous frame payload */
+ unsigned int id;
+ /*! Semaphore used for synchronization */
+ sem_t sem;
+ /*! Pointer to next entry in the list */
+ AST_LIST_ENTRY(bridge_sync) list;
+};
+
+/*!
+ * \brief List holding active synchronous action objects.
+ */
+static AST_RWLIST_HEAD_STATIC(sync_structs, bridge_sync);
+
+/*!
+ * \brief initialize a synchronous bridge object.
+ *
+ * This both initializes the structure and adds it to the list of
+ * synchronization structures.
+ *
+ * \param sync_struct The synchronization object to initialize.
+ * \param id ID to assign to the synchronization object.
+ */
+static void bridge_sync_init(struct bridge_sync *sync_struct, unsigned int id)
+{
+ memset(sync_struct, 0, sizeof(*sync_struct));
+ sync_struct->id = id;
+ sem_init(&sync_struct->sem, 0, 0);
+
+ AST_RWLIST_WRLOCK(&sync_structs);
+ AST_RWLIST_INSERT_TAIL(&sync_structs, sync_struct, list);
+ AST_RWLIST_UNLOCK(&sync_structs);
+}
+
+/*!
+ * \brief Clean up a syncrhonization bridge object.
+ *
+ * This frees fields within the synchronization object and removes
+ * it from the list of active synchronization objects.
+ *
+ * Since synchronization objects are stack-allocated, it is vital
+ * that this is called before the synchronization object goes
+ * out of scope.
+ *
+ * \param sync_struct Synchronization object to clean up.
+ */
+static void bridge_sync_cleanup(struct bridge_sync *sync_struct)
+{
+ struct bridge_sync *iter;
+
+ AST_RWLIST_WRLOCK(&sync_structs);
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&sync_structs, iter, list) {
+ if (iter->id == sync_struct->id) {
+ AST_LIST_REMOVE_CURRENT(list);
+ break;
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END;
+ AST_RWLIST_UNLOCK(&sync_structs);
+
+ sem_destroy(&sync_struct->sem);
+}
+
+/*!
+ * \brief Failsafe for synchronous bridge action waiting.
+ *
+ * When waiting for a synchronous bridge action to complete,
+ * if there is a frame resource leak somewhere, it is possible
+ * that we will never get notified that the synchronous action
+ * completed.
+ *
+ * If a significant amount of time passes, then we will abandon
+ * waiting for the synchrnous bridge action to complete.
+ *
+ * This constant represents the number of milliseconds we will
+ * wait for the bridge action to complete.
+ */
+#define PLAYBACK_TIMEOUT (600 * 1000)
+
+/*!
+ * \brief Wait for a synchronous bridge action to complete.
+ *
+ * \param sync_struct Synchronization object corresponding to the bridge action.
+ */
+static void bridge_sync_wait(struct bridge_sync *sync_struct)
+{
+ struct timeval timeout_val = ast_tvadd(ast_tvnow(), ast_samp2tv(PLAYBACK_TIMEOUT, 1000));
+ struct timespec timeout_spec = {
+ .tv_sec = timeout_val.tv_sec,
+ .tv_nsec = timeout_val.tv_usec * 1000,
+ };
+
+ sem_timedwait(&sync_struct->sem, &timeout_spec);
+}
+
+/*!
+ * \brief Signal that waiting for a synchronous bridge action is no longer necessary.
+ *
+ * This may occur for several reasons
+ * \li The synchronous bridge action has completed.
+ * \li The bridge channel has been removed from the bridge.
+ * \li The synchronous bridge action could not be queued.
+ *
+ * \param sync_struct Synchronization object corresponding to the bridge action.
+ */
+static void bridge_sync_signal(struct bridge_sync *sync_struct)
+{
+ sem_post(&sync_struct->sem);
+}
+
void ast_bridge_channel_lock_bridge(struct ast_bridge_channel *bridge_channel)
{
struct ast_bridge *bridge;
@@ -342,6 +479,8 @@ void ast_bridge_channel_kick(struct ast_bridge_channel *bridge_channel, int caus
*/
static int bridge_channel_write_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
{
+ ast_assert(frame->frametype != AST_FRAME_BRIDGE_ACTION_SYNC);
+
ast_bridge_channel_lock_bridge(bridge_channel);
/*
* XXX need to implement a deferred write queue for when there
@@ -493,7 +632,8 @@ static void bridge_channel_unsuspend(struct ast_bridge_channel *bridge_channel)
* \retval 0 on success.
* \retval -1 on error.
*/
-static int bridge_channel_queue_action_data(struct ast_bridge_channel *bridge_channel, enum bridge_channel_action_type action, const void *data, size_t datalen)
+static int bridge_channel_queue_action_data(struct ast_bridge_channel *bridge_channel,
+ enum bridge_channel_action_type action, const void *data, size_t datalen)
{
struct ast_frame frame = {
.frametype = AST_FRAME_BRIDGE_ACTION,
@@ -507,6 +647,52 @@ static int bridge_channel_queue_action_data(struct ast_bridge_channel *bridge_ch
/*!
* \internal
+ * \brief Queue an action frame onto the bridge channel with data synchronously.
+ * \since 12.2.0
+ *
+ * The function will not return until the queued frame is freed.
+ *
+ * \param bridge_channel Which channel to queue the frame onto.
+ * \param action Type of bridge action frame.
+ * \param data Frame payload data to pass.
+ * \param datalen Frame payload data length to pass.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int bridge_channel_queue_action_data_sync(struct ast_bridge_channel *bridge_channel,
+ enum bridge_channel_action_type action, const void *data, size_t datalen)
+{
+ struct sync_payload *sync_payload;
+ int sync_payload_len = sizeof(*sync_payload) + datalen;
+ struct bridge_sync sync_struct;
+ struct ast_frame frame = {
+ .frametype = AST_FRAME_BRIDGE_ACTION_SYNC,
+ .subclass.integer = action,
+ };
+
+ /* Make sure we don't end up trying to wait on ourself to deliver the frame */
+ ast_assert(!pthread_equal(pthread_self(), bridge_channel->thread));
+
+ sync_payload = ast_alloca(sync_payload_len);
+ sync_payload->id = ast_atomic_fetchadd_int(&sync_ids, +1);
+ memcpy(sync_payload->data, data, datalen);
+
+ frame.datalen = sync_payload_len;
+ frame.data.ptr = sync_payload;
+
+ bridge_sync_init(&sync_struct, sync_payload->id);
+ if (ast_bridge_channel_queue_frame(bridge_channel, &frame)) {
+ bridge_sync_cleanup(&sync_struct);
+ return -1;
+ }
+
+ bridge_sync_wait(&sync_struct);
+ bridge_sync_cleanup(&sync_struct);
+ return 0;
+}
+/*!
+ * \internal
* \brief Write an action frame onto the bridge channel with data.
* \since 12.0.0
*
@@ -518,7 +704,8 @@ static int bridge_channel_queue_action_data(struct ast_bridge_channel *bridge_ch
* \retval 0 on success.
* \retval -1 on error.
*/
-static int bridge_channel_write_action_data(struct ast_bridge_channel *bridge_channel, enum bridge_channel_action_type action, const void *data, size_t datalen)
+static int bridge_channel_write_action_data(struct ast_bridge_channel *bridge_channel,
+ enum bridge_channel_action_type action, const void *data, size_t datalen)
{
struct ast_frame frame = {
.frametype = AST_FRAME_BRIDGE_ACTION,
@@ -530,6 +717,27 @@ static int bridge_channel_write_action_data(struct ast_bridge_channel *bridge_ch
return bridge_channel_write_frame(bridge_channel, &frame);
}
+static void bridge_frame_free(struct ast_frame *frame)
+{
+ if (frame->frametype == AST_FRAME_BRIDGE_ACTION_SYNC) {
+ struct sync_payload *sync_payload = frame->data.ptr;
+ struct bridge_sync *sync;
+
+ AST_RWLIST_RDLOCK(&sync_structs);
+ AST_RWLIST_TRAVERSE(&sync_structs, sync, list) {
+ if (sync->id == sync_payload->id) {
+ break;
+ }
+ }
+ if (sync) {
+ bridge_sync_signal(sync);
+ }
+ AST_RWLIST_UNLOCK(&sync_structs);
+ }
+
+ ast_frfree(frame);
+}
+
int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *fr)
{
struct ast_frame *dup;
@@ -557,7 +765,7 @@ int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, st
if (bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT) {
/* Drop frames on channels leaving the bridge. */
ast_bridge_channel_unlock(bridge_channel);
- ast_frfree(dup);
+ bridge_frame_free(dup);
return 0;
}
@@ -816,7 +1024,7 @@ static int payload_helper_playfile(ast_bridge_channel_post_action_data post_it,
size_t len_payload = sizeof(*payload) + len_name + len_moh;
/* Fill in play file frame data. */
- payload = alloca(len_payload);
+ payload = ast_alloca(len_payload);
payload->custom_play = custom_play;
payload->moh_offset = len_moh ? len_name : 0;
strcpy(payload->playfile, playfile);/* Safe */
@@ -839,6 +1047,13 @@ int ast_bridge_channel_queue_playfile(struct ast_bridge_channel *bridge_channel,
bridge_channel, custom_play, playfile, moh_class);
}
+int ast_bridge_channel_queue_playfile_sync(struct ast_bridge_channel *bridge_channel,
+ ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class)
+{
+ return payload_helper_playfile(bridge_channel_queue_action_data_sync,
+ bridge_channel, custom_play, playfile, moh_class);
+}
+
struct bridge_custom_callback {
/*! Call this function on the bridge channel thread. */
ast_bridge_custom_callback_fn callback;
@@ -1389,53 +1604,55 @@ static void bridge_channel_attended_transfer(struct ast_bridge_channel *bridge_c
*
* \param bridge_channel Channel to execute the action on.
* \param action What to do.
+ * \param data data from the action.
*
* \return Nothing
*/
-static void bridge_channel_handle_action(struct ast_bridge_channel *bridge_channel, struct ast_frame *action)
+static void bridge_channel_handle_action(struct ast_bridge_channel *bridge_channel,
+ enum bridge_channel_action_type action, void *data)
{
- switch (action->subclass.integer) {
+ switch (action) {
case BRIDGE_CHANNEL_ACTION_DTMF_STREAM:
bridge_channel_suspend(bridge_channel);
ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
- bridge_channel_dtmf_stream(bridge_channel, action->data.ptr);
+ bridge_channel_dtmf_stream(bridge_channel, data);
ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
bridge_channel_unsuspend(bridge_channel);
break;
case BRIDGE_CHANNEL_ACTION_TALKING_START:
case BRIDGE_CHANNEL_ACTION_TALKING_STOP:
bridge_channel_talking(bridge_channel,
- action->subclass.integer == BRIDGE_CHANNEL_ACTION_TALKING_START);
+ action == BRIDGE_CHANNEL_ACTION_TALKING_START);
break;
case BRIDGE_CHANNEL_ACTION_PLAY_FILE:
bridge_channel_suspend(bridge_channel);
ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
- bridge_channel_playfile(bridge_channel, action->data.ptr);
+ bridge_channel_playfile(bridge_channel, data);
ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
bridge_channel_unsuspend(bridge_channel);
break;
case BRIDGE_CHANNEL_ACTION_RUN_APP:
bridge_channel_suspend(bridge_channel);
ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
- bridge_channel_run_app(bridge_channel, action->data.ptr);
+ bridge_channel_run_app(bridge_channel, data);
ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
bridge_channel_unsuspend(bridge_channel);
break;
case BRIDGE_CHANNEL_ACTION_CALLBACK:
- bridge_channel_do_callback(bridge_channel, action->data.ptr);
+ bridge_channel_do_callback(bridge_channel, data);
break;
case BRIDGE_CHANNEL_ACTION_PARK:
bridge_channel_suspend(bridge_channel);
ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
- bridge_channel_park(bridge_channel, action->data.ptr);
+ bridge_channel_park(bridge_channel, data);
ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
bridge_channel_unsuspend(bridge_channel);
break;
case BRIDGE_CHANNEL_ACTION_BLIND_TRANSFER:
- bridge_channel_blind_transfer(bridge_channel, action->data.ptr);
+ bridge_channel_blind_transfer(bridge_channel, data);
break;
case BRIDGE_CHANNEL_ACTION_ATTENDED_TRANSFER:
- bridge_channel_attended_transfer(bridge_channel, action->data.ptr);
+ bridge_channel_attended_transfer(bridge_channel, data);
break;
default:
break;
@@ -1700,6 +1917,7 @@ static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channe
{
struct ast_frame *fr;
char nudge;
+ struct sync_payload *sync_payload;
ast_bridge_channel_lock(bridge_channel);
if (read(bridge_channel->alert_pipe[0], &nudge, sizeof(nudge)) < 0) {
@@ -1715,7 +1933,11 @@ static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channe
}
switch (fr->frametype) {
case AST_FRAME_BRIDGE_ACTION:
- bridge_channel_handle_action(bridge_channel, fr);
+ bridge_channel_handle_action(bridge_channel, fr->subclass.integer, fr->data.ptr);
+ break;
+ case AST_FRAME_BRIDGE_ACTION_SYNC:
+ sync_payload = fr->data.ptr;
+ bridge_channel_handle_action(bridge_channel, fr->subclass.integer, sync_payload->data);
break;
case AST_FRAME_CONTROL:
bridge_channel_handle_control(bridge_channel, fr);
@@ -1728,7 +1950,7 @@ static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channe
ast_write(bridge_channel->chan, fr);
break;
}
- ast_frfree(fr);
+ bridge_frame_free(fr);
}
/*! \brief Internal function to handle DTMF from a channel */
@@ -1745,7 +1967,7 @@ static struct ast_frame *bridge_handle_dtmf(struct ast_bridge_channel *bridge_ch
if (hook) {
enum ast_frame_type frametype = frame->frametype;
- ast_frfree(frame);
+ bridge_frame_free(frame);
frame = NULL;
ao2_ref(hook, -1);
@@ -1805,7 +2027,7 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel)
switch (frame->subclass.integer) {
case AST_CONTROL_HANGUP:
ast_bridge_channel_kick(bridge_channel, 0);
- ast_frfree(frame);
+ bridge_frame_free(frame);
return;
default:
break;
@@ -1818,7 +2040,7 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel)
return;
}
if (!bridge_channel->features->dtmf_passthrough) {
- ast_frfree(frame);
+ bridge_frame_free(frame);
return;
}
break;
@@ -1828,7 +2050,7 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel)
/* Simply write the frame out to the bridge technology. */
bridge_channel_write_frame(bridge_channel, frame);
- ast_frfree(frame);
+ bridge_frame_free(frame);
}
/*!
@@ -2205,7 +2427,7 @@ static void bridge_channel_destroy(void *obj)
/* Flush any unhandled wr_queue frames. */
while ((fr = AST_LIST_REMOVE_HEAD(&bridge_channel->wr_queue, frame_list))) {
- ast_frfree(fr);
+ bridge_frame_free(fr);
}
pipe_close(bridge_channel->alert_pipe);
diff --git a/main/channel.c b/main/channel.c
index 6145e3505..b264a2170 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -1531,6 +1531,7 @@ int ast_is_deferrable_frame(const struct ast_frame *frame)
*/
switch (frame->frametype) {
case AST_FRAME_BRIDGE_ACTION:
+ case AST_FRAME_BRIDGE_ACTION_SYNC:
case AST_FRAME_CONTROL:
case AST_FRAME_TEXT:
case AST_FRAME_IMAGE:
@@ -2875,6 +2876,7 @@ int __ast_answer(struct ast_channel *chan, unsigned int delay)
case AST_FRAME_CONTROL:
case AST_FRAME_IAX:
case AST_FRAME_BRIDGE_ACTION:
+ case AST_FRAME_BRIDGE_ACTION_SYNC:
case AST_FRAME_NULL:
case AST_FRAME_CNG:
break;
diff --git a/main/frame.c b/main/frame.c
index 8713ce40d..1b13abc69 100644
--- a/main/frame.c
+++ b/main/frame.c
@@ -639,6 +639,10 @@ void ast_frame_subclass2str(struct ast_frame *f, char *subclass, size_t slen, ch
/* Should never happen */
snprintf(subclass, slen, "Bridge Frametype %d", f->subclass.integer);
break;
+ case AST_FRAME_BRIDGE_ACTION_SYNC:
+ /* Should never happen */
+ snprintf(subclass, slen, "Synchronous Bridge Frametype %d", f->subclass.integer);
+ break;
case AST_FRAME_TEXT:
ast_copy_string(subclass, "N/A", slen);
if (moreinfo) {
@@ -730,6 +734,10 @@ void ast_frame_type2str(enum ast_frame_type frame_type, char *ftype, size_t len)
/* Should never happen */
ast_copy_string(ftype, "Bridge Specific", len);
break;
+ case AST_FRAME_BRIDGE_ACTION_SYNC:
+ /* Should never happen */
+ ast_copy_string(ftype, "Bridge Specific", len);
+ break;
case AST_FRAME_TEXT:
ast_copy_string(ftype, "Text", len);
break;
diff --git a/main/sorcery.c b/main/sorcery.c
index 2ab4933be..94a11103b 100644
--- a/main/sorcery.c
+++ b/main/sorcery.c
@@ -580,6 +580,14 @@ struct ast_sorcery *__ast_sorcery_open(const char *module_name)
}
strcpy(sorcery->module_name, module_name); /* Safe */
+
+ if (__ast_sorcery_apply_config(sorcery, module_name, module_name) == AST_SORCERY_APPLY_FAIL) {
+ ast_log(LOG_ERROR, "Error attempting to apply configuration %s to sorcery.", module_name);
+ ao2_cleanup(sorcery);
+ sorcery = NULL;
+ goto done;
+ }
+
ao2_link_flags(instances, sorcery, OBJ_NOLOCK);
done:
@@ -623,7 +631,7 @@ static struct ast_sorcery_object_type *sorcery_object_type_alloc(const char *typ
}
/* Order matters for object wizards */
- if (!(object_type->wizards = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) {
+ if (!(object_type->wizards = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, sorcery_wizard_cmp))) {
ao2_ref(object_type, -1);
return NULL;
}
@@ -683,7 +691,8 @@ static void sorcery_object_wizard_destructor(void *obj)
}
/*! \brief Internal function which creates an object type and adds a wizard mapping */
-static int sorcery_apply_wizard_mapping(struct ast_sorcery *sorcery, const char *type, const char *module, const char *name, const char *data, unsigned int caching)
+static enum ast_sorcery_apply_result sorcery_apply_wizard_mapping(struct ast_sorcery *sorcery,
+ const char *type, const char *module, const char *name, const char *data, unsigned int caching)
{
RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
RAII_VAR(struct ast_sorcery_wizard *, wizard, ao2_find(wizards, name, OBJ_KEY), ao2_cleanup);
@@ -691,18 +700,30 @@ static int sorcery_apply_wizard_mapping(struct ast_sorcery *sorcery, const char
int created = 0;
if (!wizard || !object_wizard) {
- return -1;
+ return AST_SORCERY_APPLY_FAIL;
}
if (!object_type) {
if (!(object_type = sorcery_object_type_alloc(type, module))) {
- return -1;
+ return AST_SORCERY_APPLY_FAIL;
}
created = 1;
}
+ if (!created) {
+ struct ast_sorcery_wizard *found;
+
+ found = ao2_find(object_type->wizards, wizard, OBJ_SEARCH_OBJECT);
+ if (found) {
+ ast_debug(1, "Wizard %s already applied to object type %s\n",
+ wizard->name, object_type->name);
+ ao2_cleanup(found);
+ return AST_SORCERY_APPLY_DUPLICATE;
+ }
+ }
+
if (wizard->open && !(object_wizard->data = wizard->open(data))) {
- return -1;
+ return AST_SORCERY_APPLY_FAIL;
}
ast_module_ref(wizard->module);
@@ -716,18 +737,18 @@ static int sorcery_apply_wizard_mapping(struct ast_sorcery *sorcery, const char
ao2_link(sorcery->types, object_type);
}
- return 0;
+ return AST_SORCERY_APPLY_SUCCESS;
}
-int __ast_sorcery_apply_config(struct ast_sorcery *sorcery, const char *name, const char *module)
+enum ast_sorcery_apply_result __ast_sorcery_apply_config(struct ast_sorcery *sorcery, const char *name, const char *module)
{
struct ast_flags flags = { 0 };
struct ast_config *config = ast_config_load2("sorcery.conf", "sorcery", flags);
struct ast_variable *mapping;
- int res = 0;
+ int res = AST_SORCERY_APPLY_SUCCESS;
if (!config || config == CONFIG_STATUS_FILEINVALID) {
- return -1;
+ return AST_SORCERY_APPLY_FAIL;
}
for (mapping = ast_variable_browse(config, name); mapping; mapping = mapping->next) {
@@ -750,8 +771,8 @@ int __ast_sorcery_apply_config(struct ast_sorcery *sorcery, const char *name, co
}
/* Any error immediately causes us to stop */
- if (sorcery_apply_wizard_mapping(sorcery, type, module, wizard, data, caching)) {
- res = -1;
+ if (sorcery_apply_wizard_mapping(sorcery, type, module, wizard, data, caching) == AST_SORCERY_APPLY_FAIL) {
+ res = AST_SORCERY_APPLY_FAIL;
break;
}
}
@@ -761,13 +782,13 @@ int __ast_sorcery_apply_config(struct ast_sorcery *sorcery, const char *name, co
return res;
}
-int __ast_sorcery_apply_default(struct ast_sorcery *sorcery, const char *type, const char *module, const char *name, const char *data)
+enum ast_sorcery_apply_result __ast_sorcery_apply_default(struct ast_sorcery *sorcery, const char *type, const char *module, const char *name, const char *data)
{
RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
/* Defaults can not be added if any existing mapping exists */
if (object_type) {
- return -1;
+ return AST_SORCERY_APPLY_DEFAULT_UNNECESSARY;
}
return sorcery_apply_wizard_mapping(sorcery, type, module, name, data, 0);
diff --git a/res/res_mwi_external.c b/res/res_mwi_external.c
index c3fc0eaf4..875f32773 100644
--- a/res/res_mwi_external.c
+++ b/res/res_mwi_external.c
@@ -163,10 +163,8 @@ static int mwi_sorcery_init(void)
}
/* Map the external MWI wizards. */
- res = !!ast_sorcery_apply_config(mwi_sorcery, "res_mwi_external");
- res &= !!ast_sorcery_apply_default(mwi_sorcery, MWI_MAILBOX_TYPE, "astdb",
- MWI_ASTDB_PREFIX);
- if (res) {
+ if (ast_sorcery_apply_default(mwi_sorcery, MWI_MAILBOX_TYPE, "astdb",
+ MWI_ASTDB_PREFIX) == AST_SORCERY_APPLY_FAIL) {
ast_log(LOG_ERROR, "MWI external: Sorcery could not setup wizards.\n");
return -1;
}
diff --git a/res/res_pjsip/config_system.c b/res/res_pjsip/config_system.c
index bdf53149f..8fae6b74c 100644
--- a/res/res_pjsip/config_system.c
+++ b/res/res_pjsip/config_system.c
@@ -116,8 +116,6 @@ int ast_sip_initialize_system(void)
return -1;
}
- ast_sorcery_apply_config(system_sorcery, "res_pjsip");
-
ast_sorcery_apply_default(system_sorcery, "system", "config", "pjsip.conf,criteria=type=system");
if (ast_sorcery_object_register_no_reload(system_sorcery, "system", system_alloc, NULL, system_apply)) {
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index 1f289ade9..0a3433450 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -1619,8 +1619,6 @@ int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_mod
return -1;
}
- ast_sorcery_apply_config(sip_sorcery, "res_pjsip");
-
ast_sip_initialize_cli();
if (ast_sip_initialize_sorcery_auth()) {
diff --git a/res/res_stasis_playback.c b/res/res_stasis_playback.c
index ee4a20bcc..299cb4483 100644
--- a/res/res_stasis_playback.c
+++ b/res/res_stasis_playback.c
@@ -78,14 +78,10 @@ struct stasis_app_playback {
long offsetms;
/*! Number of milliseconds to skip for forward/reverse operations */
int skipms;
- /*! Condition for waiting on done to be set */
- ast_cond_t done_cond;
/*! Number of milliseconds of media that has been played */
long playedms;
/*! Current playback state */
enum stasis_app_playback_state state;
- /*! Set when playback has been completed */
- unsigned int done:1;
/*! Set when the playback can be controlled */
unsigned int controllable:1;
};
@@ -121,7 +117,6 @@ static void playback_dtor(void *obj)
struct stasis_app_playback *playback = obj;
ast_string_field_free_memory(playback);
- ast_cond_destroy(&playback->done_cond);
}
static struct stasis_app_playback *playback_create(
@@ -129,7 +124,6 @@ static struct stasis_app_playback *playback_create(
{
RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
char uuid[AST_UUID_STR_LEN];
- int res;
if (!control) {
return NULL;
@@ -140,13 +134,6 @@ static struct stasis_app_playback *playback_create(
return NULL;
}
- res = ast_cond_init(&playback->done_cond, NULL);
- if (res != 0) {
- ast_log(LOG_ERROR, "Error creating done condition: %s\n",
- strerror(errno));
- return NULL;
- }
-
if (!ast_strlen_zero(id)) {
ast_string_field_set(playback, id, id);
} else {
@@ -266,21 +253,9 @@ static void playback_final_update(struct stasis_app_playback *playback,
playback_publish(playback);
}
-/*!
- * \brief RAII_VAR function to mark a playback as done when leaving scope.
- */
-static void mark_as_done(struct stasis_app_playback *playback)
-{
- SCOPED_AO2LOCK(lock, playback);
- playback->done = 1;
- ast_cond_broadcast(&playback->done_cond);
-}
-
static void play_on_channel(struct stasis_app_playback *playback,
struct ast_channel *chan)
{
- RAII_VAR(struct stasis_app_playback *, mark_when_done, playback,
- mark_as_done);
int res;
long offsetms;
@@ -399,7 +374,6 @@ static int play_uri(struct stasis_app_control *control,
RAII_VAR(struct stasis_app_playback *, playback, NULL,
remove_from_playbacks);
struct ast_bridge *bridge;
- int res;
playback = data;
@@ -413,28 +387,16 @@ static int play_uri(struct stasis_app_control *control,
/* Queue up playback on the bridge */
ast_bridge_lock(bridge);
- bridge_chan = bridge_find_channel(bridge, chan);
+ bridge_chan = ao2_bump(bridge_find_channel(bridge, chan));
+ ast_bridge_unlock(bridge);
if (bridge_chan) {
- ast_bridge_channel_queue_playfile(
+ ast_bridge_channel_queue_playfile_sync(
bridge_chan,
play_on_channel_in_bridge,
playback->id,
NULL); /* moh_class */
}
- ast_bridge_unlock(bridge);
-
- /* Wait for playback to complete */
- ao2_lock(playback);
- while (!playback->done) {
- res = ast_cond_wait(&playback->done_cond,
- ao2_object_get_lockaddr(playback));
- if (res != 0) {
- ast_log(LOG_ERROR,
- "Error waiting for playback to complete: %s\n",
- strerror(errno));
- }
- }
- ao2_unlock(playback);
+ ao2_cleanup(bridge_chan);
} else {
play_on_channel(playback, chan);
}
diff --git a/tests/test_sorcery.c b/tests/test_sorcery.c
index ed4d604e6..aa34a11d3 100644
--- a/tests/test_sorcery.c
+++ b/tests/test_sorcery.c
@@ -306,7 +306,7 @@ static struct ast_sorcery *alloc_and_initialize_sorcery(void)
return NULL;
}
- if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL) ||
+ if ((ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) ||
ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL)) {
ast_sorcery_unref(sorcery);
return NULL;
@@ -452,17 +452,17 @@ AST_TEST_DEFINE(apply_default)
return AST_TEST_FAIL;
}
- if (!ast_sorcery_apply_default(sorcery, "test", "dummy", NULL)) {
+ if (ast_sorcery_apply_default(sorcery, "test", "dummy", NULL) != AST_SORCERY_APPLY_FAIL) {
ast_test_status_update(test, "Successfully set a default wizard that doesn't exist\n");
return AST_TEST_FAIL;
}
- if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL)) {
+ if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) {
ast_test_status_update(test, "Failed to set a known wizard as a default\n");
return AST_TEST_FAIL;
}
- if (!ast_sorcery_apply_default(sorcery, "test", "memory", NULL)) {
+ if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_DEFAULT_UNNECESSARY) {
ast_test_status_update(test, "Successfully set a default wizard on a type twice\n");
return AST_TEST_FAIL;
}
@@ -493,7 +493,7 @@ AST_TEST_DEFINE(apply_config)
return AST_TEST_NOT_RUN;
}
- if (!ast_category_get(config, "test_sorcery")) {
+ if (!ast_category_get(config, "test_sorcery_section")) {
ast_test_status_update(test, "Sorcery configuration file does not have test_sorcery section\n");
ast_config_destroy(config);
return AST_TEST_NOT_RUN;
@@ -506,7 +506,7 @@ AST_TEST_DEFINE(apply_config)
return AST_TEST_FAIL;
}
- if (ast_sorcery_apply_config(sorcery, "test_sorcery")) {
+ if (ast_sorcery_apply_config(sorcery, "test_sorcery_section") != AST_SORCERY_APPLY_SUCCESS) {
ast_test_status_update(test, "Failed to apply configured object mappings\n");
return AST_TEST_FAIL;
}
@@ -535,7 +535,7 @@ AST_TEST_DEFINE(object_register)
return AST_TEST_FAIL;
}
- if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL)) {
+ if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) {
ast_test_status_update(test, "Failed to set a known wizard as a default\n");
return AST_TEST_FAIL;
}
@@ -608,7 +608,7 @@ AST_TEST_DEFINE(object_field_register)
return AST_TEST_FAIL;
}
- if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL)) {
+ if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) {
ast_test_status_update(test, "Failed to set a known wizard as a default\n");
return AST_TEST_FAIL;
}
@@ -657,7 +657,7 @@ AST_TEST_DEFINE(object_fields_register)
return AST_TEST_FAIL;
}
- if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL)) {
+ if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) {
ast_test_status_update(test, "Failed to set a known wizard as a default\n");
return AST_TEST_FAIL;
}
@@ -1192,7 +1192,7 @@ AST_TEST_DEFINE(objectset_create_regex)
return AST_TEST_FAIL;
}
- if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL) ||
+ if ((ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) ||
ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, test_apply_handler)) {
ast_test_status_update(test, "Failed to register 'test' object type\n");
return AST_TEST_FAIL;
@@ -1292,7 +1292,7 @@ AST_TEST_DEFINE(objectset_apply_handler)
return AST_TEST_FAIL;
}
- if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL) ||
+ if ((ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) ||
ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, test_apply_handler)) {
ast_test_status_update(test, "Failed to register 'test' object type\n");
return AST_TEST_FAIL;
@@ -1387,7 +1387,7 @@ AST_TEST_DEFINE(objectset_transform)
return AST_TEST_FAIL;
}
- if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL)) {
+ if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) {
ast_test_status_update(test, "Failed to set a known wizard as a default\n");
return AST_TEST_FAIL;
}
@@ -1453,7 +1453,7 @@ AST_TEST_DEFINE(objectset_apply_fields)
return AST_TEST_FAIL;
}
- if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL) ||
+ if ((ast_sorcery_apply_default(sorcery, "test", "memory", NULL) != AST_SORCERY_APPLY_SUCCESS) ||
ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, test_apply_handler)) {
ast_test_status_update(test, "Failed to register 'test' object type\n");
return AST_TEST_FAIL;
@@ -2244,7 +2244,7 @@ AST_TEST_DEFINE(caching_wizard_behavior)
goto end;
}
- if (ast_sorcery_apply_config(sorcery, "test_sorcery_cache")) {
+ if (ast_sorcery_apply_config(sorcery, "test_sorcery_cache") != AST_SORCERY_APPLY_SUCCESS) {
ast_test_status_update(test, "Failed to apply configured object mappings\n");
goto end;
}
@@ -2489,7 +2489,7 @@ AST_TEST_DEFINE(configuration_file_wizard)
return AST_TEST_FAIL;
}
- if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf")) {
+ if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf") != AST_SORCERY_APPLY_SUCCESS) {
ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
return AST_TEST_NOT_RUN;
}
@@ -2552,7 +2552,7 @@ AST_TEST_DEFINE(configuration_file_wizard_with_file_integrity)
return AST_TEST_FAIL;
}
- if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf,integrity=file")) {
+ if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf,integrity=file") != AST_SORCERY_APPLY_SUCCESS) {
ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
return AST_TEST_NOT_RUN;
}
@@ -2606,7 +2606,7 @@ AST_TEST_DEFINE(configuration_file_wizard_with_criteria)
return AST_TEST_FAIL;
}
- if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf,criteria=type=zombies")) {
+ if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf,criteria=type=zombies") != AST_SORCERY_APPLY_SUCCESS) {
ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
return AST_TEST_NOT_RUN;
}
@@ -2665,7 +2665,7 @@ AST_TEST_DEFINE(configuration_file_wizard_retrieve_field)
return AST_TEST_FAIL;
}
- if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf")) {
+ if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf") != AST_SORCERY_APPLY_SUCCESS) {
ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
return AST_TEST_NOT_RUN;
}
@@ -2728,7 +2728,7 @@ AST_TEST_DEFINE(configuration_file_wizard_retrieve_multiple)
return AST_TEST_FAIL;
}
- if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf")) {
+ if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf") != AST_SORCERY_APPLY_SUCCESS) {
ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
return AST_TEST_NOT_RUN;
}
@@ -2799,7 +2799,7 @@ AST_TEST_DEFINE(configuration_file_wizard_retrieve_multiple_all)
return AST_TEST_FAIL;
}
- if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf")) {
+ if (ast_sorcery_apply_default(sorcery, "test", "config", "test_sorcery.conf") != AST_SORCERY_APPLY_SUCCESS) {
ast_test_status_update(test, "Could not set a default wizard of the 'config' type, so skipping since it may not be loaded\n");
return AST_TEST_NOT_RUN;
}
diff --git a/tests/test_sorcery_astdb.c b/tests/test_sorcery_astdb.c
index 41e7adbc9..b87ed74f8 100644
--- a/tests/test_sorcery_astdb.c
+++ b/tests/test_sorcery_astdb.c
@@ -60,7 +60,7 @@ static struct ast_sorcery *alloc_and_initialize_sorcery(void)
return NULL;
}
- if (ast_sorcery_apply_default(sorcery, "test", "astdb", "test") ||
+ if ((ast_sorcery_apply_default(sorcery, "test", "astdb", "test") != AST_SORCERY_APPLY_SUCCESS) ||
ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL)) {
ast_sorcery_unref(sorcery);
return NULL;
diff --git a/tests/test_sorcery_realtime.c b/tests/test_sorcery_realtime.c
index 7cf42d210..e3d0a4b37 100644
--- a/tests/test_sorcery_realtime.c
+++ b/tests/test_sorcery_realtime.c
@@ -212,7 +212,7 @@ static struct ast_sorcery *alloc_and_initialize_sorcery(void)
return NULL;
}
- if (ast_sorcery_apply_default(sorcery, "test", "realtime", "sorcery_realtime_test") ||
+ if ((ast_sorcery_apply_default(sorcery, "test", "realtime", "sorcery_realtime_test") != AST_SORCERY_APPLY_SUCCESS) ||
ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL) ||
!(realtime_objects = ast_config_new())) {
ast_sorcery_unref(sorcery);