[asterisk-commits] file: branch file/dialing_api r49258 - in
/team/file/dialing_api: apps/ inclu...
asterisk-commits at lists.digium.com
asterisk-commits at lists.digium.com
Tue Jan 2 17:14:27 MST 2007
Author: file
Date: Tue Jan 2 18:14:27 2007
New Revision: 49258
URL: http://svn.digium.com/view/asterisk?view=rev&rev=49258
Log:
Add some guts to the API. Dial2 is now able to dial a single channel at least.
Modified:
team/file/dialing_api/apps/app_dial2.c
team/file/dialing_api/include/asterisk/dial.h
team/file/dialing_api/main/dial.c
Modified: team/file/dialing_api/apps/app_dial2.c
URL: http://svn.digium.com/view/asterisk/team/file/dialing_api/apps/app_dial2.c?view=diff&rev=49258&r1=49257&r2=49258
==============================================================================
--- team/file/dialing_api/apps/app_dial2.c (original)
+++ team/file/dialing_api/apps/app_dial2.c Tue Jan 2 18:14:27 2007
@@ -43,6 +43,7 @@
#include "asterisk/lock.h"
#include "asterisk/app.h"
#include "asterisk/dial.h"
+#include "asterisk/features.h"
static char *app = "Dial2";
static char *synopsis =
@@ -57,11 +58,12 @@
static int dial2_exec(struct ast_channel *chan, void *data)
{
- int res = 0;
+ int res = -1;
struct ast_module_user *u;
struct ast_dial *dial = NULL;
char *tmp = NULL, *tech = NULL, *device = NULL;
struct ast_channel *answered = NULL;
+ struct ast_bridge_config bridge_config;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "%s requires an argument (Technology/resource[&Tech2/resource2...])\n", app);
@@ -91,8 +93,17 @@
ast_dial_append(dial, tech, device);
}
- /* Attempt to dial all the channels */
- ast_dial_run(dial, chan, &answered, 0);
+ memset(&bridge_config, 0, sizeof(bridge_config));
+
+ /* Attempt to dial all the channels and bridge to the one that answered */
+ if (!ast_dial_run(dial, chan, 0) && (answered = ast_dial_answered(dial)))
+ ast_bridge_call(chan, answered, &bridge_config);
+
+ /* Hangup all calls in the dialing structure */
+ ast_dial_hangup(dial);
+
+ /* Perform cleanup on dial structure */
+ ast_dial_destroy(dial);
ast_module_user_remove(u);
Modified: team/file/dialing_api/include/asterisk/dial.h
URL: http://svn.digium.com/view/asterisk/team/file/dialing_api/include/asterisk/dial.h?view=diff&rev=49258&r1=49257&r2=49258
==============================================================================
--- team/file/dialing_api/include/asterisk/dial.h (original)
+++ team/file/dialing_api/include/asterisk/dial.h Tue Jan 2 18:14:27 2007
@@ -39,6 +39,15 @@
AST_DIAL_OPTION_MAX, /*! End terminator -- must always remain last */
};
+/*! \brief List of return codes for dial run API calls */
+enum ast_dial_result {
+ AST_DIAL_RESULT_INVALID = 0, /*! Invalid options were passed to run function */
+ AST_DIAL_RESULT_ANSWERED, /*! A channel was answered */
+ AST_DIAL_RESULT_TIMEOUT, /*! Timeout was tripped, nobody answered */
+ AST_DIAL_RESULT_HANGUP, /*! Caller hung up */
+ AST_DIAL_RESULT_UNANSWERED, /*! Nobody answered */
+};
+
/*! \brief New dialing structure
* \note Create a dialing structure
* \return Returns a calloc'd ast_dial structure, NULL on failure
@@ -55,13 +64,25 @@
* \note Dials channels in a dial structure and does not return until one is answered or timeout is reached. Will also forward progress/ringing.
* \return Returns 0 on success, -1 on failure
*/
-int ast_dial_run(struct ast_dial *dial, struct ast_channel *chan, struct ast_channel **answered, int timeout);
+enum ast_dial_result ast_dial_run(struct ast_dial *dial, struct ast_channel *chan, int timeout);
/*! \brief Execute dialing asynchronously
* \note Dials channels in a dial structure in a separate thread, returns almost immediately
* \return Returns 0 on success, -1 on failure
*/
int ast_dial_run_async(struct ast_dial *dial);
+
+/*! \brief Return channel that answered
+ * \note Returns the Asterisk channel that answered
+ * \param dial Dialing structure
+ */
+struct ast_channel *ast_dial_answered(struct ast_dial *dial);
+
+/*! \brief Hangup channels
+ * \note Hangup all active channels
+ * \param dial Dialing structure
+ */
+void ast_dial_hangup(struct ast_dial *dial);
/*! \brief Destroys a dialing structure
* \note Cancels dialing and destroys (free's) the given ast_dial structure
Modified: team/file/dialing_api/main/dial.c
URL: http://svn.digium.com/view/asterisk/team/file/dialing_api/main/dial.c?view=diff&rev=49258&r1=49257&r2=49258
==============================================================================
--- team/file/dialing_api/main/dial.c (original)
+++ team/file/dialing_api/main/dial.c Tue Jan 2 18:14:27 2007
@@ -47,6 +47,7 @@
struct ast_dial {
int num; /*! Current number to give to next dialed channel */
void *options[AST_DIAL_OPTION_MAX]; /*! Global options */
+ struct ast_channel *answered; /*! Channel that answered */
AST_LIST_HEAD_NOLOCK(, ast_dial_channel) channels; /*! Channels being dialed */
};
@@ -56,6 +57,7 @@
const char *tech; /*! Technology being dialed */
const char *device; /*! Device being dialed */
void *options[AST_DIAL_OPTION_MAX]; /*! Channel specific options */
+ int cause; /*! Cause code in case of failure */
struct ast_channel *owner; /*! Asterisk channel */
AST_LIST_ENTRY(ast_dial_channel) list; /*! Linked list information */
};
@@ -76,9 +78,22 @@
{ AST_DIAL_OPTION_MAX, NULL, NULL }, /*! Terminator of list */
};
+/* free the buffer if allocated, and set the pointer to the second arg */
+#define S_REPLACE(s, new_val) \
+ do { \
+ if (s) \
+ free(s); \
+ s = (new_val); \
+ } while (0)
+
+/*! \brief Maximum number of channels we can watch at a time */
+#define AST_MAX_WATCHERS 256
/*! \brief Macro for finding the option structure to use on a dialed channel */
#define FIND_RELATIVE_OPTION(dial, dial_channel, ast_dial_option) (dial_channel->options[ast_dial_option] ? dial_channel->options[ast_dial_option] : dial->options[ast_dial_option])
+
+/*! \brief Macro that determines whether a channel is the caller or not */
+#define IS_CALLER(chan, owner) (chan == owner ? 1 : 0)
/*! \brief New dialing structure
* \note Create a dialing structure
@@ -111,7 +126,7 @@
return -1;
/* Allocate new memory for dialed channel structure */
- if (!(channel = ast_calloc(1, sizeof(*dial))))
+ if (!(channel = ast_calloc(1, sizeof(*channel))))
return -1;
/* Record technology and device for when we actually dial */
@@ -127,13 +142,253 @@
return channel->num;
}
+/*! \brief Helper function that does the beginning dialing */
+static int begin_dial(struct ast_dial *dial, struct ast_channel *chan)
+{
+ struct ast_dial_channel *channel = NULL;
+ int success = 0, res = 0;
+
+ /* Iterate through channel list, requesting and calling each one */
+ AST_LIST_TRAVERSE(&dial->channels, channel, list) {
+ char numsubst[AST_MAX_EXTENSION];
+
+ /* Copy device string over */
+ ast_copy_string(numsubst, channel->device, sizeof(numsubst));
+
+ /* Request that the channel be created */
+ if (!(channel->owner = ast_request(channel->tech, chan->nativeformats, numsubst, &channel->cause)))
+ continue;
+
+ channel->owner->appl = "AppDial2";
+ channel->owner->data = "(Outgoing Line)";
+ channel->owner->whentohangup = 0;
+
+ /* Inherit everything from he who spawned this Dial */
+ ast_channel_inherit_variables(chan, channel->owner);
+
+ /* Copy over callerid information */
+ S_REPLACE(channel->owner->cid.cid_num, ast_strdup(chan->cid.cid_num));
+ S_REPLACE(channel->owner->cid.cid_name, ast_strdup(chan->cid.cid_name));
+ S_REPLACE(channel->owner->cid.cid_ani, ast_strdup(chan->cid.cid_ani));
+ S_REPLACE(channel->owner->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis));
+
+ ast_string_field_set(channel->owner, language, chan->language);
+ ast_string_field_set(channel->owner, accountcode, chan->accountcode);
+ channel->owner->cdrflags = chan->cdrflags;
+ if (ast_strlen_zero(channel->owner->musicclass))
+ ast_string_field_set(channel->owner, musicclass, chan->musicclass);
+
+ channel->owner->cid.cid_pres = chan->cid.cid_pres;
+ channel->owner->cid.cid_ton = chan->cid.cid_ton;
+ channel->owner->cid.cid_tns = chan->cid.cid_tns;
+ channel->owner->adsicpe = chan->adsicpe;
+ channel->owner->transfercapability = chan->transfercapability;
+
+ /* Actually call the device */
+ if ((res = ast_call(channel->owner, numsubst, 0))) {
+ ast_hangup(channel->owner);
+ channel->owner = NULL;
+ } else {
+ if (channel->owner->_state == AST_STATE_UP)
+ ast_log(LOG_NOTICE, "eeeeeeep they are up!\n");
+ success++;
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", numsubst);
+ }
+ }
+
+ /* If number of failures matches the number of channels, then this truly failed */
+ return success;
+}
+
+/*! \brief Helper function that finds the dialed channel based on owner */
+static struct ast_dial_channel *find_relative_dial_channel(struct ast_dial *dial, struct ast_channel *owner)
+{
+ struct ast_dial_channel *channel = NULL;
+
+ AST_LIST_TRAVERSE(&dial->channels, channel, list) {
+ if (channel->owner == owner)
+ break;
+ }
+
+ return channel;
+}
+
/*! \brief Execute dialing synchronously
* \note Dials channels in a dial structure and does not return until one is answered or timeout is reached. Will also forward progress/ringing.
* \return Returns 0 on success, -1 on failure
*/
-int ast_dial_run(struct ast_dial *dial, struct ast_channel *chan, struct ast_channel **answered, int timeout)
-{
- return 0;
+enum ast_dial_result ast_dial_run(struct ast_dial *dial, struct ast_channel *chan, int timeout)
+{
+ int to_monitor = 0, old_monitor = 0, single = 0;
+ struct ast_channel *cs[AST_MAX_WATCHERS] = {NULL, };
+ struct ast_dial_channel *channel = NULL;
+ enum ast_dial_result res = AST_DIAL_RESULT_INVALID;
+
+ /* Ensure required arguments are passed */
+ if (!dial || !chan)
+ return AST_DIAL_RESULT_INVALID;
+
+ /* If there are no channels to dial we can't very well try to dial them */
+ if (AST_LIST_EMPTY(&dial->channels))
+ return AST_DIAL_RESULT_INVALID;
+
+ /* Dial each requested channel */
+ if (!(to_monitor = begin_dial(dial, chan)))
+ return AST_DIAL_RESULT_INVALID;
+
+ /* Increment by one since we have to monitor our own channel */
+ to_monitor++;
+
+ /* See if this is just a single dial */
+ if (AST_LIST_FIRST(&dial->channels) == AST_LIST_LAST(&dial->channels))
+ single = 1;
+
+ /* If no timeout is specified, then assume infinite */
+ if (!timeout)
+ timeout = -1;
+
+ /* Go into a loop monitoring channels */
+ while (res == AST_DIAL_RESULT_INVALID) {
+ int pos = 1;
+ struct ast_channel *who = NULL;
+ struct ast_frame *fr = NULL;
+
+ /* If we are down to a single channel to monitor then our attempts have failed */
+ if (to_monitor == 1) {
+ res = AST_DIAL_RESULT_UNANSWERED;
+ break;
+ }
+
+ /* If the two monitor values do not match, we need to rebuild our watchers */
+ if (to_monitor != old_monitor) {
+ /* Put ourselves into the structure */
+ cs[0] = chan;
+ /* Now everyone else! */
+ pos = 1;
+ AST_LIST_TRAVERSE(&dial->channels, channel, list) {
+ if (!channel->owner)
+ continue;
+ cs[pos++] = channel->owner;
+ }
+ /* Finally record the new monitor count as the old monitor count */
+ old_monitor = to_monitor;
+ }
+
+ /* Monitor the channels */
+ if (!(who = ast_waitfor_n(cs, pos, &timeout)))
+ continue;
+
+ /* Find relative dial channel... just in case */
+ if (!IS_CALLER(chan, who))
+ channel = find_relative_dial_channel(dial, who);
+
+ /* Try to read in a frame */
+ if (!(fr = ast_read(who))) {
+ if (IS_CALLER(chan, who)) {
+ /* This is the caller who hung up */
+ res = AST_DIAL_RESULT_HANGUP;
+ continue;
+ }
+ ast_hangup(who);
+ channel->owner = NULL;
+ to_monitor--;
+ continue;
+ }
+
+ /* Process control frames first */
+ if (fr->frametype == AST_FRAME_CONTROL) {
+ switch (fr->subclass) {
+ case AST_CONTROL_ANSWER:
+ if (option_verbose > 2)
+ ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", who->name, chan->name);
+ dial->answered = who;
+ res = AST_DIAL_RESULT_ANSWERED;
+ break;
+ case AST_CONTROL_BUSY:
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "%s is busy\n", who->name);
+ ast_hangup(who);
+ channel->owner = NULL;
+ to_monitor--;
+ break;
+ case AST_CONTROL_CONGESTION:
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "%s is circuit-busy\n", who->name);
+ ast_hangup(who);
+ channel->owner = NULL;
+ to_monitor--;
+ break;
+ case AST_CONTROL_RINGING:
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "%s is ringing\n", who->name);
+ ast_indicate(chan, AST_CONTROL_RINGING);
+ break;
+ case AST_CONTROL_PROGRESS:
+ if (option_verbose > 2)
+ ast_verbose (VERBOSE_PREFIX_3 "%s is making progress, passing it to %s\n", who->name, chan->name);
+ ast_indicate(chan, AST_CONTROL_PROGRESS);
+ break;
+ case AST_CONTROL_VIDUPDATE:
+ if (option_verbose > 2)
+ ast_verbose (VERBOSE_PREFIX_3 "%s requested a video update, passing it to %s\n", who->name, chan->name);
+ ast_indicate(chan, AST_CONTROL_VIDUPDATE);
+ break;
+ case AST_CONTROL_PROCEEDING:
+ if (option_verbose > 2)
+ ast_verbose (VERBOSE_PREFIX_3 "%s is proceeding, passing it to %s\n", who->name, chan->name);
+ ast_indicate(chan, AST_CONTROL_PROCEEDING);
+ break;
+ case AST_CONTROL_HOLD:
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "Call on %s placed on hold\n", chan->name);
+ ast_indicate(chan, AST_CONTROL_HOLD);
+ break;
+ case AST_CONTROL_UNHOLD:
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "Call on %s left from hold\n", chan->name);
+ ast_indicate(chan, AST_CONTROL_UNHOLD);
+ break;
+ case AST_CONTROL_OFFHOOK:
+ case AST_CONTROL_FLASH:
+ break;
+ case -1:
+ /* Prod the channel */
+ ast_indicate(chan, -1);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /* Based on the result code we can determine what to do next */
+ switch (res) {
+ case AST_DIAL_RESULT_ANSWERED:
+ /* A channel was answered, so hang up all our other attempts */
+ AST_LIST_TRAVERSE(&dial->channels, channel, list) {
+ if (channel->owner && channel->owner != dial->answered) {
+ ast_hangup(channel->owner);
+ channel->owner = NULL;
+ }
+ }
+ break;
+ case AST_DIAL_RESULT_HANGUP:
+ case AST_DIAL_RESULT_UNANSWERED:
+ case AST_DIAL_RESULT_TIMEOUT:
+ /* No channels were answered, hangup everyone */
+ AST_LIST_TRAVERSE(&dial->channels, channel, list) {
+ if (channel->owner) {
+ ast_hangup(channel->owner);
+ channel->owner = NULL;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return res;
}
/*! \brief Execute dialing asynchronously
@@ -142,7 +397,41 @@
*/
int ast_dial_run_async(struct ast_dial *dial)
{
+ /* If there are no channels to dial we can't very well try to dial them */
+ if (AST_LIST_EMPTY(&dial->channels))
+ return -1;
+
return 0;
+}
+
+/*! \brief Return channel that answered
+ * \note Returns the Asterisk channel that answered
+ * \param dial Dialing structure
+ */
+struct ast_channel *ast_dial_answered(struct ast_dial *dial)
+{
+ return (dial ? dial->answered : NULL);
+}
+
+/*! \brief Hangup channels
+ * \note Hangup all active channels
+ * \param dial Dialing structure
+ */
+void ast_dial_hangup(struct ast_dial *dial)
+{
+ struct ast_dial_channel *channel = NULL;
+
+ if (!dial)
+ return;
+
+ AST_LIST_TRAVERSE(&dial->channels, channel, list) {
+ if (channel->owner) {
+ ast_hangup(channel->owner);
+ channel->owner = NULL;
+ }
+ }
+
+ return;
}
/*! \brief Destroys a dialing structure
@@ -152,11 +441,42 @@
*/
int ast_dial_destroy(struct ast_dial *dial)
{
- /* Abort any dialing */
-
+ int i = 0;
+ struct ast_dial_channel *channel = NULL;
+
+ if (!dial)
+ return -1;
+
+ /* Hangup and deallocate all the dialed channels */
+ AST_LIST_TRAVERSE(&dial->channels, channel, list) {
+ /* Disable any enabled options */
+ for (i = 0; i < AST_DIAL_OPTION_MAX; i++) {
+ if (!channel->options[i])
+ continue;
+ if (option_types[i].disable)
+ option_types[i].disable(channel->options[i]);
+ channel->options[i] = NULL;
+ }
+ /* Hang up channel if need be */
+ if (channel->owner) {
+ ast_hangup(channel->owner);
+ channel->owner = NULL;
+ }
+ /* Free structure */
+ free(channel);
+ }
+
/* Disable any enabled options globally */
+ for (i = 0; i < AST_DIAL_OPTION_MAX; i++) {
+ if (!dial->options[i])
+ continue;
+ if (option_types[i].disable)
+ option_types[i].disable(dial->options[i]);
+ dial->options[i] = NULL;
+ }
/* Free structure */
+ free(dial);
return 0;
}
More information about the asterisk-commits
mailing list