Tue Mar 2 17:32:46 2010

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 = "a9c98e5d177805051735cb5b0b16b0a0" , .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 71 of file chan_alsa.c.

#define ALSA_OUTDEV   "default"

Definition at line 72 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 82 of file chan_alsa.c.

#define DEBUG   0

Definition at line 69 of file chan_alsa.c.

#define DESIRED_RATE   8000

Definition at line 73 of file chan_alsa.c.

Referenced by alsa_card_init().

#define FRAME_SIZE   160

Definition at line 76 of file chan_alsa.c.

Referenced by alsa_read(), oss_read(), and soundcard_writeframe().

#define MAX_BUFFER_SIZE   100

Definition at line 125 of file chan_alsa.c.

#define MIN_SWITCH_TIME   600

Definition at line 85 of file chan_alsa.c.

#define PERIOD_FRAMES   80

Definition at line 77 of file chan_alsa.c.

Referenced by alsa_card_init().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 927 of file chan_alsa.c.

static void __unreg_module ( void   )  [static]

Definition at line 927 of file chan_alsa.c.

static int alsa_answer ( struct ast_channel c  )  [static]

Definition at line 336 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.

00337 {
00338    ast_mutex_lock(&alsalock);
00339    ast_verbose(" << Console call has been answered >> \n");
00340    ast_setstate(c, AST_STATE_UP);
00341    snd_pcm_prepare(alsa.icard);
00342    snd_pcm_start(alsa.icard);
00343    ast_mutex_unlock(&alsalock);
00344 
00345    return 0;
00346 }

static int alsa_call ( struct ast_channel c,
char *  dest,
int  timeout 
) [static]

Definition at line 305 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.

