diff --git a/CHANGES b/CHANGES index 037001dafc424d8fa7f097d87565a3c3fa951f22..5819d7098da596b745dd3f20e0e14c90c5999eb3 100644 --- a/CHANGES +++ b/CHANGES @@ -270,6 +270,17 @@ AMI (Asterisk Manager Interface) * AMI events now contain a SystemName field, if available. + * Local channel optimization is now conveyed in two events: + LocalOptimizationBegin and LocalOptimizationEnd. The Begin event is sent + when the Local channel driver begins attempting to optimize itself out of + the media path; the End event is sent after the channel halves have + successfully optimized themselves out of the media path. + + * Local channel information in events is now prefixed with "LocalOne" and + "LocalTwo". This replaces the suffix of "1" and "2" for the two halves of + the Local channel. This affects the LocalBridge, LocalOptimizationBegin, + and LocalOptimizationEnd events. + AGI (Asterisk Gateway Interface) ------------------ * The manager event AGIExec has been split into AGIExecStart and AGIExecEnd. diff --git a/include/asterisk/bridging.h b/include/asterisk/bridging.h index e03bfd0cdbb65e4d74b5dac237915aa27196d050..08d0023e5bdee7078bbe1b6ec153fa93f3cd53df 100644 --- a/include/asterisk/bridging.h +++ b/include/asterisk/bridging.h @@ -870,19 +870,23 @@ int ast_bridge_suspend(struct ast_bridge *bridge, struct ast_channel *chan); */ int ast_bridge_unsuspend(struct ast_bridge *bridge, struct ast_channel *chan); +struct ast_unreal_pvt; + /*! * \brief Check and optimize out the unreal channels between bridges. * \since 12.0.0 * * \param chan Unreal channel writing a frame into the channel driver. * \param peer Other unreal channel in the pair. + * \param pvt Private data provided by an implementation of the unreal driver that + * contains the callbacks that should be called when optimization begins/ends * * \note It is assumed that chan is already locked. * * \retval 0 if unreal channels were not optimized out. * \retval non-zero if unreal channels were optimized out. */ -int ast_bridge_unreal_optimized_out(struct ast_channel *chan, struct ast_channel *peer); +int ast_bridge_unreal_optimize_out(struct ast_channel *chan, struct ast_channel *peer, struct ast_unreal_pvt *pvt); /*! * \brief Tells, if optimization is allowed, how the optimization would be performed diff --git a/include/asterisk/core_local.h b/include/asterisk/core_local.h index 693c93b4679ea936a4e300560269c157e3cd2f82..491112d2bf0a2514c0aa57c1aaf04348411bab3e 100644 --- a/include/asterisk/core_local.h +++ b/include/asterisk/core_local.h @@ -37,6 +37,7 @@ extern "C" { struct ast_channel; struct ast_bridge; struct ast_bridge_features; +struct stasis_message_type; /* ------------------------------------------------------------------- */ @@ -91,6 +92,44 @@ int ast_local_setup_masquerade(struct ast_channel *ast, struct ast_channel *masq /* ------------------------------------------------------------------- */ +/*! + * \brief Message type for when two local channel halves are bridged together + * \since 12.0.0 + * + * \note Payloads for the \ref ast_local_bridge_type are a \ref ast_multi_channel_blob. + * Roles for the channels in the \ref ast_multi_channel_blob are "1" and "2", reflecting + * the two halves. Unlike most other bridges, the 'bridge' between two local channels is + * not part of the bridge framework; as such, the message simply references the two local + * channel halves that are now bridged. + * + * \retval A \ref stasis message type + */ +struct stasis_message_type *ast_local_bridge_type(void); + +/*! + * \brief Message type for when a local channel optimization begins + * \since 12.0.0 + * + * \note Payloads for the \ref ast_local_optimization_begin_type are a + * \ref ast_multi_channel_blob. Roles for the channels in the \ref ast_multi_channel_blob + * are "1" and "2", reflecting the two halves. + * + * \retval A \ref stasis message type + */ +struct stasis_message_type *ast_local_optimization_begin_type(void); + +/*! + * \brief Message type for when a local channel optimization completes + * \since 12.0.0 + * + * \note Payloads for the \ref ast_local_optimization_end_type are a + * \ref ast_multi_channel_blob. Roles for the channels in the \ref ast_multi_channel_blob + * are "1" and "2", reflecting the two halves. + * + * \retval A \ref stasis message type + */ +struct stasis_message_type *ast_local_optimization_end_type(void); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/include/asterisk/core_unreal.h b/include/asterisk/core_unreal.h index 7cb68f162307607d84df9f4d7c8c64ba575a9e62..a6e98895ac475d462c4b0119517ce7e546b60b2a 100644 --- a/include/asterisk/core_unreal.h +++ b/include/asterisk/core_unreal.h @@ -43,6 +43,30 @@ struct ast_callid; /* ------------------------------------------------------------------- */ +struct ast_unreal_pvt; + +/*! + * \brief Callbacks that can be provided by concrete implementations of the unreal + * channel driver that will be called when events occur in the unreal layer + */ +struct ast_unreal_pvt_callbacks { + /*! + * \brief Called when an optimization attempt has started + * \note p is locked when this callback is called + * \param p The \ref ast_unreal_pvt object + */ + void (* const optimization_started)(struct ast_unreal_pvt *p); + + /*! + * \brief Called when an optimization attempt completed successfully + * \note p is locked when this callback is called + * \param p The \ref ast_unreal_pvt object + * \param success Non-zero if the optimization succeeded, zero if the optimization + * met with fatal and permanent error + */ + void (* const optimization_finished)(struct ast_unreal_pvt *p); +}; + /*! * \brief The base pvt structure for local channel derivatives. * @@ -51,11 +75,12 @@ struct ast_callid; * ast_chan owner -> ast_unreal_pvt -> ast_chan chan */ struct ast_unreal_pvt { - struct ast_channel *owner; /*!< Master Channel - ;1 side */ - struct ast_channel *chan; /*!< Outbound channel - ;2 side */ - struct ast_format_cap *reqcap; /*!< Requested format capabilities */ - struct ast_jb_conf jb_conf; /*!< jitterbuffer configuration */ - unsigned int flags; /*!< Private option flags */ + struct ast_unreal_pvt_callbacks *callbacks; /*!< Event callbacks */ + struct ast_channel *owner; /*!< Master Channel - ;1 side */ + struct ast_channel *chan; /*!< Outbound channel - ;2 side */ + struct ast_format_cap *reqcap; /*!< Requested format capabilities */ + struct ast_jb_conf jb_conf; /*!< jitterbuffer configuration */ + unsigned int flags; /*!< Private option flags */ /*! Base name of the unreal channels. exten@context or other name. */ char name[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2]; }; @@ -65,6 +90,7 @@ struct ast_unreal_pvt { #define AST_UNREAL_CARETAKER_THREAD (1 << 0) /*!< The ;2 side launched a PBX, was pushed into a bridge, or was masqueraded into an application. */ #define AST_UNREAL_NO_OPTIMIZATION (1 << 1) /*!< Do not optimize out the unreal channels */ #define AST_UNREAL_MOH_INTERCEPT (1 << 2) /*!< Intercept and act on hold/unhold control frames */ +#define AST_UNREAL_OPTIMIZE_BEGUN (1 << 3) /*!< Indicates that an optimization attempt has been started */ /*! * \brief Send an unreal pvt in with no locks held and get all locks diff --git a/main/bridging.c b/main/bridging.c index 1dc8b6ea325035b82c19f854fb77280031b09787..d01a66ad7cd485b0ae64805ec5baa26defa14973 100644 --- a/main/bridging.c +++ b/main/bridging.c @@ -61,6 +61,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/cli.h" #include "asterisk/parking.h" #include "asterisk/core_local.h" +#include "asterisk/core_unreal.h" #include "asterisk/features_config.h" /*! All bridges container. */ @@ -628,6 +629,12 @@ static void bridge_channel_pull(struct ast_bridge_channel *bridge_channel) ast_debug(1, "Bridge %s: pulling %p(%s)\n", bridge->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan)); + ast_verb(3, "Channel %s left '%s' %s-bridge <%s>\n", + ast_channel_name(bridge_channel->chan), + bridge->technology->name, + bridge->v_table->name, + bridge->uniqueid); + /* BUGBUG This is where incoming HOLD/UNHOLD memory should write UNHOLD into bridge. (if not local optimizing) */ /* BUGBUG This is where incoming DTMF begin/end memory should write DTMF end into bridge. (if not local optimizing) */ if (!bridge_channel->just_joined) { @@ -713,6 +720,16 @@ static int bridge_channel_push(struct ast_bridge_channel *bridge_channel) if (!bridge_channel->suspended) { ++bridge->num_active; } + + ast_verb(3, "Channel %s %s%s%s '%s' %s-bridge <%s>\n", + ast_channel_name(bridge_channel->chan), + swap ? "swapped with " : "joined", + swap ? ast_channel_name(swap->chan) : "", + swap ? " into" : "", + bridge->technology->name, + bridge->v_table->name, + bridge->uniqueid); + ast_bridge_publish_enter(bridge, bridge_channel->chan); if (swap) { ast_bridge_change_state(swap, AST_BRIDGE_CHANNEL_STATE_HANGUP); @@ -1895,7 +1912,7 @@ static int smart_bridge_operation(struct ast_bridge *bridge) * must not release the bridge lock until we have installed the * new bridge technology. */ - ast_debug(1, "Bridge %s: switching %s technology to %s\n", + ast_verb(4, "Bridge %s: switching from %s technology to %s\n", bridge->uniqueid, old_technology->name, new_technology->name); /* @@ -4644,14 +4661,17 @@ static enum bridge_allow_swap bridges_allow_swap_optimization(struct ast_bridge * \param chan_bridge_channel * \param peer_bridge * \param peer_bridge_channel + * \param pvt Unreal data containing callbacks to call if the optimization actually + * happens * * \retval 1 if unreal channels failed to optimize out. * \retval 0 if unreal channels were not optimized out. * \retval -1 if unreal channels were optimized out. */ -static int check_swap_optimize_out(struct ast_bridge *chan_bridge, +static int try_swap_optimize_out(struct ast_bridge *chan_bridge, struct ast_bridge_channel *chan_bridge_channel, struct ast_bridge *peer_bridge, - struct ast_bridge_channel *peer_bridge_channel) + struct ast_bridge_channel *peer_bridge_channel, + struct ast_unreal_pvt *pvt) { struct ast_bridge *dst_bridge; struct ast_bridge_channel *dst_bridge_channel; @@ -4696,10 +4716,18 @@ static int check_swap_optimize_out(struct ast_bridge *chan_bridge, ast_channel_name(dst_bridge_channel->chan), ast_channel_name(other->chan)); + if (pvt && !ast_test_flag(pvt, AST_UNREAL_OPTIMIZE_BEGUN) && pvt->callbacks + && pvt->callbacks->optimization_started) { + pvt->callbacks->optimization_started(pvt); + ast_set_flag(pvt, AST_UNREAL_OPTIMIZE_BEGUN); + } other->swap = dst_bridge_channel->chan; if (!bridge_move_do(dst_bridge, other, 1)) { ast_bridge_change_state(src_bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP); res = -1; + if (pvt && pvt->callbacks && pvt->callbacks->optimization_finished) { + pvt->callbacks->optimization_finished(pvt); + } } } return res; @@ -4761,13 +4789,16 @@ static enum bridge_allow_merge bridges_allow_merge_optimization(struct ast_bridg * \param chan_bridge_channel * \param peer_bridge * \param peer_bridge_channel + * \param pvt Unreal data containing callbacks to call if the optimization actually + * happens * * \retval 0 if unreal channels were not optimized out. * \retval -1 if unreal channels were optimized out. */ -static int check_merge_optimize_out(struct ast_bridge *chan_bridge, +static int try_merge_optimize_out(struct ast_bridge *chan_bridge, struct ast_bridge_channel *chan_bridge_channel, struct ast_bridge *peer_bridge, - struct ast_bridge_channel *peer_bridge_channel) + struct ast_bridge_channel *peer_bridge_channel, + struct ast_unreal_pvt *pvt) { struct merge_direction merge; struct ast_bridge_channel *kick_me[] = { @@ -4798,12 +4829,20 @@ static int check_merge_optimize_out(struct ast_bridge *chan_bridge, ast_channel_name(chan_bridge_channel->chan), ast_channel_name(peer_bridge_channel->chan)); + if (pvt && !ast_test_flag(pvt, AST_UNREAL_OPTIMIZE_BEGUN) && pvt->callbacks + && pvt->callbacks->optimization_started) { + pvt->callbacks->optimization_started(pvt); + ast_set_flag(pvt, AST_UNREAL_OPTIMIZE_BEGUN); + } bridge_merge_do(merge.dest, merge.src, kick_me, ARRAY_LEN(kick_me)); + if (pvt && pvt->callbacks && pvt->callbacks->optimization_finished) { + pvt->callbacks->optimization_finished(pvt); + } return -1; } -int ast_bridge_unreal_optimized_out(struct ast_channel *chan, struct ast_channel *peer) +int ast_bridge_unreal_optimize_out(struct ast_channel *chan, struct ast_channel *peer, struct ast_unreal_pvt *pvt) { struct ast_bridge *chan_bridge; struct ast_bridge *peer_bridge; @@ -4821,11 +4860,11 @@ int ast_bridge_unreal_optimized_out(struct ast_channel *chan, struct ast_channel if (peer_bridge) { peer_bridge_channel = ast_channel_internal_bridge_channel(peer); - res = check_swap_optimize_out(chan_bridge, chan_bridge_channel, - peer_bridge, peer_bridge_channel); + res = try_swap_optimize_out(chan_bridge, chan_bridge_channel, + peer_bridge, peer_bridge_channel, pvt); if (!res) { - res = check_merge_optimize_out(chan_bridge, chan_bridge_channel, - peer_bridge, peer_bridge_channel); + res = try_merge_optimize_out(chan_bridge, chan_bridge_channel, + peer_bridge, peer_bridge_channel, pvt); } else if (0 < res) { res = 0; } diff --git a/main/core_local.c b/main/core_local.c index 16abc428cfc217c1306a2180d06880d7f00a5282..b35e03110b7d265c00bb07e15f6d9e7cf804417c 100644 --- a/main/core_local.c +++ b/main/core_local.c @@ -46,6 +46,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/bridging.h" #include "asterisk/core_unreal.h" #include "asterisk/core_local.h" +#include "asterisk/stasis.h" +#include "asterisk/stasis_channels.h" #include "asterisk/_private.h" #include "asterisk/stasis_channels.h" @@ -161,6 +163,34 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") </syntax> </managerEventInstance> </managerEvent> + <managerEvent language="en_US" name="LocalOptimizationBegin"> + <managerEventInstance class="EVENT_FLAG_CALL"> + <synopsis>Raised when two halves of a Local Channel begin to optimize + themselves out of the media path.</synopsis> + <syntax> + <xi:include xpointer="xpointer(/docs/managerEvent[@name='LocalBridge']/managerEventInstance/syntax/parameter[contains(@name, 'LocalOne')])" /> + <xi:include xpointer="xpointer(/docs/managerEvent[@name='LocalBridge']/managerEventInstance/syntax/parameter[contains(@name, 'LocalTwo')])" /> + </syntax> + <see-also> + <ref type="managerEvent">LocalOptimizationEnd</ref> + <ref type="manager">LocalOptimizeAway</ref> + </see-also> + </managerEventInstance> + </managerEvent> + <managerEvent language="en_US" name="LocalOptimizationEnd"> + <managerEventInstance class="EVENT_FLAG_CALL"> + <synopsis>Raised when two halves of a Local Channel have finished optimizing + themselves out of the media path.</synopsis> + <syntax> + <xi:include xpointer="xpointer(/docs/managerEvent[@name='LocalBridge']/managerEventInstance/syntax/parameter[contains(@name, 'LocalOne')])" /> + <xi:include xpointer="xpointer(/docs/managerEvent[@name='LocalBridge']/managerEventInstance/syntax/parameter[contains(@name, 'LocalTwo')])" /> + </syntax> + <see-also> + <ref type="managerEvent">LocalOptimizationBegin</ref> + <ref type="manager">LocalOptimizeAway</ref> + </see-also> + </managerEventInstance> + </managerEvent> ***/ static const char tdesc[] = "Local Proxy Channel Driver"; @@ -171,6 +201,30 @@ static struct ast_channel *local_request(const char *type, struct ast_format_cap static int local_call(struct ast_channel *ast, const char *dest, int timeout); static int local_hangup(struct ast_channel *ast); static int local_devicestate(const char *data); +static void local_optimization_started_cb(struct ast_unreal_pvt *base); +static void local_optimization_finished_cb(struct ast_unreal_pvt *base); + +static struct ast_manager_event_blob *local_message_to_ami(struct stasis_message *msg); + +/*! + * @{ \brief Define local channel message types. + */ +STASIS_MESSAGE_TYPE_DEFN(ast_local_bridge_type, + .to_ami = local_message_to_ami, + ); +STASIS_MESSAGE_TYPE_DEFN(ast_local_optimization_begin_type, + .to_ami = local_message_to_ami, + ); +STASIS_MESSAGE_TYPE_DEFN(ast_local_optimization_end_type, + .to_ami = local_message_to_ami, + ); +/*! @} */ + +/*! \brief Callbacks from the unreal core when channel optimization occurs */ +struct ast_unreal_pvt_callbacks local_unreal_callbacks = { + .optimization_started = local_optimization_started_cb, + .optimization_finished = local_optimization_finished_cb, +}; /* PBX interface structure for channel registration */ static struct ast_channel_tech local_tech = { @@ -326,59 +380,115 @@ static int local_devicestate(const char *data) return res; } -static struct ast_manager_event_blob *local_bridge_to_ami(struct stasis_message *msg) +static void publish_local_optimization(struct local_pvt *p, int complete) { - RAII_VAR(struct ast_str *, channel_one_string, NULL, ast_free); - RAII_VAR(struct ast_str *, channel_two_string, NULL, ast_free); - struct ast_multi_channel_blob *obj = stasis_message_data(msg); - struct ast_json *blob, *context, *exten, *optimize; - struct ast_channel_snapshot *chan_one, *chan_two; - - chan_one = ast_multi_channel_blob_get_channel(obj, "1"); - chan_two = ast_multi_channel_blob_get_channel(obj, "2"); - blob = ast_multi_channel_blob_get_json(obj); - - channel_one_string = ast_manager_build_channel_state_string_prefix(chan_one, "LocalOne"); - if (!channel_one_string) { + RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup); + RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); + RAII_VAR(struct ast_json *, blob, ast_json_null(), ast_json_unref); + RAII_VAR(struct ast_channel_snapshot *, local_one_snapshot, NULL, ao2_cleanup); + RAII_VAR(struct ast_channel_snapshot *, local_two_snapshot, NULL, ao2_cleanup); + + if (!blob) { + return; + } + + local_one_snapshot = ast_channel_snapshot_create(p->base.owner); + if (!local_one_snapshot) { + return; + } + + local_two_snapshot = ast_channel_snapshot_create(p->base.chan); + if (!local_two_snapshot) { + return; + } + + payload = ast_multi_channel_blob_create(blob); + if (!payload) { + return; + } + ast_multi_channel_blob_add_channel(payload, "1", local_one_snapshot); + ast_multi_channel_blob_add_channel(payload, "2", local_two_snapshot); + + msg = stasis_message_create( + complete ? ast_local_optimization_end_type() : ast_local_optimization_begin_type(), + payload); + if (!msg) { + return; + } + + stasis_publish(ast_channel_topic(p->base.owner), msg); + +} + +/*! \brief Callback for \ref ast_unreal_pvt_callbacks \ref optimization_started_cb */ +static void local_optimization_started_cb(struct ast_unreal_pvt *base) +{ + struct local_pvt *p = (struct local_pvt *)base; + publish_local_optimization(p, 0); +} + +/*! \brief Callback for \ref ast_unreal_pvt_callbacks \ref optimization_finished_cb */ +static void local_optimization_finished_cb(struct ast_unreal_pvt *base) +{ + struct local_pvt *p = (struct local_pvt *)base; + publish_local_optimization(p, 1); +} + +static struct ast_manager_event_blob *local_message_to_ami(struct stasis_message *message) +{ + struct ast_multi_channel_blob *obj = stasis_message_data(message); + struct ast_json *blob = ast_multi_channel_blob_get_json(obj); + struct ast_channel_snapshot *local_snapshot_one; + struct ast_channel_snapshot *local_snapshot_two; + RAII_VAR(struct ast_str *, local_channel_one, NULL, ast_free); + RAII_VAR(struct ast_str *, local_channel_two, NULL, ast_free); + struct ast_str *event_buffer = ast_str_alloca(128); + const char *event; + + local_snapshot_one = ast_multi_channel_blob_get_channel(obj, "1"); + local_snapshot_two = ast_multi_channel_blob_get_channel(obj, "2"); + if (!local_snapshot_one || !local_snapshot_two) { return NULL; } - channel_two_string = ast_manager_build_channel_state_string_prefix(chan_two, "LocalTwo"); - if (!channel_two_string) { + local_channel_one = ast_manager_build_channel_state_string_prefix(local_snapshot_one, "LocalOne"); + local_channel_two = ast_manager_build_channel_state_string_prefix(local_snapshot_two, "LocalTwo"); + if (!local_channel_one || !local_channel_two) { return NULL; } - context = ast_json_object_get(blob, "context"); - exten = ast_json_object_get(blob, "exten"); - optimize = ast_json_object_get(blob, "optimize"); + if (stasis_message_type(message) == ast_local_optimization_begin_type()) { + event = "LocalOptimizationBegin"; + } else if (stasis_message_type(message) == ast_local_optimization_end_type()) { + event = "LocalOptimizationEnd"; + } else if (stasis_message_type(message) == ast_local_bridge_type()) { + event = "LocalBridge"; + ast_str_append(&event_buffer, 0, "Context: %s\r\n", ast_json_string_get(ast_json_object_get(blob, "context"))); + ast_str_append(&event_buffer, 0, "Exten: %s\r\n", ast_json_string_get(ast_json_object_get(blob, "exten"))); + ast_str_append(&event_buffer, 0, "LocalOptimization: %s\r\n", ast_json_is_true(ast_json_object_get(blob, "can_optimize")) ? "Yes" : "No"); + } else { + return NULL; + } - return ast_manager_event_blob_create(EVENT_FLAG_CALL, "LocalBridge", + return ast_manager_event_blob_create(EVENT_FLAG_CALL, event, "%s" "%s" - "Context: %s\r\n" - "Exten: %s\r\n" - "LocalOptimization: %s\r\n", - ast_str_buffer(channel_one_string), - ast_str_buffer(channel_two_string), - ast_json_string_get(context), - ast_json_string_get(exten), - ast_json_is_true(optimize) ? "Yes" : "No"); + "%s", + ast_str_buffer(local_channel_one), + ast_str_buffer(local_channel_two), + ast_str_buffer(event_buffer)); } -STASIS_MESSAGE_TYPE_DEFN_LOCAL(local_bridge_type, - .to_ami = local_bridge_to_ami, - ); - /*! * \internal - * \brief Post the LocalBridge AMI event. + * \brief Post the \ref ast_local_bridge_type \ref stasis message * \since 12.0.0 * - * \param p local_pvt to raise the bridge event. + * \param p local_pvt to raise the local bridge message * * \return Nothing */ -static void local_bridge_event(struct local_pvt *p) +static void publish_local_bridge_message(struct local_pvt *p) { RAII_VAR(struct ast_multi_channel_blob *, multi_blob, NULL, ao2_cleanup); RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref); @@ -390,7 +500,7 @@ static void local_bridge_event(struct local_pvt *p) blob = ast_json_pack("{s: s, s: s, s: b}", "context", p->context, "exten", p->exten, - "optimize", ast_test_flag(&p->base, AST_UNREAL_NO_OPTIMIZATION)); + "can_optimize", !ast_test_flag(&p->base, AST_UNREAL_NO_OPTIMIZATION)); if (!blob) { return; } @@ -413,7 +523,7 @@ static void local_bridge_event(struct local_pvt *p) ast_multi_channel_blob_add_channel(multi_blob, "1", one_snapshot); ast_multi_channel_blob_add_channel(multi_blob, "2", two_snapshot); - msg = stasis_message_create(local_bridge_type(), multi_blob); + msg = stasis_message_create(ast_local_bridge_type(), multi_blob); if (!msg) { return; } @@ -564,14 +674,14 @@ static int local_call(struct ast_channel *ast, const char *dest, int timeout) ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->exten, p->context); } else { - local_bridge_event(p); + publish_local_bridge_message(p); /* Start switch on sub channel */ res = ast_pbx_start(chan); } break; case LOCAL_CALL_ACTION_BRIDGE: - local_bridge_event(p); + publish_local_bridge_message(p); ast_answer(chan); res = ast_bridge_impart(p->action.bridge.join, chan, p->action.bridge.swap, p->action.bridge.features, 1); @@ -582,7 +692,7 @@ static int local_call(struct ast_channel *ast, const char *dest, int timeout) p->action.bridge.features = NULL; break; case LOCAL_CALL_ACTION_MASQUERADE: - local_bridge_event(p); + publish_local_bridge_message(p); ast_answer(chan); res = ast_channel_move(p->action.masq, chan); if (!res) { @@ -699,6 +809,7 @@ static struct local_pvt *local_alloc(const char *data, struct ast_format_cap *ca if (!pvt) { return NULL; } + pvt->base.callbacks = &local_unreal_callbacks; parse = ast_strdupa(data); @@ -883,12 +994,24 @@ static void local_shutdown(void) locals = NULL; ast_format_cap_destroy(local_tech.capabilities); - STASIS_MESSAGE_TYPE_CLEANUP(local_bridge_type); + + STASIS_MESSAGE_TYPE_CLEANUP(ast_local_optimization_begin_type); + STASIS_MESSAGE_TYPE_CLEANUP(ast_local_optimization_end_type); + STASIS_MESSAGE_TYPE_CLEANUP(ast_local_bridge_type); } int ast_local_init(void) { - if (STASIS_MESSAGE_TYPE_INIT(local_bridge_type)) { + + if (STASIS_MESSAGE_TYPE_INIT(ast_local_optimization_begin_type)) { + return -1; + } + + if (STASIS_MESSAGE_TYPE_INIT(ast_local_optimization_end_type)) { + return -1; + } + + if (STASIS_MESSAGE_TYPE_INIT(ast_local_bridge_type)) { return -1; } diff --git a/main/core_unreal.c b/main/core_unreal.c index d5e5881117df2eeb6e2d47236805b73757a6a1f5..71d0f6c8f51ba1a880af08fe50b1c2eb9c935448 100644 --- a/main/core_unreal.c +++ b/main/core_unreal.c @@ -281,18 +281,20 @@ int ast_unreal_answer(struct ast_channel *ast) */ static int got_optimized_out(struct ast_channel *ast, struct ast_unreal_pvt *p) { + int res = 0; + /* Do a few conditional checks early on just to see if this optimization is possible */ if (ast_test_flag(p, AST_UNREAL_NO_OPTIMIZATION) || !p->chan || !p->owner) { - return 0; + return res; } + if (ast == p->owner) { - return ast_bridge_unreal_optimized_out(p->owner, p->chan); + res = ast_bridge_unreal_optimize_out(p->owner, p->chan, p); + } else if (ast == p->chan) { + res = ast_bridge_unreal_optimize_out(p->chan, p->owner, p); } - if (ast == p->chan) { - return ast_bridge_unreal_optimized_out(p->chan, p->owner); - } - /* ast is not valid to optimize. */ - return 0; + + return res; } struct ast_frame *ast_unreal_read(struct ast_channel *ast)