[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