00306 {
00307    struct ast_frame f = { AST_FRAME_CONTROL };
00308 
00309    ast_mutex_lock(&alsalock);
00310    ast_verbose(" << Call placed to '%s' on console >> \n", dest);
00311    if (autoanswer) {
00312       ast_verbose(" << Auto-answered >> \n");
00313       grab_owner();
00314       if (alsa.owner) {
00315          f.subclass = AST_CONTROL_ANSWER;
00316          ast_queue_frame(alsa.owner, &f);
00317          ast_channel_unlock(alsa.owner);
00318       }
00319    } else {
00320       ast_verbose(" << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
00321       grab_owner();
00322       if (alsa.owner) {
00323          f.subclass = AST_CONTROL_RINGING;
00324          ast_queue_frame(alsa.owner, &f);
00325          ast_channel_unlock(alsa.owner);
00326          ast_indicate(alsa.owner, AST_CONTROL_RINGING);
00327       }
00328    }
00329    snd_pcm_prepare(alsa.icard);
00330    snd_pcm_start(alsa.icard);
00331    ast_mutex_unlock(&alsalock);
00332 
00333    return 0;
00334 }

static snd_pcm_t* alsa_card_init ( char *  dev,
snd_pcm_stream_t  stream 
) [static]

Definition at line 160 of file chan_alsa.c.

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

Referenced by soundcard_init().

00161 {
00162    int err;
00163    int direction;
00164    snd_pcm_t *handle = NULL;
00165    snd_pcm_hw_params_t *hwparams = NULL;
00166    snd_pcm_sw_params_t *swparams = NULL;
00167    struct pollfd pfd;
00168    snd_pcm_uframes_t period_size = PERIOD_FRAMES * 4;
00169    snd_pcm_uframes_t buffer_size = 0;
00170    unsigned int rate = DESIRED_RATE;
00171    snd_pcm_uframes_t start_threshold, stop_threshold;
00172 
00173    err = snd_pcm_open(&handle, dev, stream, SND_PCM_NONBLOCK);
00174    if (err < 0) {
00175       ast_log(LOG_ERROR, "snd_pcm_open failed: %s\n", snd_strerror(err));
00176       return NULL;
00177    } else {
00178       ast_debug(1, "Opening device %s in %s mode\n", dev, (stream == SND_PCM_STREAM_CAPTURE) ? "read" : "write");
00179    }
00180 
00181    hwparams = alloca(snd_pcm_hw_params_sizeof());
00182    memset(hwparams, 0, snd_pcm_hw_params_sizeof());
00183    snd_pcm_hw_params_any(handle, hwparams);
00184 
00185    err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
00186    if (err < 0)
00187       ast_log(LOG_ERROR, "set_access failed: %s\n", snd_strerror(err));
00188 
00189    err = snd_pcm_hw_params_set_format(handle, hwparams, format);
00190    if (err < 0)
00191       ast_log(LOG_ERROR, "set_format failed: %s\n", snd_strerror(err));
00192 
00193    err = snd_pcm_hw_params_set_channels(handle, hwparams, 1);
00194    if (err < 0)
00195       ast_log(LOG_ERROR, "set_channels failed: %s\n", snd_strerror(err));
00196 
00197    direction = 0;
00198    err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rate, &direction);
00199    if (rate != DESIRED_RATE)
00200       ast_log(LOG_WARNING, "Rate not correct, requested %d, got %d\n", DESIRED_RATE, rate);
00201 
00202    direction = 0;
00203    err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_size, &direction);
00204    if (err < 0)
00205       ast_log(LOG_ERROR, "period_size(%ld frames) is bad: %s\n", period_size, snd_strerror(err));
00206    else {
00207       ast_debug(1, "Period size is %d\n", err);
00208    }
00209 
00210    buffer_size = 4096 * 2;    /* period_size * 16; */
00211    err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &buffer_size);
00212    if (err < 0)
00213       ast_log(LOG_WARNING, "Problem setting buffer size of %ld: %s\n", buffer_size, snd_strerror(err));
00214    else {
00215       ast_debug(1, "Buffer size is set to %d frames\n", err);
00216    }
00217 
00218    err = snd_pcm_hw_params(handle, hwparams);
00219    if (err < 0)
00220       ast_log(LOG_ERROR, "Couldn't set the new hw params: %s\n", snd_strerror(err));
00221 
00222    swparams = alloca(snd_pcm_sw_params_sizeof());
00223    memset(swparams, 0, snd_pcm_sw_params_sizeof());
00224    snd_pcm_sw_params_current(handle, swparams);
00225 
00226    if (stream == SND_PCM_STREAM_PLAYBACK)
00227       start_threshold = period_size;
00228    else
00229       start_threshold = 1;
00230 
00231    err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold);
00232    if (err < 0)
00233       ast_log(LOG_ERROR, "start threshold: %s\n", snd_strerror(err));
00234 
00235    if (stream == SND_PCM_STREAM_PLAYBACK)
00236       stop_threshold = buffer_size;
00237    else
00238       stop_threshold = buffer_size;
00239 
00240    err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold);
00241    if (err < 0)
00242       ast_log(LOG_ERROR, "stop threshold: %s\n", snd_strerror(err));
00243 
00244    err = snd_pcm_sw_params(handle, swparams);
00245    if (err < 0)
00246       ast_log(LOG_ERROR, "sw_params: %s\n", snd_strerror(err));
00247 
00248    err = snd_pcm_poll_descriptors_count(handle);
00249    if (err <= 0)
00250       ast_log(LOG_ERROR, "Unable to get a poll descriptors count, error is %s\n", snd_strerror(err));
00251    if (err != 1) {
00252       ast_debug(1, "Can't handle more than one device\n");
00253    }
00254 
00255    snd_pcm_poll_descriptors(handle, &pfd, err);
00256    ast_debug(1, "Acquired fd %d from the poll descriptor\n", pfd.fd);
00257 
00258    if (stream == SND_PCM_STREAM_CAPTURE)
00259       readdev = pfd.fd;
00260    else
00261       writedev = pfd.fd;
00262 
00263    return handle;
00264 }

static int alsa_digit ( struct ast_channel c,
char  digit,
unsigned int  duration 
) [static]

Definition at line 279 of file chan_alsa.c.

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

00280 {
00281    ast_mutex_lock(&alsalock);
00282    ast_verbose(" << Console Received digit %c of duration %u ms >> \n", 
00283       digit, duration);
00284    ast_mutex_unlock(&alsalock);
00285 
00286    return 0;
00287 }

static int alsa_fixup ( struct ast_channel oldchan,
struct ast_channel newchan 
) [static]

Definition at line 488 of file chan_alsa.c.

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

