[asterisk-commits] russell: branch russell/sla_rewrite r52333 - /team/russell/sla_rewrite/apps/

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Fri Jan 26 16:18:58 MST 2007


Author: russell
Date: Fri Jan 26 17:18:57 2007
New Revision: 52333

URL: http://svn.digium.com/view/asterisk?view=rev&rev=52333
Log:
Today has been a good day in the world of SLA.  The SLAStation application
is now implemented.  I can now press the line buttons on one of my SIP phones,
and it will take the trunk off hook and dump it into the conference.  Then, the
trunk is providing its own dialtone.  All of the blinky lights work, too.

Modified:
    team/russell/sla_rewrite/apps/app_meetme.c

Modified: team/russell/sla_rewrite/apps/app_meetme.c
URL: http://svn.digium.com/view/asterisk/team/russell/sla_rewrite/apps/app_meetme.c?view=diff&rev=52333&r1=52332&r2=52333
==============================================================================
--- team/russell/sla_rewrite/apps/app_meetme.c (original)
+++ team/russell/sla_rewrite/apps/app_meetme.c Fri Jan 26 17:18:57 2007
@@ -371,7 +371,6 @@
 	/*! Number of stations currently on a call with this trunk */
 	unsigned int active_stations;
 	struct ast_channel *chan;
-	enum sla_trunk_state state;
 	pthread_t station_thread;
 };
 
@@ -2787,8 +2786,250 @@
 	return trunk;
 }
 
