Fri Jul 15 2011 11:59:47

Asterisk developer's documentation


chan_alsa.c File Reference

ALSA sound card channel driver. More...

#include "asterisk.h"
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <alsa/asoundlib.h>
#include "asterisk/frame.h"
#include "asterisk/channel.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/endian.h"
#include "asterisk/stringfields.h"
#include "asterisk/abstract_jb.h"
#include "asterisk/musiconhold.h"
#include "asterisk/poll-compat.h"
Include dependency graph for chan_alsa.c:

Go to the source code of this file.

Data Structures

struct  chan_alsa_pvt

Defines

#define ALSA_INDEV   "default"
#define ALSA_OUTDEV   "default"
#define ALSA_PCM_NEW_HW_PARAMS_API
#define ALSA_PCM_NEW_SW_PARAMS_API
#define BUFFER_FMT   ((buffersize * 10) << 16) | (0x0006);
#define DEBUG   0
#define DESIRED_RATE   8000
#define FRAME_SIZE   160
#define MAX_BUFFER_SIZE   100
#define MIN_SWITCH_TIME   600
#define PERIOD_FRAMES   80

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int alsa_answer (struct ast_channel *c)
static int alsa_call (struct ast_channel *c, char *dest, int timeout)
static snd_pcm_t * alsa_card_init (char *dev, snd_pcm_stream_t stream)
static int alsa_digit (struct ast_channel *c, char digit, unsigned int duration)
static int alsa_fixup (struct ast_channel *oldchan, struct ast_channel *newchan)
static int alsa_hangup (struct ast_channel *c)
static int alsa_indicate (struct ast_channel *chan, int cond, const void *data, size_t datalen)
static struct ast_channelalsa_new (struct chan_alsa_pvt *p, int state)
static struct ast_framealsa_read (struct ast_channel *chan)
static struct ast_channelalsa_request (const char *type, int format, void *data, int *cause)
static int alsa_text (struct ast_channel *c, const char *text)
static int alsa_write (struct ast_channel *chan, struct ast_frame *f)
static char * autoanswer_complete (const char *line, const char *word, int pos, int state)
static char * console_answer (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * console_autoanswer (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * console_dial (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * console_hangup (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * console_sendtext (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void grab_owner (void)
static int load_module (void)
static int soundcard_init (void)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "ALSA Console Channel Driver" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, }
static struct chan_alsa_pvt alsa
static struct ast_channel_tech alsa_tech
static ast_mutex_t alsalock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP )
static struct ast_module_infoast_module_info = &__mod_info
static int autoanswer = 1
static struct ast_cli_entry cli_alsa []
static const char config [] = "alsa.conf"
static char context [AST_MAX_CONTEXT] = "default"
static struct ast_jb_conf default_jbconf
static char exten [AST_MAX_EXTENSION] = "s"
static snd_pcm_format_t format = SND_PCM_FORMAT_S16_BE
static struct ast_jb_conf global_jbconf
static int hookstate = 0
static char indevname [50] = ALSA_INDEV
static char language [MAX_LANGUAGE] = ""
static char mohinterpret [MAX_MUSICCLASS]
static char outdevname [50] = ALSA_OUTDEV
static int readdev = -1
static int silencesuppression = 0
static int silencethreshold = 1000
static const char tdesc [] = "ALSA Console Channel Driver"
static int writedev = -1

Detailed Description

ALSA sound card channel driver.

Author:
Matthew Fredrickson <creslin@digium.com>
See also
  • Config_alsa

Definition in file chan_alsa.c.


Define Documentation

#define ALSA_INDEV   "default"

Definition at line 72 of file chan_alsa.c.

#define ALSA_OUTDEV   "default"

Definition at line 73 of file chan_alsa.c.

#define ALSA_PCM_NEW_HW_PARAMS_API

Definition at line 42 of file chan_alsa.c.

#define ALSA_PCM_NEW_SW_PARAMS_API

Definition at line 43 of file chan_alsa.c.

#define BUFFER_FMT   ((buffersize * 10) << 16) | (0x0006);

Definition at line 83 of file chan_alsa.c.

#define DEBUG   0

Definition at line 70 of file chan_alsa.c.

#define DESIRED_RATE   8000

Definition at line 74 of file chan_alsa.c.

Referenced by alsa_card_init().

#define FRAME_SIZE   160

Definition at line 77 of file chan_alsa.c.

Referenced by alsa_read().

#define MAX_BUFFER_SIZE   100

Definition at line 126 of file chan_alsa.c.

#define MIN_SWITCH_TIME   600

Definition at line 86 of file chan_alsa.c.

#define PERIOD_FRAMES   80

Definition at line 78 of file chan_alsa.c.

Referenced by alsa_card_init().


Function Documentation

static void __reg_module ( void  ) [static]

Definition at line 931 of file chan_alsa.c.

static void __unreg_module ( void  ) [static]

Definition at line 931 of file chan_alsa.c.

static int alsa_answer ( struct ast_channel c) [static]

Definition at line 337 of file chan_alsa.c.

References alsa, alsalock, ast_mutex_lock(), ast_mutex_unlock(), ast_setstate(), AST_STATE_UP, ast_verbose(), and chan_alsa_pvt::icard.

{
   ast_mutex_lock(&alsalock);
   ast_verbose(" << Console call has been answered >> \n");
   ast_setstate(c, AST_STATE_UP);
   snd_pcm_prepare(alsa.icard);
   snd_pcm_start(alsa.icard);
   ast_mutex_unlock(&alsalock);

   return 0;
}
static int alsa_call ( struct ast_channel c,
char *  dest,
int  timeout 
) [static]

Definition at line 306 of file chan_alsa.c.

References alsa, alsalock, ast_channel_unlock, AST_CONTROL_ANSWER, AST_CONTROL_RINGING, AST_FRAME_CONTROL, ast_indicate(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_frame(), ast_verbose(), grab_owner(), chan_alsa_pvt::icard, chan_alsa_pvt::owner, and ast_frame::subclass.

{
   struct ast_frame f = { AST_FRAME_CONTROL };

   ast_mutex_lock(&alsalock);
   ast_verbose(" << Call placed to '%s' on console >> \n", dest);
   if (autoanswer) {
      ast_verbose(" << Auto-answered >> \n");
      grab_owner();
      if (alsa.owner) {
         f.subclass = AST_CONTROL_ANSWER;
         ast_queue_frame(alsa.owner, &f);
         ast_channel_unlock(alsa.owner);
      }
   } else {
      ast_verbose(" << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
      grab_owner();
      if (alsa.owner) {
         f.subclass = AST_CONTROL_RINGING;
         ast_queue_frame(alsa.owner, &f);
         ast_channel_unlock(alsa.owner);
         ast_indicate(alsa.owner, AST_CONTROL_RINGING);
      }
   }
   snd_pcm_prepare(alsa.icard);
   snd_pcm_start(alsa.icard);
   ast_mutex_unlock(&alsalock);

   return 0;
}
static snd_pcm_t* alsa_card_init ( char *  dev,
snd_pcm_stream_t  stream 
) [static]

Definition at line 161 of file chan_alsa.c.

References ast_debug, ast_log(), DESIRED_RATE, LOG_ERROR, LOG_WARNING, and PERIOD_FRAMES.

Referenced by soundcard_init().

{
   int err;
   int direction;
   snd_pcm_t *handle = NULL;
   snd_pcm_hw_params_t *hwparams = NULL;
   snd_pcm_sw_params_t *swparams = NULL;
   struct pollfd pfd;
   snd_pcm_uframes_t period_size = PERIOD_FRAMES * 4;
   snd_pcm_uframes_t buffer_size = 0;
   unsigned int rate = DESIRED_RATE;
   snd_pcm_uframes_t start_threshold, stop_threshold;

   err = snd_pcm_open(&handle, dev, stream, SND_PCM_NONBLOCK);
   if (err < 0) {
      ast_log(LOG_ERROR, "snd_pcm_open failed: %s\n", snd_strerror(err));
      return NULL;
   } else {
      ast_debug(1, "Opening device %s in %s mode\n", dev, (stream == SND_PCM_STREAM_CAPTURE) ? "read" : "write");
   }

   hwparams = alloca(snd_pcm_hw_params_sizeof());
   memset(hwparams, 0, snd_pcm_hw_params_sizeof());
   snd_pcm_hw_params_any(handle, hwparams);

   err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
   if (err < 0)
      ast_log(LOG_ERROR, "set_access failed: %s\n", snd_strerror(err));

   err = snd_pcm_hw_params_set_format(handle, hwparams, format);
   if (err < 0)
      ast_log(LOG_ERROR, "set_format failed: %s\n", snd_strerror(err));

   err = snd_pcm_hw_params_set_channels(handle, hwparams, 1);
   if (err < 0)
      ast_log(LOG_ERROR, "set_channels failed: %s\n", snd_strerror(err));

   direction = 0;
   err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rate, &direction);
   if (rate != DESIRED_RATE)
      ast_log(LOG_WARNING, "Rate not correct, requested %d, got %d\n", DESIRED_RATE, rate);

   direction = 0;
   err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_size, &direction);
   if (err < 0)
      ast_log(LOG_ERROR, "period_size(%ld frames) is bad: %s\n", period_size, snd_strerror(err));
   else {
      ast_debug(1, "Period size is %d\n", err);
   }

   buffer_size = 4096 * 2;    /* period_size * 16; */
   err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &buffer_size);
   if (err < 0)
      ast_log(LOG_WARNING, "Problem setting buffer size of %ld: %s\n", buffer_size, snd_strerror(err));
   else {
      ast_debug(1, "Buffer size is set to %d frames\n", err);
   }

   err = snd_pcm_hw_params(handle, hwparams);
   if (err < 0)
      ast_log(LOG_ERROR, "Couldn't set the new hw params: %s\n", snd_strerror(err));

   swparams = alloca(snd_pcm_sw_params_sizeof());
   memset(swparams, 0, snd_pcm_sw_params_sizeof());
   snd_pcm_sw_params_current(handle, swparams);

   if (stream == SND_PCM_STREAM_PLAYBACK)
      start_threshold = period_size;
   else
      start_threshold = 1;

   err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold);
   if (err < 0)
      ast_log(LOG_ERROR, "start threshold: %s\n", snd_strerror(err));

   if (stream == SND_PCM_STREAM_PLAYBACK)
      stop_threshold = buffer_size;
   else
      stop_threshold = buffer_size;

   err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold);
   if (err < 0)
      ast_log(LOG_ERROR, "stop threshold: %s\n", snd_strerror(err));

   err = snd_pcm_sw_params(handle, swparams);
   if (err < 0)
      ast_log(LOG_ERROR, "sw_params: %s\n", snd_strerror(err));

   err = snd_pcm_poll_descriptors_count(handle);
   if (err <= 0)
      ast_log(LOG_ERROR, "Unable to get a poll descriptors count, error is %s\n", snd_strerror(err));
   if (err != 1) {
      ast_debug(1, "Can't handle more than one device\n");
   }

   snd_pcm_poll_descriptors(handle, &pfd, err);
   ast_debug(1, "Acquired fd %d from the poll descriptor\n", pfd.fd);

   if (stream == SND_PCM_STREAM_CAPTURE)
      readdev = pfd.fd;
   else
      writedev = pfd.fd;

   return handle;
}
static int alsa_digit ( struct ast_channel c,
char  digit,
unsigned int  duration 
) [static]

