[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