Sat Apr 26 2014 22:02:01

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 /* 80 Frames, at 2 bytes each */

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, const 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, const char *linkedid)
static struct ast_framealsa_read (struct ast_channel *chan)
static struct ast_channelalsa_request (const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *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_mute (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_LOAD_ORDER , .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, .load_pri = AST_MODPRI_CHANNEL_DRIVER, }
static struct chan_alsa_pvt alsa
static struct ast_channel_tech alsa_tech
static ast_mutex_t alsalock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }
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 int mute = 0
static int noaudiocapture = 0
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 74 of file chan_alsa.c.

#define ALSA_OUTDEV   "default"

Definition at line 75 of file chan_alsa.c.

Definition at line 43 of file chan_alsa.c.

Definition at line 44 of file chan_alsa.c.

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

Definition at line 85 of file chan_alsa.c.

#define DEBUG   0

Definition at line 72 of file chan_alsa.c.

#define DESIRED_RATE   8000

Definition at line 76 of file chan_alsa.c.

Referenced by alsa_card_init().

#define FRAME_SIZE   160

Definition at line 79 of file chan_alsa.c.

Referenced by alsa_read().

#define MAX_BUFFER_SIZE   100

Definition at line 128 of file chan_alsa.c.

#define MIN_SWITCH_TIME   600

Definition at line 88 of file chan_alsa.c.

#define PERIOD_FRAMES   80 /* 80 Frames, at 2 bytes each */

Definition at line 80 of file chan_alsa.c.

Referenced by alsa_card_init().


Function Documentation

static void __reg_module ( void  ) [static]

Definition at line 1031 of file chan_alsa.c.

static void __unreg_module ( void  ) [static]

Definition at line 1031 of file chan_alsa.c.

static int alsa_answer ( struct ast_channel c) [static]

Definition at line 352 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);
   if (!noaudiocapture) {
      snd_pcm_prepare(alsa.icard);
      snd_pcm_start(alsa.icard);
   }
   ast_mutex_unlock(&alsalock);

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

Definition at line 316 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, ast_frame_subclass::integer, 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");
      if (mute) {
         ast_verbose( " << Muted >> \n" );
      }
      grab_owner();
      if (alsa.owner) {
         f.subclass.integer = 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.integer = AST_CONTROL_RINGING;
         ast_queue_frame(alsa.owner, &f);
         ast_channel_unlock(alsa.owner);
         ast_indicate(alsa.owner, AST_CONTROL_RINGING);
      }
   }
   if (!noaudiocapture) {
      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 164 of file chan_alsa.c.

References ast_alloca, 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 = ast_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 = ast_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 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 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 522 of file chan_alsa.c.

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

{
   struct chan_alsa_pvt *p = ast_channel_tech_pvt(newchan);

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

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

Definition at line 533 of file chan_alsa.c.

References alsalock, ast_channel_name(), AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HOLD, AST_CONTROL_INCOMPLETE, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_PVT_CAUSE_CODE, 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(), and LOG_WARNING.

{
   int res = 0;

   ast_mutex_lock(&alsalock);

   switch (cond) {
   case AST_CONTROL_BUSY:
   case AST_CONTROL_CONGESTION:
   case AST_CONTROL_RINGING:
   case AST_CONTROL_INCOMPLETE:
   case AST_CONTROL_PVT_CAUSE_CODE:
   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, ast_channel_name(chan));
      res = -1;
   }

   ast_mutex_unlock(&alsalock);

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

Definition at line 571 of file chan_alsa.c.

References ast_channel_alloc(), ast_channel_context_set(), ast_channel_exten_set(), ast_channel_name(), ast_channel_nativeformats(), ast_channel_readformat(), ast_channel_set_fd(), ast_channel_tech_pvt_set(), ast_channel_tech_set(), ast_channel_writeformat(), ast_format_cap_add(), ast_format_set(), AST_FORMAT_SLINEAR, ast_hangup(), ast_jb_configure(), ast_log(), ast_module_ref(), ast_pbx_start(), AST_STATE_DOWN, ast_strlen_zero(), chan_alsa_pvt::context, chan_alsa_pvt::exten, global_jbconf, LOG_WARNING, chan_alsa_pvt::owner, and ast_module_info::self.

Referenced by alsa_request(), and console_dial().

static struct ast_frame * alsa_read ( struct ast_channel chan) [static, read]

Definition at line 434 of file chan_alsa.c.

References alsa, alsalock, ast_format_set(), AST_FORMAT_SLINEAR, AST_FRAME_NULL, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), ast_mutex_lock, ast_mutex_unlock, AST_STATE_UP, ast_frame::data, ast_frame::datalen, ast_frame::delivery, f, ast_frame_subclass::format, FRAME_SIZE, ast_frame::frametype, chan_alsa_pvt::icard, ast_frame_subclass::integer, LOG_ERROR, ast_frame::mallocd, ast_frame::offset, ast_frame::ptr, ast_frame::samples, ast_frame::src, state, 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;

   ast_mutex_lock(&alsalock);
   f.frametype = AST_FRAME_NULL;
   f.subclass.integer = 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;

   if (noaudiocapture) {
      /* Return null frame to asterisk*/
      ast_mutex_unlock(&alsalock);
      return &f;
   }

   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));
   }

   /* Return NULL frame on error */
   if (r < 0) {
      ast_mutex_unlock(&alsalock);
      return &f;
   }

   /* Update positions */
   readpos += r;
   left -= r;

   if (readpos >= FRAME_SIZE) {
      /* A real frame */
      readpos = 0;
      left = FRAME_SIZE;
      if (ast_channel_state(chan) != AST_STATE_UP) {
         /* Don't transmit unless it's up */
         ast_mutex_unlock(&alsalock);
         return &f;
      }
      if (mute) {
         /* Don't transmit if muted */
         ast_mutex_unlock(&alsalock);
         return &f;
      }

      f.frametype = AST_FRAME_VOICE;
      ast_format_set(&f.subclass.format, AST_FORMAT_SLINEAR, 0);
      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,
struct ast_format_cap cap,
const struct ast_channel requestor,
const char *  data,
int *  cause 
) [static, read]

