diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c
index 271f8564eab6e054cf75a096a47550f6a8bf5f95..e2ab2135f3eb9d600e463d4d1bd60cbc240faad2 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 ee130036039a6e68572f984ef3d9ee8fcee1abd4..7406214fbe3f9f1d0f704015ee84e46dbd4ea60c 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 17f7c896589672d57c5bf394e13d6690f20f7ba1..bdbc596e64de4f4bb3e5f677217fe0a2a63103dd 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 73c65701965ead98fdd26aa247f0cacdfc9cccc2..c8aaf890682dc4545269b4fdecd4816fcbd56718 100644
--- a/include/asterisk/bridge_channel.h
+++ b/include/asterisk/bridge_channel.h
@@ -528,6 +528,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.
  *
diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h
index 53383834f1023b99d367573c8faca813839f5b97..846832aff743379d3a0087f72d76954b5cbfbbba 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 026fb4074bd379d23b59687323ad4277a85c12a7..22616d5b4fb1592145dbcacb735a6f4aed4cfde5 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 06da4eeedff28a1c37963676f6a5dfdc01091a6b..75008fe188f225da0a1cecab9d21154335787766 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,
@@ -505,6 +645,52 @@ static int bridge_channel_queue_action_data(struct ast_bridge_channel *bridge_ch
 	return ast_bridge_channel_queue_frame(bridge_channel, &frame);
 }
 
+/*!
+ * \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.
@@ -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 6145e350576112ea6881fa6c1b78f5c58c3ffbf1..b264a2170e902d81c6ed08b5566f4245b99d8ce7 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 8713ce40d6ce901b17d05056b7d22865b4f7385f..1b13abc690d596e715f501793d35c5dadc6e94b0 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 2ab4933beb94346b9a0ef3691730344619447325..94a11103ba81402f276051dc9bd6a81688ab2d8a 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 c3fc0eaf405c59ece461207099a66b7a242e9ebd..875f3277347a1d7ebd73e50b7b7d2bac27d19dd6 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 bdf53149f43c427af164cd7926001abb4e6a6f81..8fae6b74c5eaa3848b856cc38ae7121ef90ff664 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 1f289ade9376cf87a2a8583e776947ff4d792e80..0a34334505801f48123be55422426b1f8c057f3d 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 ee4a20bccbc43c544c1c6d6a291748f0f59f91ed..299cb4483788c88f32538329de856d88dd43ea92 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 ed4d604e6ba3f251201f969187037ff2312b5534..aa34a11d3a8f59dfa1fc459792c0b73d89fdf4e2 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 41e7adbc95cf94444d6836e4beaf804a383f6166..b87ed74f8686a60bce9c25ab91a381c97d0e3d8c 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 7cf42d2107ee0e9867899b8705e3c29d4bcb928a..e3d0a4b3728e3f842bdf5964ac4569b48af7a1e2 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);