00489 {
00490    struct chan_alsa_pvt *p = newchan->tech_pvt;
00491 
00492    ast_mutex_lock(&alsalock);
00493    p->owner = newchan;
00494    ast_mutex_unlock(&alsalock);
00495 
00496    return 0;
00497 }

static int alsa_hangup ( struct ast_channel c  )  [static]

Definition at line 348 of file chan_alsa.c.

References alsa, alsalock, ast_module_unref(), ast_mutex_lock(), ast_mutex_unlock(), ast_verbose, chan_alsa_pvt::icard, chan_alsa_pvt::owner, and ast_channel::tech_pvt.

00349 {
00350    ast_mutex_lock(&alsalock);
00351    c->tech_pvt = NULL;
00352    alsa.owner = NULL;
00353    ast_verbose(" << Hangup on console >> \n");
00354    ast_module_unref(ast_module_info->self);
00355    hookstate = 0;
00356    snd_pcm_drop(alsa.icard);
00357    ast_mutex_unlock(&alsalock);
00358 
00359    return 0;
00360 }

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

Definition at line 499 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, and LOG_WARNING.

00500 {
00501    int res = 0;
00502 
00503    ast_mutex_lock(&alsalock);
00504 
00505    switch (cond) {
00506    case AST_CONTROL_BUSY:
00507    case AST_CONTROL_CONGESTION:
00508    case AST_CONTROL_RINGING:
00509    case -1:
00510       res = -1;  /* Ask for inband indications */
00511       break;
00512    case AST_CONTROL_PROGRESS:
00513    case AST_CONTROL_PROCEEDING:
00514    case AST_CONTROL_VIDUPDATE:
00515    case AST_CONTROL_SRCUPDATE:
00516       break;
00517    case AST_CONTROL_HOLD:
00518       ast_verbose(" << Console Has Been Placed on Hold >> \n");
00519       ast_moh_start(chan, data, mohinterpret);
00520       break;
00521    case AST_CONTROL_UNHOLD:
00522       ast_verbose(" << Console Has Been Retrieved from Hold >> \n");
00523       ast_moh_stop(chan);
00524       break;
00525    default:
00526       ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, chan->name);
00527       res = -1;
00528    }
00529 
00530    ast_mutex_unlock(&alsalock);
00531 
00532    return res;
00533 }

static struct ast_channel* alsa_new ( struct chan_alsa_pvt p,
int  state 
) [static, read]

Definition at line 535 of file chan_alsa.c.

References 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::nativeformats, chan_alsa_pvt::owner, ast_channel::readformat, ast_channel::tech, ast_channel::tech_pvt, and ast_channel::writeformat.

Referenced by alsa_request(), and console_dial().

00536 {
00537    struct ast_channel *tmp = NULL;
00538 
00539    if (!(tmp = ast_channel_alloc(1, state, 0, 0, "", p->exten, p->context, 0, "ALSA/%s", indevname)))
00540       return NULL;
00541 
00542    tmp->tech = &alsa_tech;
00543    ast_channel_set_fd(tmp, 0, readdev);
00544    tmp->nativeformats = AST_FORMAT_SLINEAR;
00545    tmp->readformat = AST_FORMAT_SLINEAR;
00546    tmp->writeformat = AST_FORMAT_SLINEAR;
00547    tmp->tech_pvt = p;
00548    if (!ast_strlen_zero(p->context))
00549       ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
00550    if (!ast_strlen_zero(p->exten))
00551       ast_copy_string(tmp->exten, p->exten, sizeof(tmp->exten));
00552    if (!ast_strlen_zero(language))
00553       ast_string_field_set(tmp, language, language);
00554    p->owner = tmp;
00555    ast_module_ref(ast_module_info->self);
00556    ast_jb_configure(tmp, &global_jbconf);
00557    if (state != AST_STATE_DOWN) {
00558       if (ast_pbx_start(tmp)) {
00559          ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
00560          ast_hangup(tmp);
00561          tmp = NULL;
00562       }
00563    }
00564 
00565    return tmp;
00566 }

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

Definition at line 416 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, 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.