Definition at line 605 of file chan_alsa.c.

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

{
   struct ast_format tmpfmt;
   char buf[256];
   struct ast_channel *tmp = NULL;

   ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0);

   if (!(ast_format_cap_iscompatible(cap, &tmpfmt))) {
      ast_log(LOG_NOTICE, "Asked to get a channel of format '%s'\n", ast_getformatname_multiple(buf, sizeof(buf), cap));
      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, requestor ? ast_channel_linkedid(requestor) : NULL))) {
      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 300 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 382 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, ast_frame::ptr, and state.

{
   static char sizbuf[8000];
   static int sizpos = 0;
   int len = sizpos;
   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;
      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 632 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 684 of file chan_alsa.c.

References alsa, alsalock, ast_cli_args::argc, ast_channel_unlock, ast_cli(), AST_CONTROL_ANSWER, ast_mutex_lock, ast_mutex_unlock, ast_queue_control(), ast_verbose(), 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 {
      if (mute) {
         ast_verbose( " << Muted >> \n" );
      }
      hookstate = 1;
      grab_owner();
      if (alsa.owner) {
         ast_queue_control(alsa.owner, AST_CONTROL_ANSWER);
         ast_channel_unlock(alsa.owner);
      }
   }

   if (!noaudiocapture) {
      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 648 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 817 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, context, chan_alsa_pvt::context, exten, chan_alsa_pvt::exten, ast_cli_args::fd, ast_frame::frametype, chan_alsa_pvt::owner, and ast_cli_entry::usage.

{
   char tmp[256], *tmp2;
   char *mye, *myc;
   const 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.integer = *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, NULL);
      } 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 779 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_mute ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 882 of file chan_alsa.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.

{
   int toggle = 0;
   char *res = CLI_SUCCESS;

   switch (cmd) {
   case CLI_INIT:
      e->command = "console {mute|unmute} [toggle]";
      e->usage =
         "Usage: console {mute|unmute} [toggle]\n"
         "       Mute/unmute the microphone.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }


   if (a->argc > 3) {
      return CLI_SHOWUSAGE;
   }

   if (a->argc == 3) {
      if (strcasecmp(a->argv[2], "toggle"))
         return CLI_SHOWUSAGE;
      toggle = 1;
   }

   if (a->argc < 2) {
      return CLI_SHOWUSAGE;
   }

   if (!strcasecmp(a->argv[1], "mute")) {
      mute = toggle ? !mute : 1;
   } else if (!strcasecmp(a->argv[1], "unmute")) {
      mute = toggle ? !mute : 0;
   } else {
      return CLI_SHOWUSAGE;
   }

   ast_cli(a->fd, "Console mic is %s\n", mute ? "off" : "on");

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

Definition at line 730 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_TEXT, ast_mutex_lock, ast_mutex_unlock, ast_queue_control(), 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, grab_owner(), chan_alsa_pvt::owner, ast_frame::ptr, 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 };
      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);
         ast_queue_control(alsa.owner, AST_CONTROL_ANSWER);
         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 935 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_format_cap_add(), ast_format_cap_alloc(), ast_format_set(), AST_FORMAT_SLINEAR, 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, ast_channel_tech::capabilities, 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 };
   struct ast_format tmpfmt;

   if (!(alsa_tech.capabilities = ast_format_cap_alloc())) {
      return AST_MODULE_LOAD_DECLINE;
   }
   ast_format_cap_add(alsa_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 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, "mute")) {
         mute = ast_true(v->value);
      } else if (!strcasecmp(v->name, "noaudiocapture")) {
         noaudiocapture = 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 270 of file chan_alsa.c.

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

Referenced by load_module().

{
   if (!noaudiocapture) {
      alsa.icard = alsa_card_init(indevname, SND_PCM_STREAM_CAPTURE);
      if (!alsa.icard) {
         ast_log(LOG_ERROR, "Problem opening alsa capture device\n");
         return -1;
      }
   }

   alsa.ocard = alsa_card_init(outdevname, SND_PCM_STREAM_PLAYBACK);

   if (!alsa.ocard) {
      ast_log(LOG_ERROR, "Problem opening ALSA playback device\n");
      return -1;
   }

   return writedev;
}

Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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, .load_pri = AST_MODPRI_CHANNEL_DRIVER, } [static]

