[asterisk-commits] jrose: branch jrose/bridge_projects r384328 - in /team/jrose/bridge_projects:...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Mar 29 11:48:41 CDT 2013
Author: jrose
Date: Fri Mar 29 11:48:37 2013
New Revision: 384328
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=384328
Log:
Progress up to March 29
Modified:
team/jrose/bridge_projects/include/asterisk/bridging.h
team/jrose/bridge_projects/include/asterisk/parking.h
team/jrose/bridge_projects/main/bridging.c
team/jrose/bridge_projects/main/features.c
team/jrose/bridge_projects/main/manager_channels.c
team/jrose/bridge_projects/res/parking/parking_applications.c
team/jrose/bridge_projects/res/parking/parking_bridge.c
team/jrose/bridge_projects/res/parking/parking_controller.c
team/jrose/bridge_projects/res/parking/res_parking.h
team/jrose/bridge_projects/res/res_parking.c
Modified: team/jrose/bridge_projects/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/include/asterisk/bridging.h?view=diff&rev=384328&r1=384327&r2=384328
==============================================================================
--- team/jrose/bridge_projects/include/asterisk/bridging.h (original)
+++ team/jrose/bridge_projects/include/asterisk/bridging.h Fri Mar 29 11:48:37 2013
@@ -675,6 +675,22 @@
int ast_bridge_merge(struct ast_bridge *bridge1, struct ast_bridge *bridge2);
/*!
+ * \brief XXX Hack function for moving a channel from one bridge to another
+ *
+ * \param bridge_src bridge the channel is being moved from
+ * \param bridge_dst bridge the chnanel is being moved to
+ * \param chan Channel being moved
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * \code
+ * ast_bridge_move(old_bridge, new_bridge, chan);
+ * \endcode
+ */
+int ast_bridge_move(struct ast_bridge *bridge_src, struct ast_bridge *bridge_dst, struct ast_channel *chan);
+
+/*!
* \brief Adjust the bridge merge inhibit request count.
* \since 12.0.0
*
Modified: team/jrose/bridge_projects/include/asterisk/parking.h
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/include/asterisk/parking.h?view=diff&rev=384328&r1=384327&r2=384328
==============================================================================
--- team/jrose/bridge_projects/include/asterisk/parking.h (original)
+++ team/jrose/bridge_projects/include/asterisk/parking.h Fri Mar 29 11:48:37 2013
@@ -52,10 +52,49 @@
);
};
-/*! \brief Constructor for parked_call_payload objects */
+/*!
+ * \brief Constructor for parked_call_payload objects
+ * \since 12
+ *
+ * \param event_type What kind of parked call event is happening
+ * \param parkee_snapshot channel snapshot of the parkee
+ * \param parker_snapshot channel snapshot of the parker
+ * \param parkinglot name of the parking lot where the parked call is parked
+ * \param parkingspace what numerical parking space the parked call is parked in
+ * \param timeout how long the parked call can remain at the point this snapshot is created before timing out
+ * \param duration how long the parked call has currently been parked
+ *
+ * \retval NULL if the parked call payload can't be allocated
+ * \retval reference to a newly created parked call payload
+ */
struct ast_parked_call_payload *ast_parked_call_payload_create(enum ast_parked_call_event_type event_type, struct ast_channel_snapshot *parkee_snapshot, struct ast_channel_snapshot *parker_snapshot, const char *parkinglot, int parkingspace, long int timeout, long int duration);
+/*!
+ * \brief initialize parking stasis types
+ * \since 12
+ */
void ast_parking_stasis_init(void);
+
+/*!
+ * \brief disable parking stasis types
+ * \since 12
+ */
void ast_parking_stasis_disable(void);
+
+/*!
+ * \brief accessor for the parking stasis topic
+ * \since 12
+ *
+ * \retval NULL if the parking topic hasn't been created or has been disabled
+ * \retval a pointer to the parking topic
+ */
struct stasis_topic *ast_parking_topic(void);
+
+/*!
+ * \brief accessor for the parked call stasis message type
+ * \since 12
+ *
+ * \retval NULL if the parking topic hasn't been created or has been canceled
+ * \retval a pointer to the parked call message type
+ */
struct stasis_message_type *ast_parked_call_type(void);
Modified: team/jrose/bridge_projects/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/main/bridging.c?view=diff&rev=384328&r1=384327&r2=384328
==============================================================================
--- team/jrose/bridge_projects/main/bridging.c (original)
+++ team/jrose/bridge_projects/main/bridging.c Fri Mar 29 11:48:37 2013
@@ -2614,6 +2614,66 @@
ast_debug(1, "Merged channels from bridge %p into bridge %p\n", bridge2, bridge1);
}
+static void ast_bridge_move_do(struct ast_bridge *bridge_src, struct ast_bridge *bridge_dst, struct ast_channel *chan)
+{
+ struct ast_bridge_channel *bridge_channel;
+
+ ast_debug(1, "Moving channel %s from bridge %p into bridge %p\n", ast_channel_name(chan), bridge_src, bridge_dst);
+
+ AST_LIST_TRAVERSE(&bridge_src->channels, bridge_channel, entry) {
+ if (bridge_channel->chan == chan) {
+ break;
+ }
+ }
+
+ ast_bridge_channel_pull(bridge_channel);
+
+ /* Point to new bridge. */
+ ao2_ref(bridge_dst, +1);
+ ast_bridge_channel_lock(bridge_channel);
+ bridge_channel->bridge = bridge_dst;
+ ast_bridge_channel_unlock(bridge_channel);
+ ao2_ref(bridge_src, -1);
+
+ ast_bridge_channel_push(bridge_channel);
+
+ ast_bridge_reconfigured(bridge_dst);
+ ast_bridge_reconfigured(bridge_src);
+
+ ast_debug(1, "Moved channel %s from bridge %p into bridge %p\n", ast_channel_name(chan), bridge_src, bridge_dst);
+}
+
+int ast_bridge_move(struct ast_bridge *bridge_src, struct ast_bridge *bridge_dst, struct ast_channel *chan)
+{
+ int res = -1;
+
+ /* Deadlock avoidance. */
+ for (;;) {
+ ast_bridge_lock(bridge_src);
+ if (!ast_bridge_trylock(bridge_dst)) {
+ break;
+ }
+ ast_bridge_unlock(bridge_src);
+ sched_yield();
+ }
+
+ if (bridge_src->dissolved || bridge_dst->dissolved) {
+ ast_debug(1, "Can't move from bridge %p into bridge %p, one or both bridges are dissolved.\n",
+ bridge_src, bridge_dst);
+ } else {
+ ++bridge_src->inhibit_merge;
+ ++bridge_dst->inhibit_merge;
+ ast_bridge_move_do(bridge_src, bridge_dst, chan);
+ --bridge_dst->inhibit_merge;
+ --bridge_src->inhibit_merge;
+ res = 0;
+ }
+
+ ast_bridge_unlock(bridge_dst);
+ ast_bridge_unlock(bridge_src);
+ return res;
+}
+
int ast_bridge_merge(struct ast_bridge *bridge1, struct ast_bridge *bridge2)
{
int res = -1;
Modified: team/jrose/bridge_projects/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/main/features.c?view=diff&rev=384328&r1=384327&r2=384328
==============================================================================
--- team/jrose/bridge_projects/main/features.c (original)
+++ team/jrose/bridge_projects/main/features.c Fri Mar 29 11:48:37 2013
@@ -249,40 +249,7 @@
</variablelist>
</description>
</application>
- <application name="ParkedCall" language="en_US">
- <synopsis>
- Retrieve a parked call.
- </synopsis>
- <syntax>
- <parameter name="exten">
- <para>Parking space extension to retrieve a parked call.
- If not provided then the first available parked call in the
- parking lot will be retrieved.</para>
- </parameter>
- <parameter name="parking_lot_name">
- <para>Specify from which parking lot to retrieve a parked call.</para>
- <para>The parking lot used is selected in the following order:</para>
- <para>1) parking_lot_name option</para>
- <para>2) <variable>PARKINGLOT</variable> variable</para>
- <para>3) <literal>CHANNEL(parkinglot)</literal> function
- (Possibly preset by the channel driver.)</para>
- <para>4) Default parking lot.</para>
- </parameter>
- </syntax>
- <description>
- <para>Used to retrieve a parked call from a parking lot.</para>
- <note>
- <para>Parking lots automatically create and manage dialplan extensions in
- the parking lot context. You do not need to explicitly use this
- application in your dialplan. Instead, all you should do is include the
- parking lot context in your dialplan.</para>
- </note>
- </description>
- <see-also>
- <ref type="application">Park</ref>
- <ref type="application">ParkAndAnnounce</ref>
- </see-also>
- </application>
+
<manager name="Park" language="en_US">
<synopsis>
Park a channel.
@@ -4925,279 +4892,6 @@
AST_APP_OPTION('s', AST_PARK_OPT_SILENCE),
END_OPTIONS );
-/*! \brief Pickup parked call */
-static int parked_call_exec(struct ast_channel *chan, const char *data)
-{
- int res;
- struct ast_channel *peer = NULL;
- struct parkeduser *pu;
- struct ast_context *con;
- char *parse;
- const char *pl_name;
- int park = 0;
- struct ast_bridge_config config;
- struct ast_parkinglot *parkinglot;
- AST_DECLARE_APP_ARGS(app_args,
- AST_APP_ARG(pl_space); /*!< Parking lot space to retrieve if present. */
- AST_APP_ARG(pl_name); /*!< Parking lot name to use if present. */
- AST_APP_ARG(dummy); /*!< Place to put any remaining args string. */
- );
-
- parse = ast_strdupa(data);
- AST_STANDARD_APP_ARGS(app_args, parse);
-
- if (!ast_strlen_zero(app_args.pl_space)) {
- if (sscanf(app_args.pl_space, "%30u", &park) != 1) {
- ast_log(LOG_WARNING, "Specified parking extension not a number: %s\n",
- app_args.pl_space);
- park = -1;
- }
- }
-
- if (!ast_strlen_zero(app_args.pl_name)) {
- pl_name = app_args.pl_name;
- } else {
- pl_name = findparkinglotname(chan);
- }
- if (ast_strlen_zero(pl_name)) {
- /* Parking lot is not specified, so use the default parking lot. */
- parkinglot = parkinglot_addref(default_parkinglot);
- } else {
- parkinglot = find_parkinglot(pl_name);
- if (!parkinglot) {
- /* It helps to answer the channel if not already up. :) */
- if (ast_channel_state(chan) != AST_STATE_UP) {
- ast_answer(chan);
- }
- if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) {
- ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n",
- "pbx-invalidpark", ast_channel_name(chan));
- }
- ast_log(LOG_WARNING,
- "Channel %s tried to retrieve parked call from unknown parking lot '%s'\n",
- ast_channel_name(chan), pl_name);
- return -1;
- }
- }
-
- AST_LIST_LOCK(&parkinglot->parkings);
- AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) {
- if ((ast_strlen_zero(app_args.pl_space) || pu->parkingnum == park)
- && !pu->notquiteyet && !ast_channel_pbx(pu->chan)) {
- /* The parking space has a call and can be picked up now. */
- AST_LIST_REMOVE_CURRENT(list);
- break;
- }
- }
- AST_LIST_TRAVERSE_SAFE_END;
- if (pu) {
- struct ast_callid *callid = ast_read_threadstorage_callid();
-
- /* Found a parked call to pickup. */
- peer = pu->chan;
-
- /* We need to map the call id we have from this thread to the channel we found. */
- if (callid) {
- ast_channel_callid_set(peer, callid);
- callid = ast_callid_unref(callid);
- }
-
- con = ast_context_find(parkinglot->cfg.parking_con);
- if (con) {
- if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) {
- ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
- } else {
- notify_metermaids(pu->parkingexten, parkinglot->cfg.parking_con, AST_DEVICE_NOT_INUSE);
- }
- } else {
- ast_log(LOG_WARNING, "Whoa, no parking context?\n");
- }
-
- ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan);
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when a call has been unparked.</synopsis>
- <syntax>
- <xi:include xpointer="xpointer(/docs/managerEvent[@name='ParkedCall']/managerEventInstance/syntax/parameter[@name='Exten'])" />
- <xi:include xpointer="xpointer(/docs/managerEvent[@name='ParkedCall']/managerEventInstance/syntax/parameter[@name='Parkinglot'])" />
- <xi:include xpointer="xpointer(/docs/managerEvent[@name='ParkedCall']/managerEventInstance/syntax/parameter[@name='From'])" />
- </syntax>
- <see-also>
- <ref type="application">ParkedCall</ref>
- <ref type="managerEvent">ParkedCall</ref>
- </see-also>
- </managerEventInstance>
- ***/
- ast_manager_event(pu->chan, EVENT_FLAG_CALL, "UnParkedCall",
- "Exten: %s\r\n"
- "Channel: %s\r\n"
- "Parkinglot: %s\r\n"
- "From: %s\r\n"
- "CallerIDNum: %s\r\n"
- "CallerIDName: %s\r\n"
- "ConnectedLineNum: %s\r\n"
- "ConnectedLineName: %s\r\n"
- "Uniqueid: %s\r\n",
- pu->parkingexten, ast_channel_name(pu->chan), pu->parkinglot->name,
- ast_channel_name(chan),
- S_COR(ast_channel_caller(pu->chan)->id.number.valid, ast_channel_caller(pu->chan)->id.number.str, "<unknown>"),
- S_COR(ast_channel_caller(pu->chan)->id.name.valid, ast_channel_caller(pu->chan)->id.name.str, "<unknown>"),
- S_COR(ast_channel_connected(pu->chan)->id.number.valid, ast_channel_connected(pu->chan)->id.number.str, "<unknown>"),
- S_COR(ast_channel_connected(pu->chan)->id.name.valid, ast_channel_connected(pu->chan)->id.name.str, "<unknown>"),
- ast_channel_uniqueid(pu->chan)
- );
-
- /* Stop entertaining the caller. */
- switch (pu->hold_method) {
- case AST_CONTROL_HOLD:
- ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
- break;
- case AST_CONTROL_RINGING:
- ast_indicate(pu->chan, -1);
- break;
- default:
- break;
- }
- pu->hold_method = 0;
-
- parkinglot_unref(pu->parkinglot);
- ast_free(pu);
- }
- AST_LIST_UNLOCK(&parkinglot->parkings);
-
- if (peer) {
- /* Update connected line between retrieving call and parked call. */
- struct ast_party_connected_line connected;
-
- ast_party_connected_line_init(&connected);
-
- /* Send our caller-id to peer. */
- ast_channel_lock(chan);
- ast_connected_line_copy_from_caller(&connected, ast_channel_caller(chan));
- ast_channel_unlock(chan);
- connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
- if (ast_channel_connected_line_sub(chan, peer, &connected, 0) &&
- ast_channel_connected_line_macro(chan, peer, &connected, 0, 0)) {
- ast_channel_update_connected_line(peer, &connected, NULL);
- }
-
- /*
- * Get caller-id from peer.
- *
- * Update the retrieving call before it is answered if possible
- * for best results. Some phones do not support updating the
- * connected line information after connection.
- */
- ast_channel_lock(peer);
- ast_connected_line_copy_from_caller(&connected, ast_channel_caller(peer));
- ast_channel_unlock(peer);
- connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
- if (ast_channel_connected_line_sub(peer, chan, &connected, 0) &&
- ast_channel_connected_line_macro(peer, chan, &connected, 1, 0)) {
- ast_channel_update_connected_line(chan, &connected, NULL);
- }
-
- ast_party_connected_line_free(&connected);
- }
-
- /* JK02: it helps to answer the channel if not already up */
- if (ast_channel_state(chan) != AST_STATE_UP) {
- ast_answer(chan);
- }
-
- if (peer) {
- struct ast_datastore *features_datastore;
- struct ast_dial_features *dialfeatures;
-
- /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
- if (!ast_strlen_zero(courtesytone)) {
- static const char msg[] = "courtesy tone";
-
- switch (parkedplay) {
- case 0:/* Courtesy tone to pickup chan */
- res = play_message_to_chans(chan, peer, -1, msg, courtesytone);
- break;
- case 1:/* Courtesy tone to parked chan */
- res = play_message_to_chans(chan, peer, 1, msg, courtesytone);
- break;
- case 2:/* Courtesy tone to both chans */
- res = play_message_to_chans(chan, peer, 0, msg, courtesytone);
- break;
- default:
- res = 0;
- break;
- }
- if (res) {
- bridge_failed_peer_goto(chan, peer);
- parkinglot_unref(parkinglot);
- return -1;
- }
- }
-
- res = ast_channel_make_compatible(chan, peer);
- if (res < 0) {
- ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", ast_channel_name(chan), ast_channel_name(peer));
- bridge_failed_peer_goto(chan, peer);
- parkinglot_unref(parkinglot);
- return -1;
- }
- /* This runs sorta backwards, since we give the incoming channel control, as if it
- were the person called. */
- ast_verb(3, "Channel %s connected to parked call %d\n", ast_channel_name(chan), park);
-
- pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", ast_channel_name(peer));
- ast_cdr_setdestchan(ast_channel_cdr(chan), ast_channel_name(peer));
- memset(&config, 0, sizeof(struct ast_bridge_config));
-
- /* Get datastore for peer and apply it's features to the callee side of the bridge config */
- ast_channel_lock(peer);
- features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL);
- if (features_datastore && (dialfeatures = features_datastore->data)) {
- ast_copy_flags(&config.features_callee, &dialfeatures->my_features,
- AST_FLAGS_ALL);
- }
- ast_channel_unlock(peer);
-
- if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
- ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
- }
- if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
- ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
- }
- if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
- ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
- }
- if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
- ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
- }
- if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
- ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
- }
- if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
- ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
- }
- if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
- ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
- }
- if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
- ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
- }
-
- res = ast_bridge_call(chan, peer, &config);
- } else {
- if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) {
- ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark",
- ast_channel_name(chan));
- }
- ast_verb(3, "Channel %s tried to retrieve nonexistent parked call %d\n",
- ast_channel_name(chan), park);
- res = -1;
- }
-
- parkinglot_unref(parkinglot);
- return res;
-}
-
/*!
* \brief Unreference parkinglot object.
*/
@@ -8340,7 +8034,6 @@
ast_manager_unregister("Bridge");
ast_manager_unregister("Park");
- ast_unregister_application(parkedcall);
ast_unregister_application(app_bridge);
pthread_cancel(parking_thread);
@@ -8365,7 +8058,6 @@
return -1;
}
ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL);
- res = ast_register_application2(parkedcall, parked_call_exec, NULL, NULL, NULL);
if (!res) {
ast_manager_register_xml_core("Park", EVENT_FLAG_CALL, manager_park);
ast_manager_register_xml_core("Bridge", EVENT_FLAG_CALL, action_bridge);
Modified: team/jrose/bridge_projects/main/manager_channels.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/main/manager_channels.c?view=diff&rev=384328&r1=384327&r2=384328
==============================================================================
--- team/jrose/bridge_projects/main/manager_channels.c (original)
+++ team/jrose/bridge_projects/main/manager_channels.c Fri Mar 29 11:48:37 2013
@@ -204,8 +204,8 @@
if (snapshot->manager_vars) {
struct ast_var_t *var;
AST_LIST_TRAVERSE(snapshot->manager_vars, var, entries) {
- ast_str_append(&out, 0, "ChanVariable(%s): %s=%s\r\n",
- snapshot->name,
+ ast_str_append(&out, 0, " ChanVariable(%s)%s: %s=%s\r\n",
+ snapshot->name, suffix,
var->name, var->value);
}
}
Modified: team/jrose/bridge_projects/res/parking/parking_applications.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/parking/parking_applications.c?view=diff&rev=384328&r1=384327&r2=384328
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_applications.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_applications.c Fri Mar 29 11:48:37 2013
@@ -95,6 +95,40 @@
</see-also>
</application>
+ <application name="ParkedCall" language="en_US">
+ <synopsis>
+ Retrieve a parked call.
+ </synopsis>
+ <syntax>
+ <parameter name="parking_lot_name">
+ <para>Specify from which parking lot to retrieve a parked call.</para>
+ <para>The parking lot used is selected in the following order:</para>
+ <para>1) parking_lot_name option</para>
+ <para>2) <variable>PARKINGLOT</variable> variable</para>
+ <para>3) <literal>CHANNEL(parkinglot)</literal> function
+ (Possibly preset by the channel driver.)</para>
+ <para>4) Default parking lot.</para>
+ </parameter>
+ <parameter name="parking_space">
+ <para>Parking space to retrieve a parked call from.
+ If not provided then the first available parked call in the
+ parking lot will be retrieved.</para>
+ </parameter>
+ </syntax>
+ <description>
+ <para>Used to retrieve a parked call from a parking lot.</para>
+ <note>
+ <para>If a parkinglot's parkext option is set, then Parking lots
+ will automatically create and manage dialplan extensions in
+ the parking lot context. If that is the case then you will not
+ need to manage parking extensions yourself, just include the
+ parking context of the parking lot.</para>
+ </note>
+ </description>
+ <see-also>
+ <ref type="application">Park</ref>
+ </see-also>
+ </application>
***/
/* Park a call */
@@ -148,6 +182,8 @@
int time_limit = -1;
char *comeback_override = NULL;
+ int res;
+
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(lot_name);
AST_APP_ARG(options);
@@ -217,15 +253,36 @@
reset_parked_time(pu);
ast_bridge_join(parking_bridge, chan, NULL, &chan_features, NULL, 0);
+ /*
+ * If the bridge was broken for a hangup that isn't real, then
+ * don't run the h extension, because the channel isn't really
+ * hung up. This should really only happen with
+ * AST_SOFTHANGUP_ASYNCGOTO.
+ */
+ res = -1;
+ ast_channel_lock(chan);
+ if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
+ res = 0;
+ }
+ ast_channel_unlock(chan);
+
/* At this point the channel is no longer in the bridge. Start breaking things down. */
ast_bridge_features_cleanup(&chan_features);
- /* If the parked channel exits without a resolution set, it gave up. Issue a ParkedCallGiveUp message and exit early. */
- if (pu->resolution == PARK_UNSET) {
+ switch (pu->resolution) {
+ case PARK_UNSET:
+ /* If the parked channel exits without a resolution set, it gave up. Issue a ParkedCallGiveUp message and exit early. */
pu->resolution = PARK_ABANDON;
publish_parked_call(pu, PARKED_CALL_GIVEUP);
unpark_parked_user(pu);
- return -1;
+ return res;
+ case PARK_ABANDON:
+ case PARK_FORCED:
+ case PARK_ANSWERED:
+ return res;
+ case PARK_TIMEOUT:
+ /* If we timed out, we need to do some fancy stuff when we re-enter the PBX */
+ break;
}
unpark_parked_user(pu);
@@ -246,3 +303,75 @@
return ast_check_hangup_locked(chan) ? -1 : 0;
}
+
+int parked_call_app_exec(struct ast_channel *chan, const char *data)
+{
+ RAII_VAR(struct parking_lot_state *, lot, NULL, ao2_cleanup);
+ RAII_VAR(struct parked_user *, pu, NULL, ao2_cleanup); /* Parked user being retrieved */
+ RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
+ int target_space = -1;
+
+ struct ast_bridge *bridge;
+
+ //struct ast_bridge_features chan_features;
+ char *parse;
+
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(lot_name);
+ AST_APP_ARG(parking_space);
+ AST_APP_ARG(other); /* Any remaining unused arguments */
+ );
+
+ parse = ast_strdupa(data);
+ AST_STANDARD_APP_ARGS(args, parse);
+
+ if (ast_strlen_zero(args.lot_name)) {
+ lot = channel_find_parking_lot_state(chan);
+ } else {
+ lot = parking_lot_state_find_by_name(args.lot_name);
+ }
+
+ if (!lot) {
+ ast_log(LOG_ERROR, "Could not find the requested parking lot\n");
+ return -1;
+ }
+
+ if (!ast_strlen_zero(args.parking_space)) {
+ if (sscanf(args.parking_space, "%d", &target_space) != 1 || target_space < 0) {
+ ast_log(LOG_ERROR, "value '%s' for parking_space argument is invalid. Must be an integer greater than 0.\n", args.parking_space);
+ return -1;
+ }
+ }
+
+ bridge = ast_bridge_base_new(
+ AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_MULTIMIX,
+ AST_BRIDGE_FLAG_DISSOLVE_HANGUP | AST_BRIDGE_FLAG_SMART);
+
+ if (!bridge) {
+ return -1;
+ }
+
+ /* answer the channel if needed */
+ if (ast_channel_state(chan) != AST_STATE_UP) {
+ ast_answer(chan);
+ }
+
+ pu = parking_lot_state_retrieve_parked_user(lot, target_space);
+
+ if (!pu) {
+ ast_stream_and_wait(chan, "pbx-invalidpark", "");
+ return -1;
+ }
+
+ /* Move the parkee into the new bridge */
+ if (ast_bridge_move(lot->parking_bridge, bridge, pu->chan)) {
+ ast_bridge_destroy(bridge);
+ return -1;
+ }
+
+ /* Now we should try to join the new bridge ourselves... */
+ ast_bridge_join(bridge, chan, NULL, /* XXX features go here! */ NULL, NULL, 1);
+
+ return 0;
+}
+
Modified: team/jrose/bridge_projects/res/parking/parking_bridge.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/parking/parking_bridge.c?view=diff&rev=384328&r1=384327&r2=384328
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_bridge.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_bridge.c Fri Mar 29 11:48:37 2013
@@ -28,6 +28,12 @@
#include "res_parking.h"
#include "asterisk/astobj2.h"
+struct ast_bridge_parking
+{
+ struct ast_bridge base;
+ /* private stuff for parking */
+};
+
/*!
* \internal
* \brief ast_bridge parking class destructor
@@ -39,8 +45,10 @@
*
* \return Nothing
*/
-static void bridge_parking_destroy(struct ast_bridge *self)
+static void bridge_parking_destroy(struct ast_bridge_parking *self)
{
+ ast_log(LOG_NOTICE, "destroying bridge\n");
+ ast_bridge_base_v_table.destroy(&self->base);
}
/*!
@@ -57,7 +65,7 @@
*
* \retval TRUE if can push this channel into the bridge.
*/
-static int bridge_parking_can_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
+static int bridge_parking_can_push(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
{
return 1;
}
@@ -77,7 +85,7 @@
* \retval 0 on success
* \retval -1 on failure
*/
-static int bridge_parking_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
+static int bridge_parking_push(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
{
return 0;
}
@@ -95,9 +103,9 @@
*
* \return Nothing
*/
-static void bridge_parking_pull(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel)
+static void bridge_parking_pull(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel)
{
- ast_bridge_base_v_table.pull(self, bridge_channel);
+ ast_bridge_base_v_table.pull(&self->base, bridge_channel);
}
/*!
@@ -113,36 +121,35 @@
*
* \return Nothing
*/
-static void bridge_parking_notify_masquerade(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel)
+static void bridge_parking_notify_masquerade(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel)
{
- ast_bridge_base_v_table.notify_masquerade(self, bridge_channel);
+ ast_bridge_base_v_table.notify_masquerade(&self->base, bridge_channel);
}
struct ast_bridge_methods ast_bridge_parking_v_table = {
.name = "parking",
- .destroy = bridge_parking_destroy,
- .can_push = bridge_parking_can_push,
- .push = bridge_parking_push,
- .pull = bridge_parking_pull,
- .notify_masquerade = bridge_parking_notify_masquerade,
+ .destroy = (ast_bridge_destructor_fn) bridge_parking_destroy,
+ .can_push = (ast_bridge_can_push_channel_fn) bridge_parking_can_push,
+ .push = (ast_bridge_push_channel_fn) bridge_parking_push,
+ .pull = (ast_bridge_pull_channel_fn) bridge_parking_pull,
+ .notify_masquerade = (ast_bridge_notify_masquerade_fn) bridge_parking_notify_masquerade,
};
-static struct ast_bridge *ast_bridge_parking_init(struct ast_bridge *self, struct parking_lot_state *bridge_lot)
+static struct ast_bridge *ast_bridge_parking_init(struct ast_bridge_parking *self, struct parking_lot_state *bridge_lot)
{
- int flags = AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM;
- uint32_t capabilities = AST_BRIDGE_CAPABILITY_HOLDING;
- ast_bridge_base_init(self, capabilities, flags);
+ if (!self) {
+ return NULL;
+ }
- /* XXX Use the parking lot state as the bridge private */
-
- return self;
+ return &self->base;
}
struct ast_bridge *bridge_parking_new(struct parking_lot_state *bridge_lot)
{
void *bridge;
- bridge = ast_bridge_alloc(sizeof(struct ast_bridge), &ast_bridge_parking_v_table);
+ bridge = ast_bridge_alloc(sizeof(struct ast_bridge_parking), &ast_bridge_parking_v_table);
+ bridge = ast_bridge_base_init(bridge, AST_BRIDGE_CAPABILITY_HOLDING, AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM);
bridge = ast_bridge_parking_init(bridge, bridge_lot);
return bridge;
Modified: team/jrose/bridge_projects/res/parking/parking_controller.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/parking/parking_controller.c?view=diff&rev=384328&r1=384327&r2=384328
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_controller.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_controller.c Fri Mar 29 11:48:37 2013
@@ -97,15 +97,7 @@
user->resolution = PARK_TIMEOUT;
ao2_unlock(user);
- ao2_lock(bridge_channel);
- switch (bridge_channel->state) {
- case AST_BRIDGE_CHANNEL_STATE_WAIT:
- ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
- break;
- default:
- break;
- }
- ao2_unlock(bridge_channel);
+ ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
/* Set parking timeout channel variables */
snprintf(parking_space, sizeof(parking_space), "%d", user->parking_space);
@@ -229,9 +221,61 @@
return -1;
}
+static int retrieve_parked_user_first(void *obj, void *arg, int flags)
+{
+ return CMP_MATCH;
+}
+
+static int retrieve_parked_user_targeted(void *obj, void *arg, int flags)
+{
+ int *target = arg;
+ struct parked_user *user = obj;
+ if (user->parking_space == *target) {
+ return CMP_MATCH;
+ }
+
+ return 0;
+}
+
+struct parked_user *parking_lot_state_retrieve_parked_user(struct parking_lot_state *lot, int target)
+{
+ RAII_VAR(struct parked_user *, user, NULL, ao2_cleanup);
+
+ if (target < 0) {
+ user = ao2_callback(lot->parked_user_list, 0, retrieve_parked_user_first, NULL);
+ } else {
+ user = ao2_callback(lot->parked_user_list, 0, retrieve_parked_user_targeted, &target);
+ }
+
+ if (!user) {
+ return NULL;
+ }
+
+ ao2_lock(user);
+ if (user->resolution != PARK_UNSET) {
+ /* Abandon since something else has resolved the parked user before we got to it. */
+ ao2_unlock(user);
+ return NULL;
+ }
+
+ ao2_unlink(lot->parked_user_list, user);
+ user->resolution = PARK_ANSWERED;
+ ao2_unlock(user);
+
+ publish_parked_call(user, PARKED_CALL_UNPARKED);
+
+ parking_lot_state_remove_if_unused(user->lot_state);
+ user->lot_state = NULL;
+
+ /* Bump the ref count by 1 since the RAII_VAR will eat the reference otherwise */
+ ao2_ref(user, +1);
+ return user;
+}
+
static void destroy_parked_user(void *obj)
{
struct parked_user *pu = obj;
+ ast_log(LOG_NOTICE, "Destroy parked user\n");
ao2_cleanup(pu->parker);
}
Modified: team/jrose/bridge_projects/res/parking/res_parking.h
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/parking/res_parking.h?view=diff&rev=384328&r1=384327&r2=384328
==============================================================================
--- team/jrose/bridge_projects/res/parking/res_parking.h (original)
+++ team/jrose/bridge_projects/res/parking/res_parking.h Fri Mar 29 11:48:37 2013
@@ -193,6 +193,22 @@
/*!
* \since 12
+ * \brief Determine if there is a parked user in a parking space and pull it from the parking lot if there is.
+ *
+ * \param lot Parking lot being pulled from
+ * \param target If < 0 search for the first occupied space in the parking lot
+ * If >= 0 Only pull from the indicated target
+ *
+ * \retval NULL if no parked user could be pulled from the requested parking lot at the requested parking space
+ * \retval reference to the requested parked user
+ *
+ * \note The parked user will be removed from parking lot as part of this process
+ * \note Remove this reference with ao2_cleanup once it falls out of scope.
+ */
+struct parked_user *parking_lot_state_retrieve_parked_user(struct parking_lot_state *lot, int target);
+
+/*!
+ * \since 12
* \brief Set necessary bridge roles on a channel that is about to enter a parking lot
*
* \param chan Entering channel
@@ -325,6 +341,18 @@
/*!
* \since 12
+ * \brief Execution function for the parked call application
+ *
+ * \param chan ast_channel entering the application
+ * \param data arguments to the application
+ *
+ * \retval 0 the application executed in such a way that the channel should proceed in the dial plan
+ * \retval -1 the channel should no longer proceed through the dial plan
+ */
+int parked_call_app_exec(struct ast_channel *chan, const char *data);
+
+/*!
+ * \since 12
* \brief Register CLI commands
*
* \retval 0 if successful
Modified: team/jrose/bridge_projects/res/res_parking.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/res_parking.c?view=diff&rev=384328&r1=384327&r2=384328
==============================================================================
--- team/jrose/bridge_projects/res/res_parking.c (original)
+++ team/jrose/bridge_projects/res/res_parking.c Fri Mar 29 11:48:37 2013
@@ -52,7 +52,7 @@
in order to pick up calls parked to these parking spaces.</para></description>
</configOption>
<configOption name="parkinghints" default="no">
- <synopsis>If yes, this parking lot will add hints automatically for parking slots.</synopsis>
+ <synopsis>If yes, this parking lot will add hints automatically for parking spaces.</synopsis>
</configOption>
<configOption name="parkingtime" default="45">
<synopsis>Amount of time a call will remain parked before giving up (in seconds).</synopsis>
@@ -155,10 +155,10 @@
</description>
</configOption>
<configOption name="findslot" default="first">
- <synopsis>Rule to use when trying to figure out which parking slot a call should be parked with.</synopsis>
+ <synopsis>Rule to use when trying to figure out which parking space a call should be parked with.</synopsis>
<description>
<enumlist>
- <enum name="first"><para>Always try to place in the lowest available slot in the parking lot</para></enum>
+ <enum name="first"><para>Always try to place in the lowest available space in the parking lot</para></enum>
<enum name="next"><para>Track the last parking space used and always attempt to use the one immediately after.
</para></enum>
</enumlist>
@@ -188,7 +188,7 @@
#include "asterisk/manager.h"
#define app_park "Park"
-#define app_parkedcall "ParkedCall"
+#define app_parked_call "ParkedCall"
static int parking_lot_state_hash_fn(const void *obj, const int flags)
{
@@ -202,10 +202,9 @@
case OBJ_POINTER:
entry = obj;
return ast_str_hash(entry->name);
- }
-
- /* It should be impossible to reach this point */
- return 0;
+ default:
+ return 0;
+ }
}
static int parking_lot_state_cmp_fn(void *obj, void *arg, const int flags)
@@ -219,17 +218,17 @@
switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
case OBJ_KEY:
key = arg;
- return (!strcmp(entry1->name, key)) ? (CMP_MATCH | CMP_STOP) : 0;
+ return (!strcmp(entry1->name, key)) ? CMP_MATCH : 0;
case OBJ_PARTIAL_KEY:
key = arg;
key_size = strlen(key);
- return (!strncmp(entry1->name, key, key_size)) ? (CMP_MATCH | CMP_STOP) : 0;
+ return (!strncmp(entry1->name, key, key_size)) ? CMP_MATCH : 0;
case OBJ_POINTER:
entry2 = arg;
- return (!strcmp(entry1->name, entry2->name)) ? (CMP_MATCH | CMP_STOP) : 0;
- }
-
- return CMP_STOP;
+ return (!strcmp(entry1->name, entry2->name)) ? CMP_MATCH : 0;
+ default:
+ return CMP_STOP;
+ }
}
/*! All parking lots that are currently alive in some fashion can be obtained from here */
@@ -294,10 +293,9 @@
case OBJ_POINTER:
entry = obj;
return ast_str_hash(entry->name);
- }
-
- /* It should be impossible to reach this point */
- return 0;
+ default:
+ return 0;
+ }
}
static int parking_lot_cfg_cmp_fn(void *obj, void *arg, const int flags)
@@ -311,17 +309,17 @@
switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
case OBJ_KEY:
key = arg;
- return (!strcmp(entry1->name, key)) ? (CMP_MATCH | CMP_STOP) : 0;
+ return (!strcmp(entry1->name, key)) ? CMP_MATCH : 0;
case OBJ_PARTIAL_KEY:
key = arg;
key_size = strlen(key);
- return (!strncmp(entry1->name, key, key_size)) ? (CMP_MATCH | CMP_STOP) : 0;
+ return (!strncmp(entry1->name, key, key_size)) ? CMP_MATCH : 0;
case OBJ_POINTER:
entry2 = arg;
- return (!strcmp(entry1->name, entry2->name)) ? (CMP_MATCH | CMP_STOP) : 0;
- }
-
- return CMP_STOP;
+ return (!strcmp(entry1->name, entry2->name)) ? CMP_MATCH : 0;
+ default:
+ return CMP_STOP;
+ }
}
/*! \brief destructor for parking_config */
@@ -400,7 +398,7 @@
int object_space = user->parking_space;
if (*search_space == object_space) {
- return CMP_MATCH | CMP_STOP;
+ return CMP_MATCH;
}
return 0;
}
@@ -585,6 +583,7 @@
static void parking_lot_state_destructor(void *obj)
{
struct parking_lot_state *lot = obj;
+ ast_log(LOG_NOTICE, "state destructor");
ao2_cleanup(lot->parking_bridge);
ao2_cleanup(lot->parked_user_list);
ast_string_field_free_memory(lot);
@@ -659,18 +658,17 @@
ao2_lock(cfg->parking_lot_list);
- iter = ao2_iterator_init(cfg->parking_lot_list, 0);
- while ((lot_cfg = ao2_iterator_next(&iter))) {
+ for (iter = ao2_iterator_init(cfg->parking_lot_list, 0); (lot_cfg = ao2_iterator_next(&iter)); ao2_ref(lot_cfg, -1)) {
if (lot_cfg->state) {
- ao2_ref(lot_cfg, -1);
continue;
}
+
lot_cfg->state = parking_lot_state_build_or_update(lot_cfg);
if (lot_cfg->state) {
lot_cfg->state->has_owner = 1;
}
- ao2_ref(lot_cfg, -1);
- }
+ }
+
ao2_iterator_destroy(&iter);
ao2_unlock(cfg->parking_lot_list);
@@ -717,6 +715,10 @@
goto error;
}
+ if (ast_register_application_xml(app_parked_call, parked_call_app_exec)) {
+ goto error;
+ }
+
if (load_parking_ui()) {
goto error;
}
More information about the asterisk-commits
mailing list