[asterisk-commits] russell: branch russell/chan_console r54001 - /team/russell/chan_console/chan...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Sun Feb 11 21:15:49 MST 2007


Author: russell
Date: Sun Feb 11 22:15:48 2007
New Revision: 54001

URL: http://svn.digium.com/view/asterisk?view=rev&rev=54001
Log:
Add "console send text" CLI command, among other various formatting and
code cleanup changes ...

Modified:
    team/russell/chan_console/channels/chan_console.c

Modified: team/russell/chan_console/channels/chan_console.c
URL: http://svn.digium.com/view/asterisk/team/russell/chan_console/channels/chan_console.c?view=diff&rev=54001&r1=54000&r2=54001
==============================================================================
--- team/russell/chan_console/channels/chan_console.c (original)
+++ team/russell/chan_console/channels/chan_console.c Sun Feb 11 22:15:48 2007
@@ -27,6 +27,23 @@
  *       chan_alsa, Matthew Fredrickson <creslin at digium.com>
  * 
  * \ingroup channel_drivers
+ *
+ * \note Since this works with any audio system that libportaudio supports,
+ * including ALSA and OSS, this may someday deprecate chan_alsa and chan_oss.
+ * However, before that can be done, it needs to *at least* have all of the
+ * features that these other channel drivers have.  The features implemented
+ * in at least one of the other console channel drivers that are not yet
+ * implemented here are:
+ *
+ * Multiple device support
+ * Set Auto-answer from the dialplan
+ *
+ * answer CLI command
+ * flash CLI command
+ * transfer CLI command
+ * autoanswer CLI command (maybe general settings CLIcommand, instead?)
+ * boost CLI command
+ * active CLI command
  */
 
 /*** MODULEINFO
@@ -77,6 +94,12 @@
 /*! \brief Mono Output */
 #define OUTPUT_CHANNELS  1
 
+/*
+ * XXX text message sizes are probably 256 chars, but i am
+ * not sure if there is a suitable definition anywhere.
+ */
+#define TEXT_SIZE	256
+
 #ifndef MIN
 #define MIN(a,b) ((a) < (b) ? (a) : (b))
 #endif
@@ -84,7 +107,7 @@
 #define MAX(a,b) ((a) > (b) ? (a) : (b))
 #endif
 
-static const char *config_file = "console.conf";
+static const char config_file[] = "console.conf";
 
 /*!
  * Each sound is made of 'datalen' samples of sound, repeated as needed to
@@ -100,11 +123,11 @@
 	const int silencelen;
 	const int repeat;
 } sounds[] = {
-	{ AST_CONTROL_RINGING, "RINGING", ringtone, sizeof(ringtone)/2, 16000, 32000, 1 },
-	{ AST_CONTROL_BUSY, "BUSY", busy, sizeof(busy)/2, 4000, 4000, 1 },
-	{ AST_CONTROL_CONGESTION, "CONGESTION", busy, sizeof(busy)/2, 2000, 2000, 1 },
-	{ AST_CONTROL_RING, "RING10", ring10, sizeof(ring10)/2, 16000, 32000, 1 },
-	{ AST_CONTROL_ANSWER, "ANSWER", answer, sizeof(answer)/2, 2200, 0, 0 },
+	{ AST_CONTROL_RINGING,    "RINGING",    ringtone, sizeof(ringtone) / 2, 16000, 32000, 1 },
+	{ AST_CONTROL_BUSY,       "BUSY",       busy,     sizeof(busy) / 2,     4000,  4000,  1 },
+	{ AST_CONTROL_CONGESTION, "CONGESTION", busy,     sizeof(busy) / 2,     2000,  2000,  1 },
+	{ AST_CONTROL_RING,       "RING10",     ring10,   sizeof(ring10) / 2,   16000, 32000, 1 },
+	{ AST_CONTROL_ANSWER,     "ANSWER",     answer,   sizeof(answer) / 2,   2200,  0,     0 },
 	{ -1, NULL, 0, 0, 0, 0 },	/* end marker */
 };
 