Definition at line 280 of file chan_alsa.c.

References alsalock, ast_mutex_lock(), ast_mutex_unlock(), and ast_verbose().

{
   ast_mutex_lock(&alsalock);
   ast_verbose(" << Console Received digit %c of duration %u ms >> \n", 
      digit, duration);
   ast_mutex_unlock(&alsalock);

   return 0;
}
static int alsa_fixup ( struct ast_channel oldchan,
struct ast_channel newchan 
) [static]

Definition at line 489 of file chan_alsa.c.

References alsalock, ast_mutex_lock(), ast_mutex_unlock(), chan_alsa_pvt::owner, and ast_channel::tech_pvt.

{
   struct chan_alsa_pvt *p = newchan->tech_pvt;

   ast_mutex_lock(&alsalock);
   p->owner = newchan;
   ast_mutex_unlock(&alsalock);

   return 0;
}
static int alsa_hangup ( struct ast_channel c) [static]
static int alsa_indicate ( struct ast_channel chan,
int  cond,
const void *  data,
size_t  datalen 
) [static]

Definition at line 500 of file chan_alsa.c.

References alsalock, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HOLD, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_SRCUPDATE, AST_CONTROL_UNHOLD, AST_CONTROL_VIDUPDATE, ast_log(), ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_verbose(), LOG_WARNING, and ast_channel::name.