+/*! \brief Find an SLA station by name
+ * \note This must be called with the sla_stations container locked
+ */
+static struct sla_station *find_station(const char *name)
+{
+	struct sla_station *station = NULL;
+
+	AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
+		if (!strcasecmp(station->name, name))
+			break;
+	}
+
+	return station;
+}
+
+static struct sla_trunk_ref *find_trunk_ref(const struct sla_station *station,
+	const char *name)
+{
+	struct sla_trunk_ref *trunk_ref = NULL;
+
+	AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
+		if (!strcasecmp(trunk_ref->trunk->name, name))
+			break;
+	}
+
+	return trunk_ref;
+}
+
+struct dial_trunk_args {
+	struct sla_trunk *trunk;
+	struct sla_station *station;
+	ast_mutex_t *cond_lock;
+	ast_cond_t *cond;
+};
+
+static void *dial_trunk(void *data)
+{
+	struct dial_trunk_args *args = data;
+	struct ast_dial *dial;
+	char *tech, *tech_data;
+	enum ast_dial_result dial_res;
+	char conf_name[MAX_CONFNUM];
+	struct ast_conference *conf;
+	struct ast_flags conf_flags = { 0 };
+
+	if (!(dial = ast_dial_create())) {
+		ast_mutex_lock(args->cond_lock);
+		ast_cond_signal(args->cond);
+		ast_mutex_unlock(args->cond_lock);
+		return NULL;
+	}
+
+	tech_data = ast_strdupa(args->trunk->device);
+	tech = strsep(&tech_data, "/");
+	if (ast_dial_append(dial, tech, tech_data) == -1) {
+		ast_mutex_lock(args->cond_lock);
+		ast_cond_signal(args->cond);
+		ast_mutex_unlock(args->cond_lock);
+		ast_dial_destroy(dial);
+		return NULL;
+	}
+
+	dial_res = ast_dial_run(dial, NULL, 1);
+	if (dial_res != AST_DIAL_RESULT_TRYING) {
+		ast_mutex_lock(args->cond_lock);
+		ast_cond_signal(args->cond);
+		ast_mutex_unlock(args->cond_lock);
+		ast_dial_destroy(dial);
+		return NULL;
+	}
+
+	for (;;) {
+		unsigned int done = 0;
+		switch ((dial_res = ast_dial_status(dial))) {
+		case AST_DIAL_RESULT_ANSWERED:
+			args->trunk->chan = ast_dial_answered(dial);
+			ast_log(LOG_DEBUG, "chan %lx\n", (long) args->trunk->chan);
+		case AST_DIAL_RESULT_HANGUP:
+		case AST_DIAL_RESULT_INVALID:
+		case AST_DIAL_RESULT_FAILED:
+		case AST_DIAL_RESULT_TIMEOUT:
+		case AST_DIAL_RESULT_UNANSWERED:
+			done = 1;
+		case AST_DIAL_RESULT_TRYING:
+		case AST_DIAL_RESULT_RINGING:
+		case AST_DIAL_RESULT_PROGRESS:
+		case AST_DIAL_RESULT_PROCEEDING:
+			break;
+		}
+		if (done) {
+			ast_log(LOG_DEBUG, "done with dial_res %d\n", dial_res);
+			break;
+		}
+	}
+
+	if (!args->trunk->chan) {
+		ast_mutex_lock(args->cond_lock);
+		ast_cond_signal(args->cond);
+		ast_mutex_unlock(args->cond_lock);
+		ast_dial_join(dial);
+		ast_dial_destroy(dial);
+		ast_log(LOG_DEBUG, "broke out with no chan\n");
+		return NULL;
+	}
+
+	snprintf(conf_name, sizeof(conf_name), "SLA_%s", args->trunk->name);
+	ast_set_flag(&conf_flags, CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER);
+	conf = build_conf(conf_name, "", "", 1, 1, 1);
+
+	ast_mutex_lock(args->cond_lock);
+	ast_cond_signal(args->cond);
+	ast_mutex_unlock(args->cond_lock);
+
+	if (conf)
+		conf_run(args->trunk->chan, conf, conf_flags.flags, NULL);
+
+	args->trunk->chan = NULL;
+
+	ast_dial_join(dial);
+	ast_dial_destroy(dial);
+
+	return NULL;
+}
+
+static void change_trunk_state(const struct sla_trunk *trunk, enum sla_trunk_state state)
+{
+	struct sla_station *station;
+	struct sla_trunk_ref *trunk_ref;
+
+	ast_log(LOG_DEBUG, "Setting all refs of trunk %s to state %s\n", trunk->name, trunkstate2str(state));
+
+	AST_LIST_TRAVERSE(&sla_stations, station, entry) {
+		AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
+			if (trunk_ref->trunk != trunk)
+				continue;
+			trunk_ref->state = state;
+			ast_device_state_changed("SLA:%s_%s", station->name, trunk->name);
+			break;
+		}
+	}
+}
+
 static int slastation_exec(struct ast_channel *chan, void *data)
 {
+	char *station_name, *trunk_name;
+	struct sla_station *station;
+	struct sla_trunk_ref *trunk_ref = NULL;
+	char conf_name[MAX_CONFNUM];
+	int res;
+	struct ast_flags conf_flags = { 0 };
+	struct ast_conference *conf;
+
+	if (ast_strlen_zero(data)) {
+		ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
+		pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
+		return 0;
+	}
+
+	trunk_name = ast_strdupa(data);
+	station_name = strsep(&trunk_name, "_");
+
+	if (ast_strlen_zero(station_name)) {
+		ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
+		pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
+		return 0;
+	}
+
+	AST_RWLIST_RDLOCK(&sla_stations);
+	station = find_station(station_name);
+	AST_RWLIST_UNLOCK(&sla_stations);
+
+	if (!station) {
+		ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
+		pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
+		return 0;
+	}
+
+	AST_RWLIST_RDLOCK(&sla_trunks);
+	if (!ast_strlen_zero(trunk_name))
+		trunk_ref = find_trunk_ref(station, trunk_name);
+	else {
+		AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
+			if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
+				break;
+		}
+	}
+	AST_RWLIST_UNLOCK(&sla_trunks);
+
+	if (ast_strlen_zero(trunk_name) && !trunk_ref) {
+		ast_log(LOG_NOTICE, "No trunks available for call.\n");
+		pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
+		return 0;
+	}
+
+	if (!trunk_ref->trunk->chan) {
+		ast_mutex_t cond_lock;
+		ast_cond_t cond;
+		pthread_t dont_care;
+		struct dial_trunk_args args = {
+			.trunk = trunk_ref->trunk,
+			.station = station,
+			.cond_lock = &cond_lock,
+			.cond = &cond,
+		};
+		change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP);
+		/* Create a thread to dial the trunk and dump it into the conference.
+		 * However, we want to wait until the trunk has been dialed and the
+		 * conference is created before continuing on here. */
+		ast_autoservice_start(chan);
+		ast_mutex_init(&cond_lock);
+		ast_cond_init(&cond, NULL);
+		ast_mutex_lock(&cond_lock);
+		ast_pthread_create_background(&dont_care, NULL, dial_trunk, &args);
+		ast_cond_wait(&cond, &cond_lock);
+		ast_mutex_unlock(&cond_lock);
+		ast_mutex_destroy(&cond_lock);
+		ast_cond_destroy(&cond);
+		ast_autoservice_stop(chan);
+		if (!trunk_ref->trunk->chan) {
+			ast_log(LOG_DEBUG, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
+			pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
+			change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE);
+			return 0;
+		}
+	}
+
+	ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
+	snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
+	ast_set_flag(&conf_flags, CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT);
+	station->chan = chan;
+	ast_answer(chan);
+	conf = build_conf(conf_name, "", "", 0, 0, 1);
+	if (conf)
+		conf_run(chan, conf, conf_flags.flags, NULL);
+	station->chan = NULL;
+	res = ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, -1);
+	if (res == 1) {	
+		strncat(conf_name, "|K", sizeof(conf_name) - strlen(conf_name) - 1);
+		admin_exec(NULL, conf_name);
+		change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE);
+	}
+	ast_log(LOG_DEBUG, "Exit with success...\n");
+	pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
+
 	return 0;
 }
 