@@ -161,7 +184,7 @@
 	ast_mutex_t lock;
 	/*! List of frames to be written out to the device */
 	AST_LIST_HEAD_NOLOCK(, ast_frame) frames;
-} pvt = {
+} console_pvt = {
 	.name = "default",
 	.lock = AST_MUTEX_INIT_VALUE,
 	.cursound = -1,
@@ -211,14 +234,14 @@
 	unsigned long frame_count, const PaStreamCallbackTimeInfo *time_info,
 	PaStreamCallbackFlags flags, void *userData);
 
-static int start_stream(void)
+static int start_stream(struct console_pvt *pvt)
 {
 	PaError res;
 
-	if (pvt.streamstate)
+	if (pvt->streamstate)
 		return 0;
 
-	res = Pa_OpenDefaultStream(&pvt.stream, INPUT_CHANNELS, OUTPUT_CHANNELS, 
+	res = Pa_OpenDefaultStream(&pvt->stream, INPUT_CHANNELS, OUTPUT_CHANNELS, 
 		paInt16, SAMPLE_RATE, NUM_SAMPLES, console_callback, NULL);
 	if (res != paNoError) {
 		ast_log(LOG_WARNING, "Failed to open default audio device - (%d) %s\n",
@@ -226,14 +249,14 @@
 		return -1;
 	}
 
-	res = Pa_StartStream(pvt.stream);
+	res = Pa_StartStream(pvt->stream);
 	if (res != paNoError) {
 		ast_log(LOG_WARNING, "Failed to start stream - (%d) %s\n",
 			res, Pa_GetErrorText(res));
 		return -1;
 	}
 
-	pvt.streamstate = 1;
+	pvt->streamstate = 1;
 
 	return 0;
 }
@@ -241,18 +264,18 @@
 /*!
  * \note Called with pvt struct locked
  */
-static int stop_stream(void)
-{
-	if (!pvt.streamstate)
+static int stop_stream(struct console_pvt *pvt)
+{
+	if (!pvt->streamstate)
 		return 0;
 
-	ast_mutex_lock(&pvt.lock);
-	Pa_AbortStream(pvt.stream);
-	Pa_CloseStream(pvt.stream);
-	pvt.stream = NULL;
-	pvt.streamstate = 0;
-	ast_cond_signal(&pvt.cond);
-	ast_mutex_unlock(&pvt.lock);
+	ast_mutex_lock(&pvt->lock);
+	Pa_AbortStream(pvt->stream);
+	Pa_CloseStream(pvt->stream);
+	pvt->stream = NULL;
+	pvt->streamstate = 0;
+	ast_cond_signal(&pvt->cond);
+	ast_mutex_unlock(&pvt->lock);
 
 	return 0;
 }
@@ -297,7 +320,7 @@
 			ast_hangup(chan);
 			chan = NULL;
 		} else
-			start_stream();
+			start_stream(pvt);
 	}
 
 	return chan;
@@ -307,6 +330,7 @@
 {
 	int oldformat = format;
 	struct ast_channel *chan = NULL;
+	struct console_pvt *pvt = &console_pvt;
 
 	format &= AST_FORMAT_SLINEAR;
 	if (!format) {
@@ -314,13 +338,13 @@
 		return NULL;
 	}
 
-	ast_mutex_lock(&pvt.lock);
-	if (pvt.owner) {
+	ast_mutex_lock(&pvt->lock);
+	if (pvt->owner) {
 		ast_log(LOG_NOTICE, "Console channel already active!\n");
 		*cause = AST_CAUSE_BUSY;
-	} else if (!(chan = console_new(&pvt, NULL, NULL, AST_STATE_DOWN)))
+	} else if (!(chan = console_new(pvt, NULL, NULL, AST_STATE_DOWN)))
 		ast_log(LOG_WARNING, "Unable to create new Console channel!\n");
-	ast_mutex_unlock(&pvt.lock);
+	ast_mutex_unlock(&pvt->lock);
 
 	return chan;
 }
@@ -371,23 +395,25 @@
 
 static int console_hangup(struct ast_channel *c)
 {
+	struct console_pvt *pvt = &console_pvt;
+
 	ast_verbose(" --- <(\"<) --- Hangup on Console --- (>\")> ---\n");
 
-	pvt.hookstate = 0;
-	set_cursound(&pvt, -1);
+	pvt->hookstate = 0;
+	set_cursound(pvt, -1);
 	c->tech_pvt = NULL;
-	pvt.owner = NULL;
+	pvt->owner = NULL;
 
 	/* Wait until the callback has exited before stopping the stream, also
 	 * ensuring that the callback isn't blocking while waiting on a frame. */
-	while (pvt.incallback) { /* :( */
-		ast_mutex_lock(&pvt.lock);
-		ast_cond_signal(&pvt.cond);
-		ast_mutex_unlock(&pvt.lock);
+	while (pvt->incallback) { /* :( */
+		ast_mutex_lock(&pvt->lock);
+		ast_cond_signal(&pvt->cond);
+		ast_mutex_unlock(&pvt->lock);
 		usleep(10);
 	}
 
-	stop_stream();
+	stop_stream(pvt);
 
 	return 0;
 }
@@ -395,14 +421,15 @@
 static int console_answer(struct ast_channel *c)
 {
 	int res;
+	struct console_pvt *pvt = &console_pvt;
 
 	ast_verbose(" --- <(\"<) --- Call from Console has been Answered --- (>\")> ---\n");
 
-	ast_mutex_lock(&pvt.lock);
+	ast_mutex_lock(&pvt->lock);
 	ast_setstate(c, AST_STATE_UP);
-	set_cursound(&pvt, -1);
-	res = start_stream();
-	ast_mutex_unlock(&pvt.lock);
+	set_cursound(pvt, -1);
+	res = start_stream(pvt);
+	ast_mutex_unlock(&pvt->lock);
 
 	return res;
 }
@@ -417,13 +444,14 @@
 static int console_call(struct ast_channel *c, char *dest, int timeout)
 {
 	struct ast_frame f = { 0, };
+	struct console_pvt *pvt = &console_pvt;
 
 	ast_verbose(" --- <(\"<) --- Call to device '%s' on console from '%s' <%s> --- (>\")> ---\n",
 		dest, c->cid.cid_name, c->cid.cid_num);
 
-	if (pvt.autoanswer) {
+	if (pvt->autoanswer) {
 		ast_verbose(" --- <(\"<) --- Auto-answered --- (>\")> --- \n");
-		pvt.hookstate = 1;
+		pvt->hookstate = 1;
 		f.frametype = AST_FRAME_CONTROL;
 		f.subclass = AST_CONTROL_ANSWER;
 		ast_queue_frame(c, &f);
@@ -432,22 +460,23 @@
 		f.frametype = AST_FRAME_CONTROL;
 		f.subclass = AST_CONTROL_RINGING;
 		ast_queue_frame(c, &f);
-		set_cursound(&pvt, AST_CONTROL_RING);
-	}
-
-	return start_stream();
+		set_cursound(pvt, AST_CONTROL_RING);
+	}
+
+	return start_stream(pvt);
 }
 
 static int console_write(struct ast_channel *chan, struct ast_frame *f)
 {
 	struct ast_frame *fr = ast_frdup(f);
+	struct console_pvt *pvt = &console_pvt;
 
 	if (!fr)
 		return -1; 
-	ast_mutex_lock(&pvt.lock);
-	AST_LIST_INSERT_TAIL(&pvt.frames, fr, frame_list);
-	ast_cond_signal(&pvt.cond);
-	ast_mutex_unlock(&pvt.lock);
+	ast_mutex_lock(&pvt->lock);
+	AST_LIST_INSERT_TAIL(&pvt->frames, fr, frame_list);
+	ast_cond_signal(&pvt->cond);
+	ast_mutex_unlock(&pvt->lock);
 
 	return 0;
 }
@@ -484,9 +513,11 @@
 
 static int console_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 {
-	ast_mutex_lock(&pvt.lock);
-	pvt.owner = newchan;
-	ast_mutex_unlock(&pvt.lock);
+	struct console_pvt *pvt = &console_pvt;
+
+	ast_mutex_lock(&pvt->lock);
+	pvt->owner = newchan;
+	ast_mutex_unlock(&pvt->lock);
 
 	return 0;
 }
@@ -632,16 +663,16 @@
 	PaStreamCallbackFlags flags, void *userData)
 {
 	int res = paContinue;
-	struct console_pvt *p = &pvt;
-
-	p->incallback = 1;
+	struct console_pvt *pvt = &console_pvt;
+
+	pvt->incallback = 1;
 
 	if (output)
-		res = handle_output(p, output, frame_count);
+		res = handle_output(pvt, output, frame_count);
 	if (res != paAbort && input)
-		res = handle_input(p, input, frame_count);
-
-	p->incallback = 0;
+		res = handle_input(pvt, input, frame_count);
+
+	pvt->incallback = 0;
 
 	return res;
 }
@@ -655,7 +686,7 @@
  * and it is nice not to need it because you have '@' in SIP addresses.
  * Return value is the buffer address.
  */
-static char *ast_ext_ctx(const char *src, char **ext, char **ctx)
+static char *ast_ext_ctx(struct console_pvt *pvt, const char *src, char **ext, char **ctx)
 {
 	if (ext == NULL || ctx == NULL)
 		return NULL;			/* error */
@@ -668,7 +699,7 @@
 	if (*ext == NULL)
 		return NULL;
 
-	if (!pvt.overridecontext) {
+	if (!pvt->overridecontext) {
 		/* parse from the right */
 		*ctx = strrchr(*ext, '@');
 		if (*ctx)
@@ -681,6 +712,7 @@
 static char *cli_console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	char *s = NULL, *mye = NULL, *myc = NULL;
+	struct console_pvt *pvt = &console_pvt;
 
 	if (cmd == CLI_INIT) {
 		e->command = "console dial";
@@ -693,7 +725,7 @@
 
 	if (a->argc > e->args + 1)
 		return CLI_SHOWUSAGE;
-	if (pvt.owner) {	/* already in a call */
+	if (pvt->owner) {	/* already in a call */
 		int i;
 		struct ast_frame f = { AST_FRAME_DTMF, 0 };
 
@@ -705,23 +737,23 @@
 		/* send the string one char at a time */
 		for (i = 0; i < strlen(s); i++) {
 			f.subclass = s[i];
-			ast_queue_frame(pvt.owner, &f);
+			ast_queue_frame(pvt->owner, &f);
 		}
 		return CLI_SUCCESS;
 	}
 	/* if we have an argument split it into extension and context */
 	if (a->argc == e->args + 1) {
-		s = ast_ext_ctx(a->argv[e->args], &mye, &myc);
+		s = ast_ext_ctx(pvt, a->argv[e->args], &mye, &myc);
 		ast_log(LOG_NOTICE, "provided '%s', exten '%s' context '%s'\n", a->argv[e->args], mye, myc);
 	}
 	/* supply default values if needed */
 	if (mye == NULL)
-		mye = pvt.exten;
+		mye = pvt->exten;
 	if (myc == NULL)
-		myc = pvt.context;
+		myc = pvt->context;
 	if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
-		pvt.hookstate = 1;
-		console_new(&pvt, mye, myc, AST_STATE_RINGING);
+		pvt->hookstate = 1;
+		console_new(pvt, mye, myc, AST_STATE_RINGING);
 	} else
 		ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
 	if (s)
@@ -731,6 +763,8 @@
 
 static char *cli_console_hangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
+	struct console_pvt *pvt = &console_pvt;
+
 	if (cmd == CLI_INIT) {
 		e->command = "console hangup";
 		e->usage =
@@ -742,14 +776,14 @@
 
 	if (a->argc != e->args)
 		return CLI_SHOWUSAGE;
-	if (!pvt.owner && !pvt.hookstate) {
+	if (!pvt->owner && !pvt->hookstate) {
 		ast_cli(a->fd, "No call to hang up\n");
 		return CLI_FAILURE;
 	}
-	pvt.hookstate = 0;
-	set_cursound(&pvt, -1);
-	if (pvt.owner)
-		ast_queue_hangup(pvt.owner);
+	pvt->hookstate = 0;
+	set_cursound(pvt, -1);
+	if (pvt->owner)
+		ast_queue_hangup(pvt->owner);
 
 	return CLI_SUCCESS;
 }
@@ -757,6 +791,7 @@
 static char *cli_console_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	char *s;
+	struct console_pvt *pvt = &console_pvt;
 	
 	if (cmd == CLI_INIT) {
 		e->command = "console {mute|unmute}";
@@ -771,14 +806,14 @@
 		return CLI_SHOWUSAGE;
 	s = a->argv[e->args-1];
 	if (!strcasecmp(s, "mute"))
-		pvt.muted = 1;
+		pvt->muted = 1;
 	else if (!strcasecmp(s, "unmute"))
-		pvt.muted = 0;
+		pvt->muted = 0;
 	else
 		return CLI_SHOWUSAGE;
 
 	ast_verbose(" --- <(\"<) --- The Console is now %s --- (>\")> ---\n", 
-		pvt.muted ? "Muted" : "Unmuted");
+		pvt->muted ? "Muted" : "Unmuted");
 
 	return CLI_SUCCESS;
 }
@@ -822,10 +857,51 @@
 	return CLI_SUCCESS;
 }
 
+/*!
+ * \brief Console send text CLI command
+ *
+ * \note concatenate all arguments into a single string. argv is NULL-terminated
+ * so we can use it right away
+ */
+static char *cli_console_sendtext(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	char buf[TEXT_SIZE];
+	struct console_pvt *pvt = &console_pvt;
+
+	if (cmd == CLI_INIT) {
+		e->command = "console send text";
+		e->usage =
+			"Usage: console send text <message>\n"
+			"       Sends a text message for display on the remote terminal.\n";
+		return NULL;
+	} else if (cmd == CLI_GENERATE)
+		return NULL;
+
+	if (a->argc < e->args + 1)
+		return CLI_SHOWUSAGE;
+	if (!pvt->owner) {
+		ast_cli(a->fd, "Not in a call\n");
+		return CLI_FAILURE;
+	}
+	ast_join(buf, sizeof(buf) - 1, a->argv + e->args);
+	if (!ast_strlen_zero(buf)) {
+		struct ast_frame f = { 0, };
+		int i = strlen(buf);
+		buf[i] = '\n';
+		f.frametype = AST_FRAME_TEXT;
+		f.subclass = 0;
+		f.data = buf;
+		f.datalen = i + 1;
+		ast_queue_frame(pvt->owner, &f);
+	}
+	return CLI_SUCCESS;
+}
+
 static struct ast_cli_entry cli_console[] = {
 	NEW_CLI(cli_console_dial, "Dial an extension from the console"),
 	NEW_CLI(cli_console_hangup, "Hangup a call on the console"),
 	NEW_CLI(cli_console_mute, "Disable/Enable mic input"),
+	NEW_CLI(cli_console_sendtext, "Send text to a connected party"),
 	NEW_CLI(cli_list_devices, "List available devices"),
 };
 
@@ -839,17 +915,18 @@
 {
 	struct ast_config *cfg;
 	struct ast_variable *v;
+	struct console_pvt *pvt = &console_pvt;
 
 	/* default values */
 	memcpy(&global_jbconf, &default_jbconf, sizeof(global_jbconf));
-	strcpy(pvt.mohinterpret, "default");
-	strcpy(pvt.context, "default");
-	strcpy(pvt.exten, "s");
-	pvt.language[0] = '\0';
-	pvt.cid_num[0] = '\0';
-	pvt.cid_name[0] = '\0';
-	pvt.overridecontext = 0;
-	pvt.autoanswer = 0;
+	strcpy(pvt->mohinterpret, "default");
+	strcpy(pvt->context, "default");
+	strcpy(pvt->exten, "s");
+	pvt->language[0] = '\0';
+	pvt->cid_num[0] = '\0';
+	pvt->cid_name[0] = '\0';
+	pvt->overridecontext = 0;
+	pvt->autoanswer = 0;
 
 	if (!(cfg = ast_config_load(config_file))) {
 		ast_log(LOG_NOTICE, "Unable to open configuration file %s!\n", config_file);
@@ -860,20 +937,20 @@
 		if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
 			continue;
 		else if (!strcasecmp(v->name, "context"))
-			ast_copy_string(pvt.context, v->value, sizeof(pvt.context));
+			ast_copy_string(pvt->context, v->value, sizeof(pvt->context));
 		else if (!strcasecmp(v->name, "extension"))
-			ast_copy_string(pvt.exten, v->value, sizeof(pvt.exten));
+			ast_copy_string(pvt->exten, v->value, sizeof(pvt->exten));
 		else if (!strcasecmp(v->name, "mohinterpret"))
-			ast_copy_string(pvt.mohinterpret, v->value, sizeof(pvt.mohinterpret));
+			ast_copy_string(pvt->mohinterpret, v->value, sizeof(pvt->mohinterpret));
 		else if (!strcasecmp(v->name, "language"))
-			ast_copy_string(pvt.language, v->value, sizeof(pvt.language));
+			ast_copy_string(pvt->language, v->value, sizeof(pvt->language));
 		else if (!strcasecmp(v->name, "callerid"))
-			ast_callerid_split(v->value, pvt.cid_name, sizeof(pvt.cid_name), 
-				pvt.cid_num, sizeof(pvt.cid_num));
+			ast_callerid_split(v->value, pvt->cid_name, sizeof(pvt->cid_name), 
+				pvt->cid_num, sizeof(pvt->cid_num));
 		else if (!strcasecmp(v->name, "overridecontext"))
-			pvt.overridecontext = ast_true(v->value) ? 1 : 0;
+			pvt->overridecontext = ast_true(v->value) ? 1 : 0;
 		else if (!strcasecmp(v->name, "autoanswer"))
-			pvt.autoanswer = ast_true(v->value) ? 1 : 0;
+			pvt->autoanswer = ast_true(v->value) ? 1 : 0;
 		else
 			ast_log(LOG_WARNING, "Unknown option '%s' on line '%d' of '%s'!\n",
 				v->name, v->lineno, config_file);
@@ -885,14 +962,16 @@
 
 static int unload_module(void)
 {
-	if (pvt.hookstate)
-		stop_stream();
+	struct console_pvt *pvt = &console_pvt;
+
+	if (pvt->hookstate)
+		stop_stream(pvt);
 	Pa_Terminate();
 
 	ast_channel_unregister(&console_tech);
 	ast_cli_unregister_multiple(cli_console, sizeof(cli_console) / sizeof(cli_console[0]));
 
-	ast_cond_destroy(&pvt.cond);
+	ast_cond_destroy(&pvt->cond);
 
 	return 0;
 }
@@ -900,11 +979,12 @@
 static int load_module(void)
 {
 	PaError res;
+	struct console_pvt *pvt = &console_pvt;
 
 	if (load_config(0))
 		return AST_MODULE_LOAD_DECLINE;
 
-	ast_cond_init(&pvt.cond, NULL);
+	ast_cond_init(&pvt->cond, NULL);
 
 	res = Pa_Initialize();
 	if (res != paNoError) {
@@ -915,7 +995,7 @@
 
 	if (ast_channel_register(&console_tech)) {
 		ast_log(LOG_ERROR, "Unable to register channel type 'Console'\n");
-		ast_cond_destroy(&pvt.cond);
+		ast_cond_destroy(&pvt->cond);
 		return AST_MODULE_LOAD_DECLINE;
 	}
 	



More information about the asterisk-commits mailing list