{
   int res = 0;

   ast_mutex_lock(&alsalock);

   switch (cond) {
   case AST_CONTROL_BUSY:
   case AST_CONTROL_CONGESTION:
   case AST_CONTROL_RINGING:
   case -1:
      res = -1;  /* Ask for inband indications */
      break;
   case AST_CONTROL_PROGRESS:
   case AST_CONTROL_PROCEEDING:
   case AST_CONTROL_VIDUPDATE:
   case AST_CONTROL_SRCUPDATE:
      break;
   case AST_CONTROL_HOLD:
      ast_verbose(" << Console Has Been Placed on Hold >> \n");
      ast_moh_start(chan, data, mohinterpret);
      break;
   case AST_CONTROL_UNHOLD:
      ast_verbose(" << Console Has Been Retrieved from Hold >> \n");
      ast_moh_stop(chan);
      break;
   default:
      ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, chan->name);
      res = -1;
   }

   ast_mutex_unlock(&alsalock);

   return res;
}
static struct ast_channel* alsa_new ( struct chan_alsa_pvt p,
int  state 
) [static, read]

Definition at line 536 of file chan_alsa.c.

References alsa_tech, ast_channel_alloc(), ast_channel_set_fd(), ast_copy_string(), AST_FORMAT_SLINEAR, ast_hangup(), ast_jb_configure(), ast_log(), ast_module_ref(), ast_pbx_start(), AST_STATE_DOWN, ast_string_field_set, ast_strlen_zero(), ast_channel::context, chan_alsa_pvt::context, ast_channel::exten, chan_alsa_pvt::exten, global_jbconf, LOG_WARNING, ast_channel::name, ast_channel::nativeformats, chan_alsa_pvt::owner, ast_channel::readformat, ast_module_info::self, ast_channel::tech, ast_channel::tech_pvt, and ast_channel::writeformat.

Referenced by alsa_request(), and console_dial().

