[asterisk-commits] jrose: branch jrose/bridge_projects r384814 - in /team/jrose/bridge_projects:...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Apr 5 11:19:14 CDT 2013
Author: jrose
Date: Fri Apr 5 11:19:10 2013
New Revision: 384814
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=384814
Log:
April 5 update
Added:
team/jrose/bridge_projects/res/parking/parking_bridge_features.c (with props)
Modified:
team/jrose/bridge_projects/bridges/bridge_builtin_features.c
team/jrose/bridge_projects/include/asterisk/parking.h
team/jrose/bridge_projects/main/bridging.c
team/jrose/bridge_projects/main/bridging_roles.c
team/jrose/bridge_projects/main/parking.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/bridges/bridge_builtin_features.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/bridges/bridge_builtin_features.c?view=diff&rev=384814&r1=384813&r2=384814
==============================================================================
--- team/jrose/bridge_projects/bridges/bridge_builtin_features.c (original)
+++ team/jrose/bridge_projects/bridges/bridge_builtin_features.c Fri Apr 5 11:19:10 2013
@@ -48,6 +48,7 @@
#include "asterisk/app.h"
#include "asterisk/astobj2.h"
#include "asterisk/pbx.h"
+#include "asterisk/parking.h"
/*!
* \brief Helper function that presents dialtone and grabs extension
@@ -163,6 +164,28 @@
return "default";
}
+/* XXX move this to parking.h */
+static struct ast_exten *get_parking_exten(const char *exten_str, struct ast_channel *chan, const char *context)
+{
+ struct ast_exten *exten;
+ struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
+ const char *app_at_exten;
+
+ ast_debug(4, "Checking if %s@%s is a parking exten\n", exten_str, context);
+ exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL,
+ E_MATCH);
+ if (!exten) {
+ return NULL;
+ }
+
+ app_at_exten = ast_get_extension_app(exten);
+ if (!app_at_exten || strcasecmp(PARK_APPLICATION, app_at_exten)) {
+ return NULL;
+ }
+
+ return exten;
+}
+
/*! \brief Internal built in feature for blind transfers */
static int feature_blind_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
{
@@ -170,6 +193,7 @@
struct ast_channel *chan = NULL;
struct ast_bridge_features_blind_transfer *blind_transfer = hook_pvt;
const char *context;
+ struct ast_exten *park_exten;
/* BUGBUG the peer needs to be put on hold for the transfer. */
ast_channel_lock(bridge_channel->chan);
@@ -179,6 +203,16 @@
/* Grab the extension to transfer to */
if (grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) {
+ return 0;
+ }
+
+ /* Parking blind transfer override - phase this out for something more general purpose in the future. */
+ park_exten = get_parking_exten(exten, bridge_channel->chan, context);
+ if (park_exten) {
+ /* We are transfering the transferee to a parking lot. */
+ if (ast_park_blind_xfer(bridge, bridge_channel, ast_get_extension_app_data(park_exten))) {
+ ast_log(LOG_ERROR, "%s attempted to transfer to park application and failed.\n", ast_channel_name(bridge_channel->chan));
+ };
return 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=384814&r1=384813&r2=384814
==============================================================================
--- team/jrose/bridge_projects/include/asterisk/parking.h (original)
+++ team/jrose/bridge_projects/include/asterisk/parking.h Fri Apr 5 11:19:10 2013
@@ -24,6 +24,8 @@
*/
#include "asterisk/stringfields.h"
+
+#define PARK_APPLICATION "Park"
/*!
* \brief Defines the type of parked call message being published
@@ -98,3 +100,32 @@
* \retval a pointer to the parked call message type
*/
struct stasis_message_type *ast_parked_call_type(void);
+
+/*!
+ * \brief install a callback for handling blind transfers to a parking extension
+ * \since 12
+ *
+ * \param parking_func Function to use for transfers to 'Park' applications
+ */
+void ast_install_park_blind_xfer_func(int (*park_blind_xfer_func)(struct ast_bridge *bridge, struct ast_bridge_channel *parker,
+ const char *app_data));
+
+/*!
+ * \brief uninstall a callback for handling blind transfers to a parking extension
+ * \since 12
+ */
+void ast_uninstall_park_blind_xfer_func(void);
+
+/*!
+ * \brief use the installed park blind xfer func
+ * \since 12
+ *
+ * \param bridge Bridge being transferred from
+ * \param bridge_channel Bridge channel initiating the transfer
+ * \param app_data arguments to the park application
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+int ast_park_blind_xfer(struct ast_bridge *bridge, struct ast_bridge_channel *parker,
+ const char *app_data);
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=384814&r1=384813&r2=384814
==============================================================================
--- team/jrose/bridge_projects/main/bridging.c (original)
+++ team/jrose/bridge_projects/main/bridging.c Fri Apr 5 11:19:10 2013
@@ -2628,6 +2628,10 @@
ast_bridge_channel_pull(bridge_channel);
+ /* While we are pulled we need to re-establish the channel roles */
+ ast_bridge_channel_clear_roles(bridge_channel);
+ ast_bridge_channel_establish_roles(bridge_channel);
+
/* Point to new bridge. */
ao2_ref(bridge_dst, +1);
ast_bridge_channel_lock(bridge_channel);
Modified: team/jrose/bridge_projects/main/bridging_roles.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/main/bridging_roles.c?view=diff&rev=384814&r1=384813&r2=384814
==============================================================================
--- team/jrose/bridge_projects/main/bridging_roles.c (original)
+++ team/jrose/bridge_projects/main/bridging_roles.c Fri Apr 5 11:19:10 2013
@@ -41,11 +41,14 @@
#include "asterisk/linkedlists.h"
#include "asterisk/bridging.h"
#include "asterisk/bridging_roles.h"
+#include "asterisk/stringfields.h"
struct bridge_role_option {
AST_LIST_ENTRY(bridge_role_option) list;
- char option[AST_ROLE_LEN];
- char value[1];
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(option);
+ AST_STRING_FIELD(value);
+ );
};
struct bridge_role {
@@ -71,6 +74,7 @@
{
struct bridge_role_option *role_option;
while ((role_option = AST_LIST_REMOVE_HEAD(&role->options, list))) {
+ ast_string_field_free_memory(role_option);
ast_free(role_option);
}
ast_free(role);
@@ -290,13 +294,18 @@
value = "";
}
- role_option = ast_calloc(1, sizeof(*role_option) + strlen(value));
+ role_option = ast_calloc(1, sizeof(*role_option));
if (!role_option) {
return -1;
}
- ast_copy_string(role_option->option, option, sizeof(role_option->option));
- strcpy(role_option->value, value);
+ if (ast_string_field_init(role_option, 32)) {
+ ast_free(role_option);
+ return -1;
+ }
+
+ ast_string_field_set(role_option, option, option);
+ ast_string_field_set(role_option, value, value);
AST_LIST_INSERT_TAIL(&role->options, role_option, list);
@@ -358,8 +367,8 @@
role_option = get_role_option(role, option);
if (role_option) {
- /* We need to clear the option out and recreate it. There is no way to do this yet. Implement it later. XXX */
- return -1;
+ ast_string_field_set(role_option, value, value);
+ return 0;
}
setup_bridge_role_option(role, option, value);
Modified: team/jrose/bridge_projects/main/parking.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/main/parking.c?view=diff&rev=384814&r1=384813&r2=384814
==============================================================================
--- team/jrose/bridge_projects/main/parking.c (original)
+++ team/jrose/bridge_projects/main/parking.c Fri Apr 5 11:19:10 2013
@@ -28,6 +28,9 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/_private.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/pbx.h"
+#include "asterisk/bridging.h"
#include "asterisk/parking.h"
#include "asterisk/channel.h"
@@ -36,6 +39,10 @@
/*! \brief Topic for parking lots */
static struct stasis_topic *parking_topic;
+
+/*! \brief Funcion Callback for handling blind transfers to park applications */
+static int (*ast_park_blind_xfer_func)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel,
+ const char *app_data) = NULL;
void ast_parking_stasis_init(void)
{
@@ -71,7 +78,10 @@
ast_string_field_free_memory(park_obj);
}
-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, unsigned int parkingspace, unsigned long int timeout, unsigned long int duration)
+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, unsigned int parkingspace, unsigned long int timeout,
+ unsigned long int duration)
{
RAII_VAR(struct ast_parked_call_payload *, payload, NULL, ao2_cleanup);
@@ -101,3 +111,30 @@
ao2_ref(payload, +1);
return payload;
}
+
+void ast_install_park_blind_xfer_func(int (*park_blind_xfer_func)(struct ast_bridge *bridge, struct ast_bridge_channel *parker,
+ const char *app_data))
+{
+ ast_park_blind_xfer_func = park_blind_xfer_func;
+}
+
+void ast_uninstall_park_blind_xfer_func(void)
+{
+ ast_park_blind_xfer_func = NULL;
+}
+
+int ast_park_blind_xfer(struct ast_bridge *bridge, struct ast_bridge_channel *parker,
+ const char *app_data)
+{
+ static int warned = 0;
+ if (ast_park_blind_xfer_func) {
+ return ast_park_blind_xfer_func(bridge, parker, app_data);
+ }
+
+ if (warned++ % 10 == 0) {
+ ast_verb(3, "%s attempted to blind transfer to a parking extension, but no parking blind transfer function is loaded.\n",
+ ast_channel_name(parker->chan));
+ }
+
+ return -1;
+}
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=384814&r1=384813&r2=384814
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_applications.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_applications.c Fri Apr 5 11:19:10 2013
@@ -170,19 +170,10 @@
return 0;
}
-int park_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);
- RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
-
- struct ast_bridge_features chan_features;
+static int park_app_parse_data(const char *data, int *disable_announce, int *use_ringing, int *randomize, int *time_limit, char **comeback_override, char **lot_name)
+{
+ char *parse;
struct ast_flags flags = { 0 };
- char *parse;
- int time_limit = -1;
- char *comeback_override = NULL;
-
- int res;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(lot_name);
@@ -197,111 +188,136 @@
char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
ast_app_parse_options(park_opts, &flags, opts, args.options);
if (ast_test_flag(&flags, MUXFLAG_TIMEOUT_OVERRIDE)) {
- if (apply_option_timeout(&time_limit, opts[OPT_ARG_TIMEOUT])) {
+ if (apply_option_timeout(time_limit, opts[OPT_ARG_TIMEOUT])) {
return -1;
}
}
+
if (ast_test_flag(&flags, MUXFLAG_COMEBACK_OVERRIDE)) {
- comeback_override = ast_strdupa(opts[OPT_ARG_COMEBACK]);
- }
- }
-
- if (ast_strlen_zero(args.lot_name)) {
- lot = channel_find_parking_lot_state(chan);
+ *comeback_override = ast_strdup(opts[OPT_ARG_COMEBACK]);
+ }
+
+ if (ast_test_flag(&flags, MUXFLAG_NOANNOUNCE)) {
+ *disable_announce = 1;
+ }
+
+ if (ast_test_flag(&flags, MUXFLAG_RINGING)) {
+ *use_ringing = 1;
+ }
+
+ if (ast_test_flag(&flags, MUXFLAG_RANDOMIZE)) {
+ *randomize = 1;
+ }
+ }
+
+ if (!ast_strlen_zero(args.lot_name)) {
+ *lot_name = ast_strdup(args.lot_name);
+ }
+
+ return 0;
+}
+
+int park_common_setup(struct parking_lot_state **lot, struct ast_bridge **parking_bridge, struct parked_user **pu,
+ struct ast_channel *parker, struct ast_channel *parkee, const char *app_data)
+{
+ int silence_announcements = 0;
+ int use_ringing = 0;
+ int randomize = 0;
+ int time_limit = -1;
+ RAII_VAR(char *, comeback_override, NULL, ast_free);
+ RAII_VAR(char *, lot_name, NULL, ast_free);
+
+ /* parse the app data if we have it */
+ if (app_data) {
+ park_app_parse_data(app_data, &silence_announcements, &use_ringing, &randomize, &time_limit, &comeback_override, &lot_name);
+ }
+
+ /* Now find out which parking lot we want to park it into. */
+ if (ast_strlen_zero(lot_name)) {
+ *lot = channel_find_parking_lot_state(parker);
} else {
- lot = parking_lot_state_find_by_name(args.lot_name);
- }
-
- if (!lot) {
+ *lot = parking_lot_state_find_by_name(lot_name);
+ }
+
+ if (!*lot) {
ast_log(LOG_ERROR, "Could not find the requested parking lot\n");
- return -1;
- }
-
- ao2_lock(lot);
- parking_bridge = parking_lot_state_get_bridge(lot);
- ao2_unlock(lot);
-
- if (!parking_bridge) {
+ ast_stream_and_wait(parker, "pbx-parkingfailed", "");
+ return -1;
+ }
+
+ ao2_lock(*lot);
+ *parking_bridge = parking_lot_state_get_bridge(*lot);
+ ao2_unlock(*lot);
+
+ if (!*parking_bridge) {
ast_log(LOG_ERROR, "Could not acquire holding bridge to park into\n");
- return -1;
- }
+ ast_stream_and_wait(parker, "pbx-parkingfailed", "");
+ return -1;
+ }
+
+ *pu = generate_parked_user(*lot, parkee, parker, randomize, time_limit);
+
+ if (!*pu) {
+ ast_log(LOG_ERROR, "Failed to create parked user for channel %s, can not park.\n", ast_channel_name(parkee));
+ ast_stream_and_wait(parker, "pbx-parkingfailed", "");
+ return -1;
+ }
+
+ /* Announce parking space to the parking channel */
+ if (!silence_announcements) {
+ ast_say_digits(parker, (*pu)->parking_space, "", ast_channel_language(parker));
+ }
+
+ /* Apply relevant bridge roles and such to the parking channel */
+ parking_channel_set_roles(parkee, *lot, use_ringing);
+
+ /* If we need to go somewhere special after timeout, set special comeback arguments */
+ if (!ast_strlen_zero(comeback_override)) {
+ ast_copy_string((*pu)->comeback, comeback_override, sizeof((*pu)->comeback));
+ }
+
+ return 0;
+}
+
+int park_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);
+ RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
+
+ struct ast_bridge_features chan_features;
+ int res;
/* answer the channel if needed */
if (ast_channel_state(chan) != AST_STATE_UP) {
ast_answer(chan);
}
- pu = generate_parked_user(lot, chan, chan, ast_test_flag(&flags, MUXFLAG_RANDOMIZE), time_limit);
-
- if (!pu) {
- ast_log(LOG_ERROR, "Failed to create parked user for channel %s, can not park.\n", ast_channel_name(chan));
- return -1;
- }
-
- /* If we aren't in silence mode, go ahead and announce the parking space */
- if (!ast_test_flag(&flags, MUXFLAG_NOANNOUNCE)) {
- ast_say_digits(chan, pu->parking_space, "", ast_channel_language(chan));
- }
-
+ /* Handle all the common aprking setup stuff */
+ if (park_common_setup(&lot, &parking_bridge, &pu, chan, chan, data)) {
+ return -1;
+ }
+
+ /* Now for the fun part... park it! */
ast_bridge_features_init(&chan_features);
-
- /* Set limits and apply channel roles */
- parking_set_duration(&chan_features, pu, time_limit);
- parking_channel_set_roles(chan, lot, ast_test_flag(&flags, MUXFLAG_RINGING));
-
- /* Alright, now wait in the holding bridge until we get removed from it for some reason. */
- 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.
+ * hung up. This should 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);
- 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 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);
-
- /* Figure out if we need to go somewhere special now that the timeout has occured */
- if (ast_test_flag(&flags, MUXFLAG_COMEBACK_OVERRIDE)) {
- if (ast_parseable_goto(chan, comeback_override)) {
- return -1;
- }
- } else {
- if (comeback_goto(pu, lot)) {
- return -1;
- }
- }
-
- /* Since this is executed from pbx, it'll automatically bump the priority when we return. We can address that by reducing it by 1 before returning. Smooth. */
- ast_channel_priority_set(chan, ast_channel_priority(chan) - 1);
-
- return ast_check_hangup_locked(chan) ? -1 : 0;
+ return res;
}
int parked_call_app_exec(struct ast_channel *chan, const char *data)
@@ -333,11 +349,13 @@
if (!lot) {
ast_log(LOG_ERROR, "Could not find the requested parking lot\n");
+ ast_stream_and_wait(chan, "pbx-invalidpark", "");
return -1;
}
if (!ast_strlen_zero(args.parking_space)) {
if (sscanf(args.parking_space, "%d", &target_space) != 1 || target_space < 0) {
+ ast_stream_and_wait(chan, "pbx-invalidpark", "");
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;
}
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=384814&r1=384813&r2=384814
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_bridge.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_bridge.c Fri Apr 5 11:19:10 2013
@@ -31,7 +31,9 @@
struct ast_bridge_parking
{
struct ast_bridge base;
+
/* private stuff for parking */
+ struct parking_lot_state *lot;
};
/*!
@@ -41,13 +43,12 @@
*
* \param self Bridge to operate upon.
*
- * \note XXX Stub
+ * \note XXX Stub... and it might go unused.
*
* \return Nothing
*/
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);
}
@@ -61,7 +62,7 @@
* \param swap Bridge channel to swap places with if not NULL.
*
* \note On entry, self is already locked.
- * \note XXX Stub
+ * \note XXX Stub... and it might go unused.
*
* \retval TRUE if can push this channel into the bridge.
*/
@@ -80,13 +81,61 @@
* \param swap Bridge channel to swap places with if not NULL
*
* \note On entry, self is already locked
- * \note XXX Stub
*
* \retval 0 on success
* \retval -1 on failure
*/
static int bridge_parking_push(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
{
+ struct parked_user *pu;
+ struct ao2_iterator iter;
+
+ /* Swaps for parking bridges should only occur as a result of local channel optimization */
+ if (swap) {
+ pu = swap->bridge_pvt;
+ if (!pu) {
+ /* This should be impossible since the only way a channel can enter in the first place is if it has a parked user associated with it */
+ return -1;
+ }
+
+ /* Give the swap channel's parked user to the incoming channel */
+ pu->chan = bridge_channel->chan;
+ bridge_channel->bridge_pvt = pu;
+ swap->bridge_pvt = NULL;
+
+ /* XXX Add a parked call swap message type to relay information about parked channel swaps */
+
+ ao2_ref(pu, -1);
+ return 0;
+ }
+
+ /* We should already have a parked user set for the channel when we push */
+ for (iter = ao2_iterator_init(self->lot->parked_user_list, 0); (pu = ao2_iterator_next(&iter)); ao2_ref(pu, -1)) {
+ if (bridge_channel->chan != pu->chan) {
+ continue;
+ }
+ break;
+ }
+ ao2_iterator_destroy(&iter);
+
+ if (!pu) {
+ /* This should be impossible since the parked user for the channel should be generated before it enters if it's not swapping. */
+ return -1;
+ }
+
+ /* Apply parking duration limits */
+ if (bridge_channel->features) {
+ reset_parked_time(pu);
+ parking_set_duration(bridge_channel->features, pu);
+ }
+
+ /* Set this to the bridge pvt so that we don't have to refind the parked user associated with this bridge channel again. */
+ bridge_channel->bridge_pvt = pu;
+
+ /* Generate ParkedCall Stasis Message */
+ publish_parked_call(pu, PARKED_CALL);
+
+ ao2_ref(pu, -1);
return 0;
}
@@ -99,13 +148,54 @@
* \param bridge_channel Bridge channel to pull.
*
* \note On entry, self is already locked.
- * \note XXX Stub
*
* \return Nothing
*/
static void bridge_parking_pull(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel)
{
+ struct parked_user *pu = bridge_channel->bridge_pvt;
ast_bridge_base_v_table.pull(&self->base, bridge_channel);
+
+ /* This should only happen if the exiting channel was swapped out */
+ if (!pu) {
+ return;
+ }
+
+ /* If we got here without the resolution being set, that's because the call was hung up for some reason without
+ * timing out or being picked up. There may be some forcible park removals later, but the resolution should be
+ * handled in those cases */
+ ao2_lock(pu);
+ if (pu->resolution == PARK_UNSET) {
+ pu->resolution = PARK_ABANDON;
+ }
+ ao2_unlock(pu);
+
+ switch (pu->resolution) {
+ case PARK_UNSET:
+ /* This should be impossible now since the resolution is forcibly set to abandon if it was unset at this point. Resolution
+ isn't allowed to be changed when it isn't currently PARK_UNSET. */
+ return;
+ case PARK_ABANDON:
+ /* Since the call was abandoned without additional handling, we need to issue the give up event and unpark the user. */
+ publish_parked_call(pu, PARKED_CALL_GIVEUP);
+ unpark_parked_user(pu);
+ return;
+ case PARK_FORCED:
+ /* PARK_FORCED is currently unused, but it is expected that it would be handled similar to PARK_ANSWERED.
+ * There is currently no event related to forced parked calls either */
+ return;
+ case PARK_ANSWERED:
+ /* If answered or forced, the channel should be pulled from the bridge as part of that process and unlinked from
+ * the parking lot afterwards. */
+ publish_parked_call(pu, PARKED_CALL_UNPARKED);
+ return;
+ case PARK_TIMEOUT:
+ /* Timeout is similar to abandon because it simply sets the bridge state to end and doesn't
+ * actually pull the channel. Because of that, unpark should happen in here. */
+ publish_parked_call(pu, PARKED_CALL_TIMEOUT);
+ unpark_parked_user(pu);
+ return;
+ }
}
/*!
@@ -117,7 +207,7 @@
* \param bridge_channel Bridge channel that was masqueraded.
*
* \note On entry, self is already locked.
- * \note XXX Stub
+ * \note XXX Stub... and it will probably go unused.
*
* \return Nothing
*/
@@ -141,6 +231,15 @@
return NULL;
}
+ /* If no lot is defined for the bridge, then we aren't allowing the bridge to be initialized. */
+ if (!bridge_lot) {
+ ao2_ref(self, -1);
+ return NULL;
+ }
+
+ /* It doesn't need to be a reference since the bridge only lives as long as the parking lot state lives. */
+ self->lot = bridge_lot;
+
return &self->base;
}
@@ -149,7 +248,12 @@
void *bridge;
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);
+ if (!bridge) {
+ return NULL;
+ }
+
bridge = ast_bridge_parking_init(bridge, bridge_lot);
return bridge;
Added: team/jrose/bridge_projects/res/parking/parking_bridge_features.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/parking/parking_bridge_features.c?view=auto&rev=384814
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_bridge_features.c (added)
+++ team/jrose/bridge_projects/res/parking/parking_bridge_features.c Fri Apr 5 11:19:10 2013
@@ -1,0 +1,146 @@
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "res_parking.h"
+#include "asterisk/utils.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/logger.h"
+#include "asterisk/bridging.h"
+#include "asterisk/bridging_features.h"
+#include "asterisk/features.h"
+#include "asterisk/say.h"
+
+static int park_feature_helper(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, const char *app_data)
+{
+ struct ast_bridge_channel *other;
+
+ RAII_VAR(struct parking_lot_state *, lot, NULL, ao2_cleanup);
+ RAII_VAR(struct parked_user *, pu, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
+
+ /* If this is the only channel in this bridge then this feature shouldn't be at all usable. */
+ if (AST_LIST_FIRST(&bridge->channels) == AST_LIST_LAST(&bridge->channels)) {
+ return 0;
+ }
+
+ /* Find the channel we want to park */
+ other = AST_LIST_FIRST(&bridge->channels);
+ if (other == bridge_channel) {
+ other = AST_LIST_LAST(&bridge->channels);
+ }
+
+ /* Handle all the common parking setup stuff */
+ if (park_common_setup(&lot, &parking_bridge, &pu, bridge_channel->chan, other->chan, app_data)) {
+ return 0;
+ }
+
+ /* Now for the fun part... park it! */
+ if (ast_bridge_move(bridge, parking_bridge, other->chan)) {
+ ast_log(LOG_ERROR, "Failed to move %s into the parking bridge for %s\n",
+ ast_channel_name(other->chan), lot->name);
+ return 0;
+ }
+
+ /* The parker parked the call successfully, so it leaves the bridge now. */
+ ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+
+ return 0;
+}
+
+static int feature_park(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+{
+ return park_feature_helper(bridge, bridge_channel, NULL);
+}
+
+static void parking_duration_cb_destroyer(void *hook_pvt)
+{
+ struct parked_user *user = hook_pvt;
+ ao2_ref(user, -1);
+}
+
+/*! \internal
+ * \brief Interval hook. Pulls a parked call from the parking bridge after the timeout is passed and sets the resolution to timeout.
+ *
+ * \param bridge Which bridge the channel was parked in
+ * \param bridge_channel bridge channel this interval hook is being executed on
+ * \param hook_pvt A pointer to the parked_user struct associated with the channel is stuffed in here
+ */
+static int parking_duration_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+{
+ struct parked_user *user = hook_pvt;
+ struct ast_channel *chan = user->chan;
+ char *peername;
+ char *dash;
+ char parking_space[AST_MAX_EXTENSION];
+
+ /* We are still in the bridge, so it's possible for other stuff to mess with the parked call before we leave the bridge
+ to deal with this, lock the parked user, check and set resolution. */
+ ao2_lock(user);
+ if (user->resolution != PARK_UNSET) {
+ /* Abandon timeout since something else has resolved the parked user before we got to it. */
+ ao2_unlock(user);
+ return -1;
+ }
+
+ user->resolution = PARK_TIMEOUT;
+ ao2_unlock(user);
+
+ 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);
+ pbx_builtin_setvar_helper(chan, "PARKING_SPACE", parking_space);
+ pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parking_space); /* Deprecated version of PARKING_SPACE */
+ pbx_builtin_setvar_helper(chan, "PARKEDLOT", user->lot_state->name);
+
+ peername = ast_strdupa(user->parker->name);
+ dash = strrchr(peername, '-');
+ if (dash) {
+ *dash = '\0';
+ }
+
+ pbx_builtin_setvar_helper(chan, "PARKER", peername);
+
+ /* async_goto the proper PBX destination - this should happen when we come out of the bridge */
+ if (!ast_strlen_zero(user->comeback)) {
+ ast_async_parseable_goto(chan, user->comeback);
+ } else {
+ comeback_goto(user, user->lot_state);
+ }
+
+ return -1;
+}
+
+void parking_set_duration(struct ast_bridge_features *features, struct parked_user *user)
+{
+ unsigned int time_limit;
+
+ time_limit = user->time_limit * 1000;
+
+ if (!time_limit) {
+ /* There is no duration limit that we need to apply. */
+ return;
+ }
+
+ /* The interval hook is going to need a reference to the parked_user */
+ ao2_ref(user, +1);
+
+ if (ast_bridge_interval_hook(features, time_limit,
+ parking_duration_callback, user, parking_duration_cb_destroyer, 1)) {
+ ast_log(LOG_ERROR, "Failed to apply duration limits to the parking call.\n");
+ }
+}
+
+void unload_parking_bridge_features(void)
+{
+ ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_PARKCALL);
+ ast_uninstall_park_blind_xfer_func();
+}
+
+int load_parking_bridge_features(void)
+{
+ ast_bridge_features_register(AST_BRIDGE_BUILTIN_PARKCALL, feature_park, NULL);
+ ast_install_park_blind_xfer_func(park_feature_helper);
+ return 0;
+}
Propchange: team/jrose/bridge_projects/res/parking/parking_bridge_features.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/jrose/bridge_projects/res/parking/parking_bridge_features.c
------------------------------------------------------------------------------
svn:keywords = "Author Date Id Rev URL"
Propchange: team/jrose/bridge_projects/res/parking/parking_bridge_features.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
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=384814&r1=384813&r2=384814
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_controller.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_controller.c Fri Apr 5 11:19:10 2013
@@ -70,61 +70,6 @@
struct parked_user *user;
};
-/*! \internal
- * \brief Interval hook. Pulls a parked call from the parking bridge after the timeout is passed and sets the resolution to timeout.
- *
- * \param bridge Which bridge the channel was parked in
- * \param bridge_channel bridge channel this interval hook is being executed on
- * \param hook_pvt A pointer to the parked_user struct associated with the channel is stuffed in here
- */
-static int parking_duration_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
- struct parked_user *user = hook_pvt;
- struct ast_channel *chan = user->chan;
- char *peername;
- char *dash;
- char parking_space[AST_MAX_EXTENSION];
-
- /* We are still in the bridge, so it's possible for other stuff to mess with the parked call before we leave the bridge
- to deal with this, lock the parked user, check and set resolution. */
- ao2_lock(user);
- if (user->resolution != PARK_UNSET) {
- /* Abandon timeout since something else has resolved the parked user before we got to it. */
- ao2_unlock(user);
- return -1;
- }
-
- user->resolution = PARK_TIMEOUT;
- ao2_unlock(user);
-
- 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);
- pbx_builtin_setvar_helper(chan, "PARKING_SPACE", parking_space);
- pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parking_space); /* Deprecated version of PARKING_SPACE */
- pbx_builtin_setvar_helper(chan, "PARKEDLOT", user->lot_state->name);
-
- peername = ast_strdupa(user->parker->name);
- dash = strrchr(peername, '-');
- if (dash) {
- *dash = '\0';
- }
-
- pbx_builtin_setvar_helper(chan, "PARKER", peername);
-
- /* Set the resolution for the user to timeout */
- publish_parked_call(user, PARKED_CALL_TIMEOUT);
-
- return -1;
-}
-
-static void parking_duration_cb_destroyer(void *hook_pvt)
-{
- struct parked_user *user = hook_pvt;
- ao2_ref(user, -1);
-}
-
int unpark_parked_user(struct parked_user *pu)
{
if (pu->lot_state) {
@@ -135,30 +80,6 @@
}
return -1;
-}
-
-void parking_set_duration(struct ast_bridge_features *features, struct parked_user *user, int override_time)
-{
- unsigned int time_limit;
-
- if (override_time >= 0) {
- time_limit = override_time * 1000;
- } else {
- time_limit = user->lot_state ? user->lot_state->parkingtime * 1000 : 0;
- }
-
- if (!time_limit) {
- /* There is no duration limit that we need to apply. */
- return;
- }
-
- /* The interval hook is going to need a reference to the parked_user */
- ao2_ref(user, +1);
-
- if (ast_bridge_interval_hook(features, time_limit,
- parking_duration_callback, user, parking_duration_cb_destroyer, 1)) {
- ast_log(LOG_ERROR, "Failed to apply duration limits to the parking call.\n");
- }
}
int parking_lot_state_get_space(struct parking_lot_state *lot, int target_override)
@@ -253,7 +174,7 @@
ao2_lock(user);
if (user->resolution != PARK_UNSET) {
- /* Abandon since something else has resolved the parked user before we got to it. */
+ /* Abandon. Something else has resolved the parked user before we got to it. */
ao2_unlock(user);
return NULL;
}
@@ -262,8 +183,6 @@
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;
@@ -275,7 +194,6 @@
static void destroy_parked_user(void *obj)
{
struct parked_user *pu = obj;
- ast_log(LOG_NOTICE, "Destroy parked user\n");
ao2_cleanup(pu->parker);
}
@@ -295,17 +213,6 @@
}
}
-/*! \internal
- * \brief store context, extension and priority
- * \param chan, context, extension, priority
- */
-static void set_c_e_p(struct ast_channel *chan, const char *context, const char *extension, int priority)
-{
- ast_channel_context_set(chan, context);
- ast_channel_exten_set(chan, extension);
- ast_channel_priority_set(chan, priority);
-}
-
int comeback_goto(struct parked_user *pu, struct parking_lot_state *lot_state)
{
struct ast_channel *chan = pu->chan;
@@ -316,7 +223,7 @@
if (lot_state->comebacktoorigin) {
if (ast_exists_extension(chan, PARK_DIAL_CONTEXT, peername, 1, NULL)) {
- set_c_e_p(chan, PARK_DIAL_CONTEXT, peername, 1);
+ ast_async_goto(chan, PARK_DIAL_CONTEXT, peername, 1);
} else {
ast_log(LOG_ERROR, "Can not start %s at %s,%s,1 because extension does not exist. Terminating call.\n",
ast_channel_name(chan), PARK_DIAL_CONTEXT, peername);
@@ -325,21 +232,21 @@
}
if (ast_exists_extension(chan, lot_state->comebackcontext, peername, 1, NULL)) {
- set_c_e_p(chan, lot_state->comebackcontext, peername, 1);
+ ast_async_goto(chan, lot_state->comebackcontext, peername, 1);
return 0;
}
if (ast_exists_extension(chan, lot_state->comebackcontext, "s", 1, NULL)) {
ast_verb(2, "Could not start %s at %s,%s,1. Using 's@%s' instead.\n", ast_channel_name(chan),
lot_state->comebackcontext, peername, lot_state->comebackcontext);
- set_c_e_p(chan, lot_state->comebackcontext, "s", 1);
+ ast_async_goto(chan, lot_state->comebackcontext, "s", 1);
return 0;
}
ast_verb(2, "Can not start %s at %s,%s,1 and exten 's@%s' does not exist. Using 's at default'\n",
ast_channel_name(chan),
lot_state->comebackcontext, peername, lot_state->comebackcontext);
- set_c_e_p(chan, "default", "s", 1);
+ ast_async_goto(chan, "default", "s", 1);
return 0;
}
@@ -398,14 +305,10 @@
new_parked_user->time_limit = (time_limit >= 0) ? time_limit : lot_state->parkingtime;
new_parked_user->parker = ast_channel_snapshot_create(parker);
if (!new_parked_user->parker) {
- ast_log(LOG_ERROR, "Allocation error\n");
ao2_ref(new_parked_user, -1);
ao2_unlock(lot_state);
return NULL;
}
-
- /* Generate ParkedCall Stasis Message */
- publish_parked_call(new_parked_user, PARKED_CALL);
/* Insert into the parking lot's parked user list. We can unlock the lot now. */
ao2_link(lot_state->parked_user_list, new_parked_user);
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=384814&r1=384813&r2=384814
==============================================================================
--- team/jrose/bridge_projects/res/parking/res_parking.h (original)
+++ team/jrose/bridge_projects/res/parking/res_parking.h Fri Apr 5 11:19:10 2013
@@ -118,8 +118,7 @@
struct ast_channel_snapshot *parker; /*!< Snapshot of the channel that parked the call at the time of parking */
struct timeval start; /*!< When the call was parked */
int parking_space; /*!< Which parking space is used */
- char context[AST_MAX_CONTEXT]; /*!< Where to go on parking timeout (context) */
- char exten[AST_MAX_CONTEXT]; /*!< Where to go on parking timeout (extension) */
+ char comeback[AST_MAX_CONTEXT]; /*!< Where to go on parking timeout */
unsigned int time_limit; /*!< How long this specific channel may remain in the parking lot before timing out */
struct parking_lot_state *lot_state; /*!< Which parking lot the user is parked to */
enum park_call_resolution resolution; /*!< How did the parking session end? If the call is in a bridge, lock parked_user before checking/setting */
@@ -223,9 +222,8 @@
*
* \param features The ast_bridge_features we are establishing the interval hook on
* \param user The parked_user receiving the timeout duration limits
- * \param override_time If >= 0, use this instead of the user's timeout inherited from its lot
- */
-void parking_set_duration(struct ast_bridge_features *features, struct parked_user *user, int override_time);
+ */
+void parking_set_duration(struct ast_bridge_features *features, struct parked_user *user);
/*!
* \since 12
@@ -308,7 +306,7 @@
/*!
* \since 12
- * \brief Pull a parked user out of its parking lot.
+ * \brief Pull a parked user out of its parking lot. Use this when you don't want to use the parked user afterwards.
* \param user The parked user being pulled.
*
* \retval 0 on success
@@ -327,6 +325,30 @@
/*!
* \since 12
+ * \brief This sets up a parked user for the channel being parked as well as prepares the parking bridge if necessary.
+ * it also handles the setup of all parking options available to the parking application.
+ *
+ * \param lot pointer to a parking lot state struct pointer. This will be set to the necessary parking lot
+ * based on either app_data or channel variables.
+ * \param parking_bridge pointer to an ast_bridge struct pointer. Set to the parking lot's parking bridge.
[... 105 lines stripped ...]
More information about the asterisk-commits
mailing list