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

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Dec 31 08:08:45 CST 2007


Author: russell
Date: Mon Dec 31 08:08:45 2007
New Revision: 95381

URL: http://svn.digium.com/view/asterisk?view=rev&rev=95381
Log:
These changes are mostly adding comments and other cosmetic changes.  I did
rearrange some code, and add locking in at least one place where it was needed.

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=95381&r1=95380&r2=95381
==============================================================================
--- team/russell/chan_console/channels/chan_console.c (original)
+++ team/russell/chan_console/channels/chan_console.c Mon Dec 31 08:08:45 2007
@@ -36,14 +36,12 @@
  * in at least one of the other console channel drivers that are not yet
  * implemented here are:
  *
- * Multiple device support
- *  - with "active" CLI command
- * Set Auto-answer from the dialplan
- *
- * transfer CLI command
- * boost CLI command and .conf option
- *
- * console_video support
+ * - Multiple device support
+ *   - with "active" CLI command
+ * - Set Auto-answer from the dialplan
+ * - transfer CLI command
+ * - boost CLI command and .conf option
+ * - console_video support
  */
 
 /*** MODULEINFO
@@ -67,29 +65,39 @@
 /*! 
  * \brief The sample rate to request from PortAudio 
  *
- * \note 8000 is universal in Asterisk right now.  Once it supports 16kHz,
- * it should probably be made an option, with a default of 16kHz.
+ * \note This should be changed to 16000 once there is a translator for going
+ *       between SLINEAR and SLINEAR16.  Making it a configuration parameter
+ *       would be even better, but 16 kHz should be the default.
+ *
+ * \note If this changes, NUM_SAMPLES will need to change, as well.
  */
 #define SAMPLE_RATE      8000
+
 /*! 
- * \brief The number of samples to read/write per callback 
- *
- * 160 samples is the most common frame size in Asterisk, so this makes
- * incoming frames and writing data out to the callback a 1 to 1 process
- * for convenience.  However, the code is still written to handle arbitrary
- * frame sizes.
+ * \brief The number of samples to configure the portaudio stream for
+ *
+ * 160 samples (20 ms) is the most common frame size in Asterisk.  So, the code
+ * in this module reads 160 sample frames from the portaudio stream and queues
+ * them up on the Asterisk channel.  Frames of any sizes can be written to a
+ * portaudio stream, but the portaudio documentation does say that for high
+ * performance applications, the data should be written to Pa_WriteStream in
+ * the same size as what is used to initialize the stream.
+ *
+ * \note This will need to be dynamic once the sample rate can be something
+ *       other than 8 kHz.
  */
 #define NUM_SAMPLES      160
+
 /*! \brief Mono Input */
 #define INPUT_CHANNELS   1
+
 /*! \brief Mono Output */
 #define OUTPUT_CHANNELS  1
 
-#define RINGBUFFER_SIZE 16384
-
-/*
- * XXX text message sizes are probably 256 chars, but i am
- * not sure if there is a suitable definition anywhere.
+/*! 
+ * \brief Maximum text message length
+ * \note This should be changed if there is a common definition somewhere
+ *       that defines the maximum length of a text message.
  */
 #define TEXT_SIZE	256
 
@@ -148,16 +156,20 @@
 	unsigned int autoanswer:1;
 	/*! Ignore context in the console dial CLI command */
 	unsigned int overridecontext:1;
-	/*! Lock for this struct */
-	ast_mutex_t lock;
+	/*! Lock to protect data in this struct */
+	ast_mutex_t __lock;
 	/*! ID for the stream monitor thread */
 	pthread_t thread;
 } console_pvt = {
-	.lock = AST_MUTEX_INIT_VALUE,
+	.__lock = AST_MUTEX_INIT_VALUE,
 	.thread = AST_PTHREADT_NULL,
 };
 