{
   struct ast_channel *tmp = NULL;

   if (!(tmp = ast_channel_alloc(1, state, 0, 0, "", p->exten, p->context, 0, "ALSA/%s", indevname)))
      return NULL;

   tmp->tech = &alsa_tech;
   ast_channel_set_fd(tmp, 0, readdev);
   tmp->nativeformats = AST_FORMAT_SLINEAR;
   tmp->readformat = AST_FORMAT_SLINEAR;
   tmp->writeformat = AST_FORMAT_SLINEAR;
   tmp->tech_pvt = p;
   if (!ast_strlen_zero(p->context))
      ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
   if (!ast_strlen_zero(p->exten))
      ast_copy_string(tmp->exten, p->exten, sizeof(tmp->exten));
   if (!ast_strlen_zero(language))
      ast_string_field_set(tmp, language, language);
   p->owner = tmp;
   ast_module_ref(ast_module_info->self);
   ast_jb_configure(tmp, &global_jbconf);
   if (state != AST_STATE_DOWN) {
      if (ast_pbx_start(tmp)) {
         ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
         ast_hangup(tmp);
         tmp = NULL;
      }
   }

   return tmp;
}
static struct ast_frame * alsa_read ( struct ast_channel chan) [static, read]

Definition at line 417 of file chan_alsa.c.

References ast_channel::_state, alsa, alsalock, AST_FORMAT_SLINEAR, AST_FRAME_NULL, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_STATE_UP, buf, ast_frame::data, ast_frame::datalen, ast_frame::delivery, f, FRAME_SIZE, ast_frame::frametype, chan_alsa_pvt::icard, LOG_ERROR, ast_frame::mallocd, ast_frame::offset, ast_frame::ptr, ast_frame::samples, ast_frame::src, and ast_frame::subclass.

{
   static struct ast_frame f;
   static short __buf[FRAME_SIZE + AST_FRIENDLY_OFFSET / 2];
   short *buf;
   static int readpos = 0;
   static int left = FRAME_SIZE;
   snd_pcm_state_t state;
   int r = 0;
   int off = 0;

   ast_mutex_lock(&alsalock);
   f.frametype = AST_FRAME_NULL;
   f.subclass = 0;
   f.samples = 0;
   f.datalen = 0;
   f.data.ptr = NULL;
   f.offset = 0;
   f.src = "Console";
   f.mallocd = 0;
   f.delivery.tv_sec = 0;
   f.delivery.tv_usec = 0;

   state = snd_pcm_state(alsa.icard);
   if ((state != SND_PCM_STATE_PREPARED) && (state != SND_PCM_STATE_RUNNING)) {
      snd_pcm_prepare(alsa.icard);
   }

   buf = __buf + AST_FRIENDLY_OFFSET / 2;

   r = snd_pcm_readi(alsa.icard, buf + readpos, left);
   if (r == -EPIPE) {
#if DEBUG
      ast_log(LOG_ERROR, "XRUN read\n");
#endif
      snd_pcm_prepare(alsa.icard);
   } else if (r == -ESTRPIPE) {
      ast_log(LOG_ERROR, "-ESTRPIPE\n");
      snd_pcm_prepare(alsa.icard);
   } else if (r < 0) {
      ast_log(LOG_ERROR, "Read error: %s\n", snd_strerror(r));
   } else if (r >= 0) {
      off -= r;
   }
   /* Update positions */
   readpos += r;
   left -= r;

   if (readpos >= FRAME_SIZE) {
      /* A real frame */
      readpos = 0;
      left = FRAME_SIZE;
      if (chan->_state != AST_STATE_UP) {
         /* Don't transmit unless it's up */
         ast_mutex_unlock(&alsalock);
         return &f;
      }
      f.frametype = AST_FRAME_VOICE;
      f.subclass = AST_FORMAT_SLINEAR;
      f.samples = FRAME_SIZE;
      f.datalen = FRAME_SIZE * 2;
      f.data.ptr = buf;
      f.offset = AST_FRIENDLY_OFFSET;
      f.src = "Console";
      f.mallocd = 0;

   }
   ast_mutex_unlock(&alsalock);

   return &f;
}
static struct ast_channel * alsa_request ( const char *  type,
int  format,
void *  data,
int *  cause 
) [static, read]

Definition at line 569 of file chan_alsa.c.

References alsa, alsa_new(), alsalock, AST_CAUSE_BUSY, AST_FORMAT_SLINEAR, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_STATE_DOWN, LOG_NOTICE, LOG_WARNING, and chan_alsa_pvt::owner.

{
   int oldformat = fmt;
   struct ast_channel *tmp = NULL;

   if (!(fmt &= AST_FORMAT_SLINEAR)) {
      ast_log(LOG_NOTICE, "Asked to get a channel of format '%d'\n", oldformat);
      return NULL;
   }

   ast_mutex_lock(&alsalock);

   if (alsa.owner) {
      ast_log(LOG_NOTICE, "Already have a call on the ALSA channel\n");
      *cause = AST_CAUSE_BUSY;
   } else if (!(tmp = alsa_new(&alsa, AST_STATE_DOWN))) {
      ast_log(LOG_WARNING, "Unable to create new ALSA channel\n");
   }

   ast_mutex_unlock(&alsalock);

   return tmp;
}
static int alsa_text ( struct ast_channel c,
const char *  text 
) [static]

Definition at line 290 of file chan_alsa.c.

References alsalock, ast_mutex_lock(), ast_mutex_unlock(), and ast_verbose().