00417 {
00418    static struct ast_frame f;
00419    static short __buf[FRAME_SIZE + AST_FRIENDLY_OFFSET / 2];
00420    short *buf;
00421    static int readpos = 0;
00422    static int left = FRAME_SIZE;
00423    snd_pcm_state_t state;
00424    int r = 0;
00425    int off = 0;
00426 
00427    ast_mutex_lock(&alsalock);
00428    f.frametype = AST_FRAME_NULL;
00429    f.subclass = 0;
00430    f.samples = 0;
00431    f.datalen = 0;
00432    f.data.ptr = NULL;
00433    f.offset = 0;
00434    f.src = "Console";
00435    f.mallocd = 0;
00436    f.delivery.tv_sec = 0;
00437    f.delivery.tv_usec = 0;
00438 
00439    state = snd_pcm_state(alsa.icard);
00440    if ((state != SND_PCM_STATE_PREPARED) && (state != SND_PCM_STATE_RUNNING)) {
00441       snd_pcm_prepare(alsa.icard);
00442    }
00443 
00444    buf = __buf + AST_FRIENDLY_OFFSET / 2;
00445 
00446    r = snd_pcm_readi(alsa.icard, buf + readpos, left);
00447    if (r == -EPIPE) {
00448 #if DEBUG
00449       ast_log(LOG_ERROR, "XRUN read\n");
00450 #endif
00451       snd_pcm_prepare(alsa.icard);
00452    } else if (r == -ESTRPIPE) {
00453       ast_log(LOG_ERROR, "-ESTRPIPE\n");
00454       snd_pcm_prepare(alsa.icard);
00455    } else if (r < 0) {
00456       ast_log(LOG_ERROR, "Read error: %s\n", snd_strerror(r));
00457    } else if (r >= 0) {
00458       off -= r;
00459    }
00460    /* Update positions */
00461    readpos += r;
00462    left -= r;
00463 
00464    if (readpos >= FRAME_SIZE) {
00465       /* A real frame */
00466       readpos = 0;
00467       left = FRAME_SIZE;
00468       if (chan->_state != AST_STATE_UP) {
00469          /* Don't transmit unless it's up */
00470          ast_mutex_unlock(&alsalock);
00471          return &f;
00472       }
00473       f.frametype = AST_FRAME_VOICE;
00474       f.subclass = AST_FORMAT_SLINEAR;
00475       f.samples = FRAME_SIZE;
00476       f.datalen = FRAME_SIZE * 2;
00477       f.data.ptr = buf;
00478       f.offset = AST_FRIENDLY_OFFSET;
00479       f.src = "Console";
00480       f.mallocd = 0;
00481 
00482    }
00483    ast_mutex_unlock(&alsalock);
00484 
00485    return &f;
00486 }

static struct ast_channel * alsa_request ( const char *  type,
int  format,
void *  data,
int *  cause 
) [static, read]

Definition at line 568 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.

00569 {
00570    int oldformat = fmt;
00571    struct ast_channel *tmp = NULL;
00572 
00573    if (!(fmt &= AST_FORMAT_SLINEAR)) {
00574       ast_log(LOG_NOTICE, "Asked to get a channel of format '%d'\n", oldformat);
00575       return NULL;
00576    }
00577 
00578    ast_mutex_lock(&alsalock);
00579 
00580    if (alsa.owner) {
00581       ast_log(LOG_NOTICE, "Already have a call on the ALSA channel\n");
00582       *cause = AST_CAUSE_BUSY;
00583    } else if (!(tmp = alsa_new(&alsa, AST_STATE_DOWN))) {
00584       ast_log(LOG_WARNING, "Unable to create new ALSA channel\n");
00585    }
00586 
00587    ast_mutex_unlock(&alsalock);
00588 
00589    return tmp;
00590 }

static int alsa_text ( struct ast_channel c,
const char *  text 
) [static]

Definition at line 289 of file chan_alsa.c.

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

00290 {
00291    ast_mutex_lock(&alsalock);
00292    ast_verbose(" << Console Received text %s >> \n", text);
00293    ast_mutex_unlock(&alsalock);
00294 
00295    return 0;
00296 }

static int alsa_write ( struct ast_channel chan,
struct ast_frame f 
) [static]

Definition at line 362 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.