-/*! Global jitterbuffer configuration - by default, jb is disabled */
+/*! 
+ * \brief Global jitterbuffer configuration 
+ *
+ * \note Disabled by default.
+ */
 static struct ast_jb_conf default_jbconf = {
 	.flags = 0,
 	.max_size = -1,
@@ -182,11 +194,16 @@
 static int console_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
 /*! @} */
 
+/*!
+ * \brief Formats natively supported by this module.
+ *
+ * \note Once 16 kHz is supported, AST_FORMAT_SLINEAR16 needs to be added.
+ */
 #define SUPPORTED_FORMATS ( AST_FORMAT_SLINEAR )
 
 static const struct ast_channel_tech console_tech = {
 	.type = "Console",
-	.description = "Cross-platform Console Channel Driver",
+	.description = "Console Channel Driver",
 	.capabilities = SUPPORTED_FORMATS,
 	.requester = console_request,
 	.send_digit_begin = console_digit_begin,
@@ -201,6 +218,12 @@
 	.fixup = console_fixup,
 };
 
+/*! \brief lock a console_pvt struct */
+#define console_pvt_lock(pvt) ast_mutex_lock(&(pvt)->__lock)
+
+/*! \brief unlock a console_pvt struct */
+#define console_pvt_unlock(pvt) ast_mutex_unlock(&(pvt)->__lock)
+
 /*!
  * \brief Stream monitor thread 
  *
@@ -216,26 +239,22 @@
 	struct console_pvt *pvt = data;
 	char buf[NUM_SAMPLES * sizeof(int16_t)];
 	PaError res;
+	struct ast_frame f = {
+		.frametype = AST_FRAME_VOICE,
+		.subclass = AST_FORMAT_SLINEAR,
+		.src = "console_stream_monitor",
+		.data = buf,
+		.datalen = sizeof(buf),
+		.samples = sizeof(buf) / sizeof(int16_t),
+	};
 
 	for (;;) {
 		pthread_testcancel();
-
 		res = Pa_ReadStream(pvt->stream, buf, sizeof(buf) / sizeof(int16_t));
-
 		pthread_testcancel();
 
-		if (res == paNoError) {
-			struct ast_frame f = {
-				.frametype = AST_FRAME_VOICE,
-				.subclass = AST_FORMAT_SLINEAR,
-				.src = "console_stream_monitor",
-				.data = buf,
-				.datalen = sizeof(buf),
-				.samples = sizeof(buf) / sizeof(int16_t),
-			};
-
+		if (res == paNoError)
 			ast_queue_frame(pvt->owner, &f);
-		}
 	}
 
 	return NULL;
@@ -246,7 +265,7 @@
 	PaError res;
 	int ret_val = 0;
 
-	ast_mutex_lock(&pvt->lock);
+	console_pvt_lock(pvt);
 
 	if (pvt->streamstate)
 		goto return_unlock;
@@ -277,7 +296,7 @@
 	}
 
 return_unlock:
-	ast_mutex_unlock(&pvt->lock);
+	console_pvt_unlock(pvt);
 
 	return ret_val;
 }
@@ -291,12 +310,12 @@
 	pthread_kill(pvt->thread, SIGURG);
 	pthread_join(pvt->thread, NULL);
 
-	ast_mutex_lock(&pvt->lock);
+	console_pvt_lock(pvt);
 	Pa_AbortStream(pvt->stream);
 	Pa_CloseStream(pvt->stream);
 	pvt->stream = NULL;
 	pvt->streamstate = 0;
-	ast_mutex_unlock(&pvt->lock);
+	console_pvt_unlock(pvt);
 
 	return 0;
 }
@@ -308,8 +327,10 @@
 {
 	struct ast_channel *chan;
 
-	if (!(chan = ast_channel_alloc(1, state, pvt->cid_num, pvt->cid_name, NULL, ext, ctx, 0, "Console/%s", pvt->name)))
-		return NULL;
+	if (!(chan = ast_channel_alloc(1, state, pvt->cid_num, pvt->cid_name, NULL, 
+		ext, ctx, 0, "Console/%s", pvt->name))) {
+		return NULL;
+	}
 
 	chan->tech = &console_tech;
 	chan->nativeformats = AST_FORMAT_SLINEAR;
@@ -326,7 +347,6 @@
 
 	if (state != AST_STATE_DOWN) {
 		if (ast_pbx_start(chan)) {
-			ast_log(LOG_WARNING, "Unable to start PBX on %s\n", chan->name);
 			chan->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
 			ast_hangup(chan);
 			chan = NULL;
@@ -340,7 +360,7 @@
 static struct ast_channel *console_request(const char *type, int format, void *data, int *cause)
 {
 	int oldformat = format;
-	struct ast_channel *chan = NULL;
+	struct ast_channel *chan;
 	struct console_pvt *pvt = &console_pvt;
 
 	format &= SUPPORTED_FORMATS;
@@ -349,13 +369,18 @@
 		return NULL;
 	}
 
-	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)))
+		return NULL;
+	}
+
+	console_pvt_lock(pvt);
+	chan = console_new(pvt, NULL, NULL, AST_STATE_DOWN);
+	console_pvt_unlock(pvt);
+
+	if (!chan)
 		ast_log(LOG_WARNING, "Unable to create new Console channel!\n");
-	ast_mutex_unlock(&pvt->lock);
 
 	return chan;
 }
@@ -408,6 +433,26 @@
 	return start_stream(pvt);
 }
 
+/*
+ * \brief Implementation of the ast_channel_tech read() callback
+ *
+ * Calling this function is harmless.  However, if it does get called, it
+ * is an indication that something weird happened that really shouldn't
+ * have and is worth looking into.
+ * 
+ * Why should this function not get called?  Well, let me explain.  There are
+ * a couple of ways to pass on audio that has come from this channel.  The way
+ * that this channel driver uses is that once the audio is available, it is
+ * wrapped in an ast_frame and queued onto the channel using ast_queue_frame().
+ *
+ * The other method would be signalling to the core that there is audio waiting,
+ * and that it needs to call the channel's read() callback to get it.  The way
+ * the channel gets signalled is that one or more file descriptors are placed
+ * in the fds array on the ast_channel which the core will poll() on.  When the
+ * fd indicates that input is available, the read() callback is called.  This
+ * is especially useful when there is a dedicated file descriptor where the
+ * audio is read from.  An example would be the socket for an RTP stream.
+ */
 static struct ast_frame *console_read(struct ast_channel *chan)
 {
 	ast_debug(1, "I should not be called ...\n");
@@ -423,7 +468,7 @@
 	ast_verb(1, V_BEGIN "Call to device '%s' on console from '%s' <%s>" V_END,
 		dest, c->cid.cid_name, c->cid.cid_num);
 
-	ast_mutex_lock(&pvt->lock);
+	console_pvt_lock(pvt);
 
 	if (pvt->autoanswer) {
 		ast_verb(1, V_BEGIN "Auto-answered" V_END);
@@ -437,7 +482,7 @@
 		f.subclass = AST_CONTROL_RINGING;
 	}
 
-	ast_mutex_unlock(&pvt->lock);
+	console_pvt_unlock(pvt);
 
 	ast_queue_frame(c, &f);
 
@@ -606,7 +651,6 @@
 {
 	char *s = NULL;
 	const char *mye = NULL, *myc = NULL; 
-	
 	struct console_pvt *pvt = &console_pvt;
 
 	if (cmd == CLI_INIT) {
@@ -620,6 +664,7 @@
 
 	if (a->argc > e->args + 1)
 		return CLI_SHOWUSAGE;
+
 	if (pvt->owner) {	/* already in a call */
 		int i;
 		struct ast_frame f = { AST_FRAME_DTMF, 0 };
@@ -636,6 +681,7 @@
 		}
 		return CLI_SUCCESS;
 	}
+
 	/* if we have an argument split it into extension and context */
 	if (a->argc == e->args + 1) {
 		char *ext = NULL, *con = NULL;
@@ -645,18 +691,24 @@
 		mye = ext;
 		myc = con;
 	}
+
 	/* supply default values if needed */
-	if (mye == NULL)
+	if (ast_strlen_zero(mye))
 		mye = pvt->exten;
-	if (myc == NULL)
+	if (ast_strlen_zero(myc))
 		myc = pvt->context;
+
 	if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
+		console_pvt_lock(pvt);
 		pvt->hookstate = 1;
 		console_new(pvt, mye, myc, AST_STATE_RINGING);
+		console_pvt_unlock(pvt);
 	} else
 		ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
+
 	if (s)
 		free(s);
+
 	return CLI_SUCCESS;
 }
 
@@ -803,6 +855,12 @@
 {
 	char buf[TEXT_SIZE];
 	struct console_pvt *pvt = &console_pvt;
+	struct ast_frame f = {
+		.frametype = AST_FRAME_TEXT,
+		.data = buf,
+		.src = "console_send_text",
+	};
+	int len;
 
 	if (cmd == CLI_INIT) {
 		e->command = "console send text";
@@ -822,35 +880,42 @@
 	}
 
 	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);
-	}
+	if (ast_strlen_zero(buf))
+		return CLI_SHOWUSAGE;
+
+	len = strlen(buf);
+	buf[len] = '\n';
+	f.datalen = len + 1;
+
+	ast_queue_frame(pvt->owner, &f);
 
 	return CLI_SUCCESS;
 }
 
 static struct ast_cli_entry cli_console[] = {
-	AST_CLI_DEFINE(cli_console_dial, "Dial an extension from the console"),
-	AST_CLI_DEFINE(cli_console_hangup, "Hangup a call on the console"),
-	AST_CLI_DEFINE(cli_console_mute, "Disable/Enable mic input"),
-	AST_CLI_DEFINE(cli_console_answer, "Answer an incoming console call"),
-	AST_CLI_DEFINE(cli_console_sendtext, "Send text to a connected party"),
-	AST_CLI_DEFINE(cli_console_flash, "Send a flash to the connected party"),
+	AST_CLI_DEFINE(cli_console_dial,       "Dial an extension from the console"),
+	AST_CLI_DEFINE(cli_console_hangup,     "Hangup a call on the console"),
+	AST_CLI_DEFINE(cli_console_mute,       "Disable/Enable mic input"),
+	AST_CLI_DEFINE(cli_console_answer,     "Answer an incoming console call"),
+	AST_CLI_DEFINE(cli_console_sendtext,   "Send text to a connected party"),
+	AST_CLI_DEFINE(cli_console_flash,      "Send a flash to the connected party"),
 	AST_CLI_DEFINE(cli_console_autoanswer, "Turn autoanswer on or off"),
-	AST_CLI_DEFINE(cli_list_devices, "List available devices"),
+	AST_CLI_DEFINE(cli_list_devices,       "List available devices"),
 };
 