{
   ast_mutex_lock(&alsalock);
   ast_verbose(" << Console Received text %s >> \n", text);
   ast_mutex_unlock(&alsalock);

   return 0;
}
static int alsa_write ( struct ast_channel chan,
struct ast_frame f 
) [static]

Definition at line 363 of file chan_alsa.c.

References alsa, alsalock, ast_debug, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_frame::data, ast_frame::datalen, len(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, chan_alsa_pvt::ocard, and ast_frame::ptr.

{
   static char sizbuf[8000];
   static int sizpos = 0;
   int len = sizpos;
   int pos;
   int res = 0;
   /* size_t frames = 0; */
   snd_pcm_state_t state;

   ast_mutex_lock(&alsalock);

   /* We have to digest the frame in 160-byte portions */
   if (f->datalen > sizeof(sizbuf) - sizpos) {
      ast_log(LOG_WARNING, "Frame too large\n");
      res = -1;
   } else {
      memcpy(sizbuf + sizpos, f->data.ptr, f->datalen);
      len += f->datalen;
      pos = 0;
      state = snd_pcm_state(alsa.ocard);
      if (state == SND_PCM_STATE_XRUN)
         snd_pcm_prepare(alsa.ocard);
      while ((res = snd_pcm_writei(alsa.ocard, sizbuf, len / 2)) == -EAGAIN) {
         usleep(1);
      }
      if (res == -EPIPE) {
#if DEBUG
         ast_debug(1, "XRUN write\n");
#endif
         snd_pcm_prepare(alsa.ocard);
         while ((res = snd_pcm_writei(alsa.ocard, sizbuf, len / 2)) == -EAGAIN) {
            usleep(1);
         }
         if (res != len / 2) {
            ast_log(LOG_ERROR, "Write error: %s\n", snd_strerror(res));
            res = -1;
         } else if (res < 0) {
            ast_log(LOG_ERROR, "Write error %s\n", snd_strerror(res));
            res = -1;
         }
      } else {
         if (res == -ESTRPIPE)
            ast_log(LOG_ERROR, "You've got some big problems\n");
         else if (res < 0)
            ast_log(LOG_NOTICE, "Error %d on write\n", res);
      }
   }
   ast_mutex_unlock(&alsalock);

   return res >= 0 ? 0 : res;
}
static char* autoanswer_complete ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 593 of file chan_alsa.c.

References ast_strdup, ast_strlen_zero(), and MIN.

Referenced by console_autoanswer().

{
   switch (state) {
      case 0:
         if (!ast_strlen_zero(word) && !strncasecmp(word, "on", MIN(strlen(word), 2)))
            return ast_strdup("on");
      case 1:
         if (!ast_strlen_zero(word) && !strncasecmp(word, "off", MIN(strlen(word), 3)))
            return ast_strdup("off");
      default:
         return NULL;
   }

   return NULL;
}
static char* console_answer ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 645 of file chan_alsa.c.

References alsa, alsalock, ast_cli_args::argc, ast_channel_unlock, ast_cli(), AST_CONTROL_ANSWER, AST_FRAME_CONTROL, ast_mutex_lock(), ast_mutex_unlock(), ast_queue_frame(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, grab_owner(), chan_alsa_pvt::icard, chan_alsa_pvt::owner, and ast_cli_entry::usage.

{
   char *res = CLI_SUCCESS;

   switch (cmd) {
   case CLI_INIT:
      e->command = "console answer";
      e->usage =
         "Usage: console answer\n"
         "       Answers an incoming call on the console (ALSA) channel.\n";

      return NULL;
   case CLI_GENERATE:
      return NULL; 
   }

   if (a->argc != 2)
      return CLI_SHOWUSAGE;

   ast_mutex_lock(&alsalock);

   if (!alsa.owner) {
      ast_cli(a->fd, "No one is calling us\n");
      res = CLI_FAILURE;
   } else {
      hookstate = 1;
      grab_owner();
      if (alsa.owner) {
         struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };

         ast_queue_frame(alsa.owner, &f);
         ast_channel_unlock(alsa.owner);
      }
   }

   snd_pcm_prepare(alsa.icard);
   snd_pcm_start(alsa.icard);

   ast_mutex_unlock(&alsalock);

   return res;
}
static char* console_autoanswer ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 609 of file chan_alsa.c.

References alsalock, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), autoanswer_complete(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

{
   char *res = CLI_SUCCESS;

   switch (cmd) {
   case CLI_INIT:
      e->command = "console autoanswer";
      e->usage =
         "Usage: console autoanswer [on|off]\n"
         "       Enables or disables autoanswer feature.  If used without\n"
         "       argument, displays the current on/off status of autoanswer.\n"
         "       The default value of autoanswer is in 'alsa.conf'.\n";
      return NULL;
   case CLI_GENERATE:
      return autoanswer_complete(a->line, a->word, a->pos, a->n);
   }

   if ((a->argc != 2) && (a->argc != 3))
      return CLI_SHOWUSAGE;

   ast_mutex_lock(&alsalock);
   if (a->argc == 2) {
      ast_cli(a->fd, "Auto answer is %s.\n", autoanswer ? "on" : "off");
   } else {
      if (!strcasecmp(a->argv[2], "on"))
         autoanswer = -1;
      else if (!strcasecmp(a->argv[2], "off"))
         autoanswer = 0;
      else
         res = CLI_SHOWUSAGE;
   }
   ast_mutex_unlock(&alsalock);

   return res;
}
static char* console_dial ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 779 of file chan_alsa.c.

References alsa, alsa_new(), alsalock, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_copy_string(), ast_exists_extension(), AST_FRAME_DTMF, ast_mutex_lock(), ast_mutex_unlock(), ast_queue_frame(), AST_STATE_RINGING, ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, chan_alsa_pvt::context, context, chan_alsa_pvt::exten, exten, ast_cli_args::fd, ast_frame::frametype, chan_alsa_pvt::owner, strsep(), and ast_cli_entry::usage.

{
   char tmp[256], *tmp2;
   char *mye, *myc;
   char *d;
   char *res = CLI_SUCCESS;

   switch (cmd) {
   case CLI_INIT:
      e->command = "console dial";
      e->usage =
         "Usage: console dial [extension[@context]]\n"
         "       Dials a given extension (and context if specified)\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if ((a->argc != 2) && (a->argc != 3))
      return CLI_SHOWUSAGE;

   ast_mutex_lock(&alsalock);

   if (alsa.owner) {
      if (a->argc == 3) {
         if (alsa.owner) {
            for (d = a->argv[2]; *d; d++) {
               struct ast_frame f = { .frametype = AST_FRAME_DTMF, .subclass = *d };

               ast_queue_frame(alsa.owner, &f);
            }
         }
      } else {
         ast_cli(a->fd, "You're already in a call.  You can use this only to dial digits until you hangup\n");
         res = CLI_FAILURE;
      }
   } else {
      mye = exten;
      myc = context;
      if (a->argc == 3) {
         char *stringp = NULL;

         ast_copy_string(tmp, a->argv[2], sizeof(tmp));
         stringp = tmp;
         strsep(&stringp, "@");
         tmp2 = strsep(&stringp, "@");
         if (!ast_strlen_zero(tmp))
            mye = tmp;
         if (!ast_strlen_zero(tmp2))
            myc = tmp2;
      }
      if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
         ast_copy_string(alsa.exten, mye, sizeof(alsa.exten));
         ast_copy_string(alsa.context, myc, sizeof(alsa.context));
         hookstate = 1;
         alsa_new(&alsa, AST_STATE_RINGING);
      } else
         ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
   }

   ast_mutex_unlock(&alsalock);

   return res;
}
static char* console_hangup ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 741 of file chan_alsa.c.

References alsa, alsalock, ast_cli_args::argc, AST_CAUSE_NORMAL_CLEARING, ast_channel_unlock, ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_hangup_with_cause(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, grab_owner(), chan_alsa_pvt::owner, and ast_cli_entry::usage.

{
   char *res = CLI_SUCCESS;

   switch (cmd) {
   case CLI_INIT:
      e->command = "console hangup";
      e->usage =
         "Usage: console hangup\n"
         "       Hangs up any call currently placed on the console.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL; 
   }
 

   if (a->argc != 2)
      return CLI_SHOWUSAGE;

   ast_mutex_lock(&alsalock);

   if (!alsa.owner && !hookstate) {
      ast_cli(a->fd, "No call to hangup\n");
      res = CLI_FAILURE;
   } else {
      hookstate = 0;
      grab_owner();
      if (alsa.owner) {
         ast_queue_hangup_with_cause(alsa.owner, AST_CAUSE_NORMAL_CLEARING);
         ast_channel_unlock(alsa.owner);
      }
   }

   ast_mutex_unlock(&alsalock);

   return res;
}
static char* console_sendtext ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 688 of file chan_alsa.c.

References alsa, alsalock, ast_cli_args::argc, ast_cli_args::argv, ast_channel_unlock, ast_cli(), AST_CONTROL_ANSWER, AST_FRAME_CONTROL, AST_FRAME_TEXT, ast_mutex_lock(), ast_mutex_unlock(), ast_queue_frame(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_frame::data, ast_frame::datalen, ast_cli_args::fd, ast_frame::frametype, grab_owner(), chan_alsa_pvt::owner, ast_frame::ptr, ast_frame::subclass, and ast_cli_entry::usage.

{
   int tmparg = 3;
   char *res = CLI_SUCCESS;

   switch (cmd) {
   case 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;
   case CLI_GENERATE:
      return NULL; 
   }

   if (a->argc < 3)
      return CLI_SHOWUSAGE;

   ast_mutex_lock(&alsalock);

   if (!alsa.owner) {
      ast_cli(a->fd, "No channel active\n");
      res = CLI_FAILURE;
   } else {
      struct ast_frame f = { AST_FRAME_TEXT, 0 };
      char text2send[256] = "";

      while (tmparg < a->argc) {
         strncat(text2send, a->argv[tmparg++], sizeof(text2send) - strlen(text2send) - 1);
         strncat(text2send, " ", sizeof(text2send) - strlen(text2send) - 1);
      }

      text2send[strlen(text2send) - 1] = '\n';
      f.data.ptr = text2send;
      f.datalen = strlen(text2send) + 1;
      grab_owner();
      if (alsa.owner) {
         ast_queue_frame(alsa.owner, &f);
         f.frametype = AST_FRAME_CONTROL;
         f.subclass = AST_CONTROL_ANSWER;
         f.data.ptr = NULL;
         f.datalen = 0;
         ast_queue_frame(alsa.owner, &f);
         ast_channel_unlock(alsa.owner);
      }
   }

   ast_mutex_unlock(&alsalock);

   return res;
}
static void grab_owner ( void  ) [static]
static int load_module ( void  ) [static]

Definition at line 852 of file chan_alsa.c.

References ARRAY_LEN, ast_channel_register(), ast_cli_register_multiple(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_jb_read_conf(), ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_true(), ast_variable_browse(), ast_verb, CONFIG_STATUS_FILEINVALID, global_jbconf, LOG_ERROR, ast_variable::name, ast_variable::next, soundcard_init(), and ast_variable::value.

{
   struct ast_config *cfg;
   struct ast_variable *v;
   struct ast_flags config_flags = { 0 };

   /* Copy the default jb config over global_jbconf */
   memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));

   strcpy(mohinterpret, "default");

   if (!(cfg = ast_config_load(config, config_flags))) {
      ast_log(LOG_ERROR, "Unable to read ALSA configuration file %s.  Aborting.\n", config);
      return AST_MODULE_LOAD_DECLINE;
   } else if (cfg == CONFIG_STATUS_FILEINVALID) {
      ast_log(LOG_ERROR, "%s is in an invalid format.  Aborting.\n", config);
      return AST_MODULE_LOAD_DECLINE;
   }

   v = ast_variable_browse(cfg, "general");
   for (; v; v = v->next) {
      /* handle jb conf */
      if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
            continue;
      
      if (!strcasecmp(v->name, "autoanswer"))
         autoanswer = ast_true(v->value);
      else if (!strcasecmp(v->name, "silencesuppression"))
         silencesuppression = ast_true(v->value);
      else if (!strcasecmp(v->name, "silencethreshold"))
         silencethreshold = atoi(v->value);
      else if (!strcasecmp(v->name, "context"))
         ast_copy_string(context, v->value, sizeof(context));
      else if (!strcasecmp(v->name, "language"))
         ast_copy_string(language, v->value, sizeof(language));
      else if (!strcasecmp(v->name, "extension"))
         ast_copy_string(exten, v->value, sizeof(exten));
      else if (!strcasecmp(v->name, "input_device"))
         ast_copy_string(indevname, v->value, sizeof(indevname));
      else if (!strcasecmp(v->name, "output_device"))
         ast_copy_string(outdevname, v->value, sizeof(outdevname));
      else if (!strcasecmp(v->name, "mohinterpret"))
         ast_copy_string(mohinterpret, v->value, sizeof(mohinterpret));
   }
   ast_config_destroy(cfg);

   if (soundcard_init() < 0) {
      ast_verb(2, "No sound card detected -- console channel will be unavailable\n");
      ast_verb(2, "Turn off ALSA support by adding 'noload=chan_alsa.so' in /etc/asterisk/modules.conf\n");
      return AST_MODULE_LOAD_DECLINE;
   }

   if (ast_channel_register(&alsa_tech)) {
      ast_log(LOG_ERROR, "Unable to register channel class 'Console'\n");
      return AST_MODULE_LOAD_FAILURE;
   }

   ast_cli_register_multiple(cli_alsa, ARRAY_LEN(cli_alsa));

   return AST_MODULE_LOAD_SUCCESS;
}
static int soundcard_init ( void  ) [static]

Definition at line 267 of file chan_alsa.c.

References alsa, alsa_card_init(), ast_log(), chan_alsa_pvt::icard, LOG_ERROR, chan_alsa_pvt::ocard, and readdev.

Referenced by load_module().

{
   alsa.icard = alsa_card_init(indevname, SND_PCM_STREAM_CAPTURE);
   alsa.ocard = alsa_card_init(outdevname, SND_PCM_STREAM_PLAYBACK);

   if (!alsa.icard || !alsa.ocard) {
      ast_log(LOG_ERROR, "Problem opening ALSA I/O devices\n");
      return -1;
   }

   return readdev;
}

Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "ALSA Console Channel Driver" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } [static]

Definition at line 931 of file chan_alsa.c.

struct ast_channel_tech alsa_tech [static]

Definition at line 145 of file chan_alsa.c.

Referenced by alsa_new().

Definition at line 931 of file chan_alsa.c.

int autoanswer = 1 [static]

Definition at line 132 of file chan_alsa.c.

struct ast_cli_entry cli_alsa[] [static]

Definition at line 844 of file chan_alsa.c.

const char config[] = "alsa.conf" [static]

Definition at line 103 of file chan_alsa.c.

char context[AST_MAX_CONTEXT] = "default" [static]

Definition at line 105 of file chan_alsa.c.

Referenced by __ast_goto_if_exists(), acf_isexten_exec(), acf_vmcount_exec(), action_atxfer(), action_extensionstate(), action_originate(), action_redirect(), add_peer_mailboxes(), advanced_options(), append_mailbox_mapping(), apply_outgoing(), ast_compile_ael2(), ast_event_hash_mwi(), ast_get_enum(), ast_pbx_outgoing_exten(), build_device(), build_peer(), check_access(), check_peer_ok(), complete_dialplan_add_include(), complete_dialplan_remove_extension(), complete_dialplan_remove_include(), config_parse_variables(), console_dial(), create_addr_from_peer(), disa_exec(), dundi_do_lookup(), dundi_do_precache(), dundi_do_query(), dundi_exec(), dundi_helper(), ebl_callback(), enum_callback(), extenspy_exec(), extstate_read(), feature_attended_transfer(), feature_blind_transfer(), find_label_in_current_db(), get_also_info(), get_cid_name(), get_destination(), gtalk_load_config(), handle_cli_dialplan_remove_extension(), handle_request_bye(), handle_request_invite(), handle_request_options(), handle_request_refer(), has_voicemail(), hint_read(), iax2_call(), iax2_transfer(), inboxcount2(), isexten_function_read(), jingle_load_config(), leave_voicemail(), load_config(), log_exec(), lua_pbx_exec(), lua_register_switches(), lua_sort_extensions(), manager_show_dialplan(), metermaidstate(), mkintf(), notify_message(), orig_exten(), pbx_builtin_background(), pbx_find_extension(), pbx_parseable_goto(), pickup_by_exten(), pickup_exec(), play_message(), process_ast_dsp(), pvalGotoSetTarget(), queue_mwi_event(), readexten_exec(), register_exten(), register_peer_exten(), reload_config(), retrydial_exec(), rpt_exec(), set_peer_defaults(), set_pvt_defaults(), sip_alloc(), sla_build_station(), sla_build_trunk(), socket_process(), store_config_core(), txt_callback(), unistim_send_mwi_to_peer(), unregister_exten(), update_registry(), vm_box_exists(), and wait_for_answer().

struct ast_jb_conf default_jbconf [static]

Global jitterbuffer configuration - by default, jb is disabled

Definition at line 61 of file chan_alsa.c.

char exten[AST_MAX_EXTENSION] = "s" [static]

Definition at line 107 of file chan_alsa.c.

Referenced by __ast_goto_if_exists(), action_atxfer(), action_extensionstate(), action_originate(), action_redirect(), apply_outgoing(), ast_compile_ael2(), ast_context_remove_extension_callerid2(), ast_ivr_menu_run_internal(), ast_merge_contexts_and_delete(), ast_pbx_outgoing_exten(), ast_walk_extension_priorities(), build_extension(), check_access(), check_user_full(), complete_dialplan_remove_extension(), complete_dpreply(), config_parse_variables(), console_dial(), copy_plain_file(), destroy_station(), disa_exec(), extenspy_exec(), extstate_read(), feature_attended_transfer(), feature_blind_transfer(), find_label_in_current_context(), find_label_in_current_db(), gen_prios(), get_cid_name(), get_destination(), get_rdnis(), gtalk_alloc(), handle_cli_dialplan_add_extension(), handle_cli_dialplan_remove_extension(), handle_debug_dialplan(), handle_request_invite(), handle_show_dialplan(), hint_read(), initreqprep(), isexten_function_read(), leave_voicemail(), linkprio(), lua_pbx_exec(), lua_sort_extensions(), manager_show_dialplan(), mgcp_ss(), new_iax(), onedigit_goto(), orig_exten(), originate_exec(), osplookup_exec(), pbx_builtin_raise_exception(), pbx_parseable_goto(), pickup_by_exten(), pickup_exec(), pp_each_extension_exec(), pvalGotoSetTarget(), readexten_exec(), register_verify(), rpt_exec(), set_config(), set_pvt_defaults(), sla_build_station(), socket_process(), ss_thread(), store_config_core(), transmit_notify_with_mwi(), transmit_register(), update_scoreboard(), user_destructor(), and waitstream_core().

snd_pcm_format_t format = SND_PCM_FORMAT_S16_BE [static]

Definition at line 91 of file chan_alsa.c.

struct ast_jb_conf global_jbconf [static]

Definition at line 68 of file chan_alsa.c.

Referenced by alsa_new(), and load_module().

int hookstate = 0 [static]

Definition at line 110 of file chan_alsa.c.

char indevname[50] = ALSA_INDEV [static]

Definition at line 94 of file chan_alsa.c.

char outdevname[50] = ALSA_OUTDEV [static]

Definition at line 95 of file chan_alsa.c.

int readdev = -1 [static]

Definition at line 129 of file chan_alsa.c.

Referenced by soundcard_init().

int silencesuppression = 0 [static]

Definition at line 97 of file chan_alsa.c.

int silencethreshold = 1000 [static]

Definition at line 98 of file chan_alsa.c.

const char tdesc[] = "ALSA Console Channel Driver" [static]

Definition at line 102 of file chan_alsa.c.

int writedev = -1 [static]

Definition at line 130 of file chan_alsa.c.