00363 {
00364    static char sizbuf[8000];
00365    static int sizpos = 0;
00366    int len = sizpos;
00367    int pos;
00368    int res = 0;
00369    /* size_t frames = 0; */
00370    snd_pcm_state_t state;
00371 
00372    ast_mutex_lock(&alsalock);
00373 
00374    /* We have to digest the frame in 160-byte portions */
00375    if (f->datalen > sizeof(sizbuf) - sizpos) {
00376       ast_log(LOG_WARNING, "Frame too large\n");
00377       res = -1;
00378    } else {
00379       memcpy(sizbuf + sizpos, f->data.ptr, f->datalen);
00380       len += f->datalen;
00381       pos = 0;
00382       state = snd_pcm_state(alsa.ocard);
00383       if (state == SND_PCM_STATE_XRUN)
00384          snd_pcm_prepare(alsa.ocard);
00385       while ((res = snd_pcm_writei(alsa.ocard, sizbuf, len / 2)) == -EAGAIN) {
00386          usleep(1);
00387       }
00388       if (res == -EPIPE) {
00389 #if DEBUG
00390          ast_debug(1, "XRUN write\n");
00391 #endif
00392          snd_pcm_prepare(alsa.ocard);
00393          while ((res = snd_pcm_writei(alsa.ocard, sizbuf, len / 2)) == -EAGAIN) {
00394             usleep(1);
00395          }
00396          if (res != len / 2) {
00397             ast_log(LOG_ERROR, "Write error: %s\n", snd_strerror(res));
00398             res = -1;
00399          } else if (res < 0) {
00400             ast_log(LOG_ERROR, "Write error %s\n", snd_strerror(res));
00401             res = -1;
00402          }
00403       } else {
00404          if (res == -ESTRPIPE)
00405             ast_log(LOG_ERROR, "You've got some big problems\n");
00406          else if (res < 0)
00407             ast_log(LOG_NOTICE, "Error %d on write\n", res);
00408       }
00409    }
00410    ast_mutex_unlock(&alsalock);
00411 
00412    return res >= 0 ? 0 : res;
00413 }

static char* autoanswer_complete ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 592 of file chan_alsa.c.

References ast_strdup, ast_strlen_zero(), and MIN.

Referenced by console_autoanswer().

00593 {
00594    switch (state) {
00595       case 0:
00596          if (!ast_strlen_zero(word) && !strncasecmp(word, "on", MIN(strlen(word), 2)))
00597             return ast_strdup("on");
00598       case 1:
00599          if (!ast_strlen_zero(word) && !strncasecmp(word, "off", MIN(strlen(word), 3)))
00600             return ast_strdup("off");
00601       default:
00602          return NULL;
00603    }
00604 
00605    return NULL;
00606 }

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

Definition at line 644 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.

00645 {
00646    char *res = CLI_SUCCESS;
00647 
00648    switch (cmd) {
00649    case CLI_INIT:
00650       e->command = "console answer";
00651       e->usage =
00652          "Usage: console answer\n"
00653          "       Answers an incoming call on the console (ALSA) channel.\n";
00654 
00655       return NULL;
00656    case CLI_GENERATE:
00657       return NULL; 
00658    }
00659 
00660    if (a->argc != 2)
00661       return CLI_SHOWUSAGE;
00662 
00663    ast_mutex_lock(&alsalock);
00664 
00665    if (!alsa.owner) {
00666       ast_cli(a->fd, "No one is calling us\n");
00667       res = CLI_FAILURE;
00668    } else {
00669       hookstate = 1;
00670       grab_owner();
00671       if (alsa.owner) {
00672          struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00673 
00674          ast_queue_frame(alsa.owner, &f);
00675          ast_channel_unlock(alsa.owner);
00676       }
00677    }
00678 
00679    snd_pcm_prepare(alsa.icard);
00680    snd_pcm_start(alsa.icard);
00681 
00682    ast_mutex_unlock(&alsalock);
00683 
00684    return res;
00685 }

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

Definition at line 608 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.