+/*!
+ * \brief Set default values for a pvt struct
+ *
+ * \note This function expects the pvt lock to be held.
+ */
 static void set_pvt_defaults(struct console_pvt *pvt, int reload)
 {
-	if (!reload)
+	if (!reload) {
+		/* This should be changed for multiple device support.  Right now,
+		 * there is no way to change the name of a device.  The default
+		 * input and output sound devices are the only ones supported. */
 		ast_string_field_set(pvt, name, "default");
+	}
 
 	ast_string_field_set(pvt, mohinterpret, "default");
 	ast_string_field_set(pvt, context, "default");
@@ -875,6 +940,11 @@
 	ast_string_field_set(pvt, cid_num, cid_num);
 }
 
+/*!
+ * \brief Store a configuration parameter in a pvt struct
+ *
+ * \note This function expects the pvt lock to be held.
+ */
 static void store_config_core(struct console_pvt *pvt, const char *var, const char *value)
 {
 	if (!ast_jb_read_conf(&global_jbconf, var, value))
@@ -912,7 +982,7 @@
 	/* default values */
 	memcpy(&global_jbconf, &default_jbconf, sizeof(global_jbconf));
 
-	ast_mutex_lock(&pvt->lock);
+	console_pvt_lock(pvt);
 
 	set_pvt_defaults(pvt, reload);
 
@@ -929,7 +999,7 @@
 	res = 0;
 
 return_unlock:
-	ast_mutex_unlock(&pvt->lock);
+	console_pvt_unlock(pvt);
 	return res;
 }
 
@@ -938,7 +1008,7 @@
 	if (ast_string_field_init(pvt, 32))
 		return -1;
 	
-	if (ast_mutex_init(&pvt->lock)) {
+	if (ast_mutex_init(&pvt->__lock)) {
 		ast_log(LOG_ERROR, "Failed to initialize mutex\n");
 		return -1;
 	}
@@ -950,7 +1020,7 @@
 {
 	ast_string_field_free_memory(pvt);
 	
-	ast_mutex_destroy(&pvt->lock);
+	ast_mutex_destroy(&pvt->__lock);
 }
 
 static int unload_module(void)
@@ -963,7 +1033,7 @@
 	Pa_Terminate();
 
 	ast_channel_unregister(&console_tech);
-	ast_cli_unregister_multiple(cli_console, sizeof(cli_console) / sizeof(cli_console[0]));
+	ast_cli_unregister_multiple(cli_console, ARRAY_LEN(cli_console));
 
 	destroy_pvt(pvt);
 
@@ -1015,7 +1085,7 @@
 	return load_config(1);
 }
 
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Generic Console Channel Driver",
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Console Channel Driver",
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,




More information about the asterisk-commits mailing list