Definition at line 1031 of file chan_alsa.c.

struct ast_channel_tech alsa_tech [static]

Definition at line 149 of file chan_alsa.c.

Definition at line 1031 of file chan_alsa.c.

int autoanswer = 1 [static]

Definition at line 134 of file chan_alsa.c.

struct ast_cli_entry cli_alsa[] [static]

Definition at line 926 of file chan_alsa.c.

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

Definition at line 105 of file chan_alsa.c.

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

Definition at line 107 of file chan_alsa.c.

Referenced by __ast_goto_if_exists(), acf_isexten_exec(), acf_vm_info(), acf_vmcount_exec(), action_atxfer(), action_dialplan_exec(), action_extensionstate(), action_originate(), action_redirect(), add_peer_mailboxes(), advanced_options(), aji_mwi_cb(), append_mailbox_mapping(), apply_outgoing(), ast_async_goto(), ast_channel_by_exten_cb(), ast_compile_ael2(), ast_event_hash_mwi(), ast_get_enum(), ast_pbx_outgoing_exten(), build_peer(), check_access(), check_peer_ok(), complete_dialplan_add_include(), complete_dialplan_remove_extension(), complete_dialplan_remove_include(), conf_run(), config_parse_variables(), console_dial(), create_addr_from_peer(), disa_exec(), do_bridge_masquerade(), dundi_do_lookup(), dundi_do_precache(), dundi_do_query(), dundi_exec(), dundi_helper(), dundi_show_cache(), dundi_show_hints(), 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(), 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(), launch_ha_netscript(), leave_voicemail(), load_config(), load_module(), local_call(), local_devicestate(), log_exec(), lua_pbx_exec(), lua_register_hints(), 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_exec(), play_message(), process_ast_dsp(), pvalGotoSetTarget(), queue_mwi_event(), readexten_exec(), receive_message(), register_exten(), register_peer_exten(), reload_config(), retrydial_exec(), set_peer_defaults(), set_pvt_defaults(), sip_alloc(), sla_build_station(), sla_build_trunk(), socket_process_helper(), store_config_core(), txt_callback(), unistim_send_mwi_to_peer(), unregister_exten(), update_registry(), vm_box_exists(), vmsayname_exec(), wait_for_answer(), and xmpp_pubsub_mwi_cb().

struct ast_jb_conf default_jbconf [static]

Global jitterbuffer configuration - by default, jb is disabled

Note:
Values shown here match the defaults shown in alsa.conf.sample

Definition at line 63 of file chan_alsa.c.

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

Definition at line 109 of file chan_alsa.c.

Referenced by __analog_ss_thread(), __ast_goto_if_exists(), action_atxfer(), action_dialplan_exec(), action_extensionstate(), action_originate(), action_redirect(), analog_ss_thread(), apply_outgoing(), ast_async_goto(), ast_channel_by_exten_cb(), 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(), console_dial(), context_used(), copy_plain_file(), create_queue_member(), disa_exec(), expand_gosub_args(), 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(), local_call(), local_devicestate(), lua_pbx_exec(), lua_sort_extensions(), manager_show_dialplan(), mgcp_ss(), new_iax(), onedigit_goto(), orig_exten(), originate_exec(), osplookup_exec(), pbx_parseable_goto(), pickup_exec(), pp_each_extension_helper(), pri_ss_thread(), pvalGotoSetTarget(), raise_exception(), readexten_exec(), register_verify(), set_config(), set_pvt_defaults(), sip_new(), sip_request_call(), sla_build_station(), sla_station_destructor(), socket_process_helper(), store_config_core(), transmit_notify_with_mwi(), transmit_register(), update_scoreboard(), user_destructor(), vm_msg_snapshot_create(), and waitstream_core().

struct ast_jb_conf global_jbconf [static]

Definition at line 70 of file chan_alsa.c.

Referenced by alsa_new(), and load_module().

int hookstate = 0 [static]

Definition at line 112 of file chan_alsa.c.

char indevname[50] = ALSA_INDEV [static]

Definition at line 96 of file chan_alsa.c.

int noaudiocapture = 0 [static]

Definition at line 136 of file chan_alsa.c.

char outdevname[50] = ALSA_OUTDEV [static]

Definition at line 97 of file chan_alsa.c.

int readdev = -1 [static]

Definition at line 131 of file chan_alsa.c.

int silencesuppression = 0 [static]

Definition at line 99 of file chan_alsa.c.

int silencethreshold = 1000 [static]

Definition at line 100 of file chan_alsa.c.

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

Definition at line 104 of file chan_alsa.c.

int writedev = -1 [static]

Definition at line 132 of file chan_alsa.c.

Referenced by soundcard_init().