00609 {
00610    char *res = CLI_SUCCESS;
00611 
00612    switch (cmd) {
00613    case CLI_INIT:
00614       e->command = "console autoanswer";
00615       e->usage =
00616          "Usage: console autoanswer [on|off]\n"
00617          "       Enables or disables autoanswer feature.  If used without\n"
00618          "       argument, displays the current on/off status of autoanswer.\n"
00619          "       The default value of autoanswer is in 'alsa.conf'.\n";
00620       return NULL;
00621    case CLI_GENERATE:
00622       return autoanswer_complete(a->line, a->word, a->pos, a->n);
00623    }
00624 
00625    if ((a->argc != 2) && (a->argc != 3))
00626       return CLI_SHOWUSAGE;
00627 
00628    ast_mutex_lock(&alsalock);
00629    if (a->argc == 2) {
00630       ast_cli(a->fd, "Auto answer is %s.\n", autoanswer ? "on" : "off");
00631    } else {
00632       if (!strcasecmp(a->argv[2], "on"))
00633          autoanswer = -1;
00634       else if (!strcasecmp(a->argv[2], "off"))
00635          autoanswer = 0;
00636       else
00637          res = CLI_SHOWUSAGE;
00638    }
00639    ast_mutex_unlock(&alsalock);
00640 
00641    return res;
00642 }

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

Definition at line 778 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, chan_alsa_pvt::exten, ast_cli_args::fd, ast_frame::frametype, chan_alsa_pvt::owner, strsep(), and ast_cli_entry::usage.

00779 {
00780    char tmp[256], *tmp2;
00781    char *mye, *myc;
00782    char *d;
00783    char *res = CLI_SUCCESS;
00784 
00785    switch (cmd) {
00786    case CLI_INIT:
00787       e->command = "console dial";
00788       e->usage =
00789          "Usage: console dial [extension[@context]]\n"
00790          "       Dials a given extension (and context if specified)\n";
00791       return NULL;
00792    case CLI_GENERATE:
00793       return NULL;
00794    }
00795 
00796    if ((a->argc != 2) && (a->argc != 3))
00797       return CLI_SHOWUSAGE;
00798 
00799    ast_mutex_lock(&alsalock);
00800 
00801    if (alsa.owner) {
00802       if (a->argc == 3) {
00803          if (alsa.owner) {
00804             for (d = a->argv[2]; *d; d++) {
00805                struct ast_frame f = { .frametype = AST_FRAME_DTMF, .subclass = *d };
00806 
00807                ast_queue_frame(alsa.owner, &f);
00808             }
00809          }
00810       } else {
00811          ast_cli(a->fd, "You're already in a call.  You can use this only to dial digits until you hangup\n");
00812          res = CLI_FAILURE;
00813       }
00814    } else {
00815       mye = exten;
00816       myc = context;
00817       if (a->argc == 3) {
00818          char *stringp = NULL;
00819 
00820          ast_copy_string(tmp, a->argv[2], sizeof(tmp));
00821          stringp = tmp;
00822          strsep(&stringp, "@");
00823          tmp2 = strsep(&stringp, "@");
00824          if (!ast_strlen_zero(tmp))
00825             mye = tmp;
00826          if (!ast_strlen_zero(tmp2))
00827             myc = tmp2;
00828       }
00829       if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
00830          ast_copy_string(alsa.exten, mye, sizeof(alsa.exten));
00831          ast_copy_string(alsa.context, myc, sizeof(alsa.context));
00832          hookstate = 1;
00833          alsa_new(&alsa, AST_STATE_RINGING);
00834       } else
00835          ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
00836    }
00837 
00838    ast_mutex_unlock(&alsalock);
00839 
00840    return res;
00841 }

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

Definition at line 740 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.

00741 {
00742    char *res = CLI_SUCCESS;
00743 
00744    switch (cmd) {
00745    case CLI_INIT:
00746       e->command = "console hangup";
00747       e->usage =
00748          "Usage: console hangup\n"
00749          "       Hangs up any call currently placed on the console.\n";
00750       return NULL;
00751    case CLI_GENERATE:
00752       return NULL; 
00753    }
00754  
00755 
00756    if (a->argc != 2)
00757       return CLI_SHOWUSAGE;
00758 
00759    ast_mutex_lock(&alsalock);
00760 
00761    if (!alsa.owner && !hookstate) {
00762       ast_cli(a->fd, "No call to hangup\n");
00763       res = CLI_FAILURE;
00764    } else {
00765       hookstate = 0;
00766       grab_owner();
00767       if (alsa.owner) {
00768          ast_queue_hangup_with_cause(alsa.owner, AST_CAUSE_NORMAL_CLEARING);
00769          ast_channel_unlock(alsa.owner);
00770       }
00771    }
00772 
00773    ast_mutex_unlock(&alsalock);
00774 
00775    return res;
00776 }

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