@@ -2900,14 +3141,14 @@
 		case AST_DIAL_RESULT_ANSWERED:
 			winner = i;
 			ast_answer(trunk->chan);
-			trunk->state = SLA_TRUNK_STATE_UP;
 			for (i = 0; trunk_refs[i]; i++) {
 				trunk_refs[i]->state = SLA_TRUNK_STATE_UP;
 				ast_device_state_changed("SLA:%s_%s", stations[i]->name, trunk->name);
 			}
 			break;
 		}
-		if (winner > -1 || trunk->state == SLA_TRUNK_STATE_IDLE)
+		/* We got a winner, or the trunk hung up. */
+		if (winner > -1 || !trunk->chan)
 			break;
 	}
 
@@ -2924,13 +3165,11 @@
 
 	ast_atomic_fetchadd_int((int *) &trunk->active_stations, 1);
 	stations[winner]->chan = ast_dial_answered(dials[winner]);
-	ast_set_flag(&conf_flags,
-		CONFFLAG_QUIET |
-		CONFFLAG_MARKEDEXIT);
+	ast_set_flag(&conf_flags, CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT);
 	snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk->name);
 	conf = build_conf(conf_name, "", "", 0, 0, 1);
 	if (conf)
-		res = conf_run(stations[winner]->chan, conf, conf_flags.flags, NULL);
+		conf_run(stations[winner]->chan, conf, conf_flags.flags, NULL);
 	res = ast_atomic_fetchadd_int((int *) &trunk->active_stations, -1);
 	if (res == 1) {	
 		strncat(conf_name, "|K", sizeof(conf_name) - strlen(conf_name) - 1);
@@ -2957,27 +3196,26 @@
 	const char *trunk_name = data;
 	char conf_name[MAX_CONFNUM];
 	struct ast_conference *conf;
-	int res;
 	struct ast_flags conf_flags = { 0 };
 	struct sla_trunk *trunk;
 
 	AST_RWLIST_RDLOCK(&sla_trunks);
 	trunk = find_trunk(trunk_name);
+	AST_RWLIST_UNLOCK(&sla_trunks);
 	if (!trunk) {
 		ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", trunk_name);
 		AST_RWLIST_UNLOCK(&sla_trunks);
 		pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
 		return 0;
 	}
-	trunk->chan = chan;
-	if (trunk->state != SLA_TRUNK_STATE_IDLE) {
-		ast_log(LOG_ERROR, "Call came in on %s, but the trunk is in state %s?!\n",
-			trunk_name, trunkstate2str(trunk->state));
+	if (trunk->chan) {
+		ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
+			trunk_name);
 		AST_RWLIST_UNLOCK(&sla_trunks);
 		pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
 		return 0;
 	}
-	AST_RWLIST_UNLOCK(&sla_trunks);
+	trunk->chan = chan;
 
 	snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_name);
 	conf = build_conf(conf_name, "", "", 1, 1, 1);
@@ -2991,17 +3229,13 @@
 		return 0;
 	}
 
-	ast_set_flag(&conf_flags, 
-		CONFFLAG_QUIET |       /* We don't want sounds played to the SLA */
-		CONFFLAG_MARKEDEXIT |  /* Close the conference when the trunk leaves */
-		CONFFLAG_MARKEDUSER);  /* Set the trunk as the "marked" user, so others will
-		                        * exit when the trunk leaves. */
+	ast_set_flag(&conf_flags, CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER);
 
 	ast_indicate(chan, AST_CONTROL_RINGING);
-	trunk->state = SLA_TRUNK_STATE_RINGING;
-	res = conf_run(chan, conf, conf_flags.flags, NULL);
-	trunk->state = SLA_TRUNK_STATE_IDLE;
+	conf_run(chan, conf, conf_flags.flags, NULL);
 	trunk->chan = NULL;
+
+	pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
 
 	return 0;
 }
@@ -3227,8 +3461,8 @@
 				continue;
 			}
 			station_ref->station = station;
+			ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
 			AST_RWLIST_WRLOCK(&sla_trunks);
-			trunk->num_stations++;
 			AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
 			AST_RWLIST_UNLOCK(&sla_trunks);
 			AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);



More information about the asterisk-commits mailing list