Definition at line 687 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.

00688 {
00689    int tmparg = 3;
00690    char *res = CLI_SUCCESS;
00691 
00692    switch (cmd) {
00693    case CLI_INIT:
00694       e->command = "console send text";
00695       e->usage =
00696          "Usage: console send text <message>\n"
00697          "       Sends a text message for display on the remote terminal.\n";
00698       return NULL;
00699    case CLI_GENERATE:
00700       return NULL; 
00701    }
00702 
00703    if (a->argc < 3)
00704       return CLI_SHOWUSAGE;
00705 
00706    ast_mutex_lock(&alsalock);
00707 
00708    if (!alsa.owner) {
00709       ast_cli(a->fd, "No channel active\n");
00710       res = CLI_FAILURE;
00711    } else {
00712       struct ast_frame f = { AST_FRAME_TEXT, 0 };
00713       char text2send[256] = "";
00714 
00715       while (tmparg < a->argc) {
00716          strncat(text2send, a->argv[tmparg++], sizeof(text2send) - strlen(text2send) - 1);
00717          strncat(text2send, " ", sizeof(text2send) - strlen(text2send) - 1);
00718       }
00719 
00720       text2send[strlen(text2send) - 1] = '\n';
00721       f.data.ptr = text2send;
00722       f.datalen = strlen(text2send) + 1;
00723       grab_owner();
00724       if (alsa.owner) {
00725          ast_queue_frame(alsa.owner, &f);
00726          f.frametype = AST_FRAME_CONTROL;
00727          f.subclass = AST_CONTROL_ANSWER;
00728          f.data.ptr = NULL;
00729          f.datalen = 0;
00730          ast_queue_frame(alsa.owner, &f);
00731          ast_channel_unlock(alsa.owner);
00732       }
00733    }
00734 
00735    ast_mutex_unlock(&alsalock);
00736 
00737    return res;
00738 }

static void grab_owner ( void   )  [static]

Definition at line 298 of file chan_alsa.c.

References alsa, alsalock, ast_channel_trylock, DEADLOCK_AVOIDANCE, and chan_alsa_pvt::owner.

Referenced by alsa_call(), console_answer(), console_hangup(), and console_sendtext().

00299 {
00300    while (alsa.owner && ast_channel_trylock(alsa.owner)) {
00301       DEADLOCK_AVOIDANCE(&alsalock);
00302    }
00303 }

static int load_module ( void   )  [static]

Definition at line 851 of file chan_alsa.c.

References 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, global_jbconf, LOG_ERROR, ast_variable::name, ast_variable::next, soundcard_init(), and ast_variable::value.

00852 {
00853    struct ast_config *cfg;
00854    struct ast_variable *v;
00855    struct ast_flags config_flags = { 0 };
00856 
00857    /* Copy the default jb config over global_jbconf */
00858    memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
00859 
00860    strcpy(mohinterpret, "default");
00861 
00862    if (!(cfg = ast_config_load(config, config_flags))) {
00863       ast_log(LOG_ERROR, "Unable to read ALSA configuration file %s.  Aborting.\n", config);
00864       return AST_MODULE_LOAD_DECLINE;
00865    }
00866 
00867    v = ast_variable_browse(cfg, "general");
00868    for (; v; v = v->next) {
00869       /* handle jb conf */
00870       if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
00871             continue;
00872       
00873       if (!strcasecmp(v->name, "autoanswer"))
00874          autoanswer = ast_true(v->value);
00875       else if (!strcasecmp(v->name, "silencesuppression"))
00876          silencesuppression = ast_true(v->value);
00877       else if (!strcasecmp(v->name, "silencethreshold"))
00878          silencethreshold = atoi(v->value);
00879       else if (!strcasecmp(v->name, "context"))
00880          ast_copy_string(context, v->value, sizeof(context));
00881       else if (!strcasecmp(v->name, "language"))
00882          ast_copy_string(language, v->value, sizeof(language));
00883       else if (!strcasecmp(v->name, "extension"))
00884          ast_copy_string(exten, v->value, sizeof(exten));
00885       else if (!strcasecmp(v->name, "input_device"))
00886          ast_copy_string(indevname, v->value, sizeof(indevname));
00887       else if (!strcasecmp(v->name, "output_device"))
00888          ast_copy_string(outdevname, v->value, sizeof(outdevname));
00889       else if (!strcasecmp(v->name, "mohinterpret"))
00890          ast_copy_string(mohinterpret, v->value, sizeof(mohinterpret));
00891    }
00892    ast_config_destroy(cfg);
00893 
00894    if (soundcard_init() < 0) {
00895       ast_verb(2, "No sound card detected -- console channel will be unavailable\n");
00896       ast_verb(2, "Turn off ALSA support by adding 'noload=chan_alsa.so' in /etc/asterisk/modules.conf\n");
00897       return AST_MODULE_LOAD_DECLINE;
00898    }
00899 
00900    if (ast_channel_register(&alsa_tech)) {
00901       ast_log(LOG_ERROR, "Unable to register channel class 'Console'\n");
00902       return AST_MODULE_LOAD_FAILURE;
00903    }
00904 
00905    ast_cli_register_multiple(cli_alsa, sizeof(cli_alsa) / sizeof(struct ast_cli_entry));
00906 
00907    return AST_MODULE_LOAD_SUCCESS;
00908 }

static int soundcard_init ( void   )  [static]

Definition at line 266 of file chan_alsa.c.

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

Referenced by load_module().

00267 {
00268    alsa.icard = alsa_card_init(indevname, SND_PCM_STREAM_CAPTURE);
00269    alsa.ocard = alsa_card_init(outdevname, SND_PCM_STREAM_PLAYBACK);
00270 
00271    if (!alsa.icard || !alsa.ocard) {
00272       ast_log(LOG_ERROR, "Problem opening ALSA I/O devices\n");
00273       return -1;
00274    }
00275 
00276    return readdev;
00277 }

static int unload_module ( void   )  [static]

Definition at line 910 of file chan_alsa.c.

References alsa, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, chan_alsa_pvt::icard, chan_alsa_pvt::ocard, and chan_alsa_pvt::owner.

00911 {
00912    ast_channel_unregister(&alsa_tech);
00913    ast_cli_unregister_multiple(cli_alsa, sizeof(cli_alsa) / sizeof(struct ast_cli_entry));
00914 
00915    if (alsa.icard)
00916       snd_pcm_close(alsa.icard);
00917    if (alsa.ocard)
00918       snd_pcm_close(alsa.ocard);
00919    if (alsa.owner)
00920       ast_softhangup(alsa.owner, AST_SOFTHANGUP_APPUNLOAD);
00921    if (alsa.owner)
00922       return -1;
00923 
00924    return 0;
00925 }


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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, } [static]

Definition at line 927 of file chan_alsa.c.

struct chan_alsa_pvt alsa [static]
struct ast_channel_tech alsa_tech [static]

Definition at line 144 of file chan_alsa.c.

ast_mutex_t alsalock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ) [static]

Definition at line 927 of file chan_alsa.c.

int autoanswer = 1 [static]

Definition at line 131 of file chan_alsa.c.

struct ast_cli_entry cli_alsa[] [static]

Definition at line 843 of file chan_alsa.c.

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

Definition at line 102 of file chan_alsa.c.

char context[AST_MAX_CONTEXT] = "default" [static]
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]
snd_pcm_format_t format = SND_PCM_FORMAT_S16_BE [static]
struct ast_jb_conf global_jbconf [static]

Definition at line 67 of file chan_alsa.c.

Referenced by alsa_new(), and load_module().

int hookstate = 0 [static]

Definition at line 109 of file chan_alsa.c.

char indevname[50] = ALSA_INDEV [static]

Definition at line 93 of file chan_alsa.c.

char language[MAX_LANGUAGE] = "" [static]
char mohinterpret[MAX_MUSICCLASS] [static]
char outdevname[50] = ALSA_OUTDEV [static]

Definition at line 94 of file chan_alsa.c.

int readdev = -1 [static]

Definition at line 128 of file chan_alsa.c.

int silencesuppression = 0 [static]

Definition at line 96 of file chan_alsa.c.

int silencethreshold = 1000 [static]

Definition at line 97 of file chan_alsa.c.

Referenced by ast_record_review(), and setup_privacy_args().

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

Definition at line 101 of file chan_alsa.c.

int writedev = -1 [static]

Definition at line 129 of file chan_alsa.c.


Generated on 2 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1