Thu May 14 15:12:48 2009

Asterisk developer's documentation


chan_alsa.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * By Matthew Fredrickson <creslin@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file 
00020  * \brief ALSA sound card channel driver 
00021  *
00022  * \author Matthew Fredrickson <creslin@digium.com>
00023  *
00024  * \par See also
00025  * \arg Config_alsa
00026  *
00027  * \ingroup channel_drivers
00028  */
00029 
00030 /*** MODULEINFO
00031    <depend>asound</depend>
00032  ***/
00033 
00034 #include "asterisk.h"
00035 
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 167095 $")
00037 
00038 #include <unistd.h>
00039 #include <fcntl.h>
00040 #include <errno.h>
00041 #include <sys/ioctl.h>
00042 #include <sys/time.h>
00043 #include <string.h>
00044 #include <stdlib.h>
00045 #include <stdio.h>
00046 
00047 #define ALSA_PCM_NEW_HW_PARAMS_API
00048 #define ALSA_PCM_NEW_SW_PARAMS_API
00049 #include <alsa/asoundlib.h>
00050 
00051 #include "asterisk/frame.h"
00052 #include "asterisk/logger.h"
00053 #include "asterisk/channel.h"
00054 #include "asterisk/module.h"
00055 #include "asterisk/options.h"
00056 #include "asterisk/pbx.h"
00057 #include "asterisk/config.h"
00058 #include "asterisk/cli.h"
00059 #include "asterisk/utils.h"
00060 #include "asterisk/causes.h"
00061 #include "asterisk/endian.h"
00062 #include "asterisk/stringfields.h"
00063 #include "asterisk/abstract_jb.h"
00064 #include "asterisk/musiconhold.h"
00065 
00066 #include "busy_tone.h"
00067 #include "ring_tone.h"
00068 #include "ring10.h"
00069 #include "answer.h"
00070 
00071 #ifdef ALSA_MONITOR
00072 #include "alsa-monitor.h"
00073 #endif
00074 
00075 /*! Global jitterbuffer configuration - by default, jb is disabled */
00076 static struct ast_jb_conf default_jbconf = {
00077    .flags = 0,
00078    .max_size = -1,
00079    .resync_threshold = -1,
00080    .impl = ""
00081 };
00082 static struct ast_jb_conf global_jbconf;
00083 
00084 #define DEBUG 0
00085 /* Which device to use */
00086 #define ALSA_INDEV "default"
00087 #define ALSA_OUTDEV "default"
00088 #define DESIRED_RATE 8000
00089 
00090 /* Lets use 160 sample frames, just like GSM.  */
00091 #define FRAME_SIZE 160
00092 #define PERIOD_FRAMES 80      /* 80 Frames, at 2 bytes each */
00093 
00094 /* When you set the frame size, you have to come up with
00095    the right buffer format as well. */
00096 /* 5 64-byte frames = one frame */
00097 #define BUFFER_FMT ((buffersize * 10) << 16) | (0x0006);
00098 
00099 /* Don't switch between read/write modes faster than every 300 ms */
00100 #define MIN_SWITCH_TIME 600
00101 
00102 #if __BYTE_ORDER == __LITTLE_ENDIAN
00103 static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
00104 #else
00105 static snd_pcm_format_t format = SND_PCM_FORMAT_S16_BE;
00106 #endif
00107 
00108 static char indevname[50] = ALSA_INDEV;
00109 static char outdevname[50] = ALSA_OUTDEV;
00110 
00111 #if 0
00112 static struct timeval lasttime;
00113 #endif
00114 
00115 static int silencesuppression = 0;
00116 static int silencethreshold = 1000;
00117 
00118 AST_MUTEX_DEFINE_STATIC(alsalock);
00119 
00120 static const char tdesc[] = "ALSA Console Channel Driver";
00121 static const char config[] = "alsa.conf";
00122 
00123 static char context[AST_MAX_CONTEXT] = "default";
00124 static char language[MAX_LANGUAGE] = "";
00125 static char exten[AST_MAX_EXTENSION] = "s";
00126 static char mohinterpret[MAX_MUSICCLASS];
00127 
00128 static int hookstate = 0;
00129 
00130 static short silence[FRAME_SIZE] = { 0, };
00131 
00132 struct sound {
00133    int ind;
00134    short *data;
00135    int datalen;
00136    int samplen;
00137    int silencelen;
00138    int repeat;
00139 };
00140 
00141 static struct sound sounds[] = {
00142    {AST_CONTROL_RINGING, ringtone, sizeof(ringtone) / 2, 16000, 32000, 1},
00143    {AST_CONTROL_BUSY, busy, sizeof(busy) / 2, 4000, 4000, 1},
00144    {AST_CONTROL_CONGESTION, busy, sizeof(busy) / 2, 2000, 2000, 1},
00145    {AST_CONTROL_RING, ring10, sizeof(ring10) / 2, 16000, 32000, 1},
00146    {AST_CONTROL_ANSWER, answer, sizeof(answer) / 2, 2200, 0, 0},
00147 };
00148 
00149 /* Sound command pipe */
00150 static int sndcmd[2];
00151 
00152 static struct chan_alsa_pvt {
00153    /* We only have one ALSA structure -- near sighted perhaps, but it
00154       keeps this driver as simple as possible -- as it should be. */
00155    struct ast_channel *owner;
00156    char exten[AST_MAX_EXTENSION];
00157    char context[AST_MAX_CONTEXT];
00158 #if 0
00159    snd_pcm_t *card;
00160 #endif
00161    snd_pcm_t *icard, *ocard;
00162 
00163 } alsa;
00164 
00165 /* Number of buffers...  Each is FRAMESIZE/8 ms long.  For example
00166    with 160 sample frames, and a buffer size of 3, we have a 60ms buffer, 
00167    usually plenty. */
00168 
00169 pthread_t sthread;
00170 
00171 #define MAX_BUFFER_SIZE 100
00172 
00173 /* File descriptors for sound device */
00174 static int readdev = -1;
00175 static int writedev = -1;
00176 
00177 static int autoanswer = 1;
00178 
00179 static int cursound = -1;
00180 static int sampsent = 0;
00181 static int silencelen = 0;
00182 static int offset = 0;
00183 static int nosound = 0;
00184 
00185 /* ZZ */
00186 static struct ast_channel *alsa_request(const char *type, int format, void *data, int *cause);
00187 static int alsa_digit(struct ast_channel *c, char digit, unsigned int duration);
00188 static int alsa_text(struct ast_channel *c, const char *text);
00189 static int alsa_hangup(struct ast_channel *c);
00190 static int alsa_answer(struct ast_channel *c);
00191 static struct ast_frame *alsa_read(struct ast_channel *chan);
00192 static int alsa_call(struct ast_channel *c, char *dest, int timeout);
00193 static int alsa_write(struct ast_channel *chan, struct ast_frame *f);
00194 static int alsa_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen);
00195 static int alsa_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00196 
00197 static const struct ast_channel_tech alsa_tech = {
00198    .type = "Console",
00199    .description = tdesc,
00200    .capabilities = AST_FORMAT_SLINEAR,
00201    .requester = alsa_request,
00202    .send_digit_end = alsa_digit,
00203    .send_text = alsa_text,
00204    .hangup = alsa_hangup,
00205    .answer = alsa_answer,
00206    .read = alsa_read,
00207    .call = alsa_call,
00208    .write = alsa_write,
00209    .indicate = alsa_indicate,
00210    .fixup = alsa_fixup,
00211 };
00212 
00213 static int send_sound(void)
00214 {
00215    short myframe[FRAME_SIZE];
00216    int total = FRAME_SIZE;
00217    short *frame = NULL;
00218    int amt = 0, res, myoff;
00219    snd_pcm_state_t state;
00220 
00221    if (cursound == -1)
00222       return 0;
00223    
00224    res = total;
00225    if (sampsent < sounds[cursound].samplen) {
00226       myoff = 0;
00227       while (total) {
00228          amt = total;
00229          if (amt > (sounds[cursound].datalen - offset))
00230             amt = sounds[cursound].datalen - offset;
00231          memcpy(myframe + myoff, sounds[cursound].data + offset, amt * 2);
00232          total -= amt;
00233          offset += amt;
00234          sampsent += amt;
00235          myoff += amt;
00236          if (offset >= sounds[cursound].datalen)
00237             offset = 0;
00238       }
00239       /* Set it up for silence */
00240       if (sampsent >= sounds[cursound].samplen)
00241          silencelen = sounds[cursound].silencelen;
00242       frame = myframe;
00243    } else {
00244       if (silencelen > 0) {
00245          frame = silence;
00246          silencelen -= res;
00247       } else {
00248          if (sounds[cursound].repeat) {
00249             /* Start over */
00250             sampsent = 0;
00251             offset = 0;
00252          } else {
00253             cursound = -1;
00254             nosound = 0;
00255          }
00256          return 0;
00257       }
00258    }
00259    
00260    if (res == 0 || !frame)
00261       return 0;
00262 
00263 #ifdef ALSA_MONITOR
00264    alsa_monitor_write((char *) frame, res * 2);
00265 #endif
00266    state = snd_pcm_state(alsa.ocard);
00267    if (state == SND_PCM_STATE_XRUN)
00268       snd_pcm_prepare(alsa.ocard);
00269    while ((res = snd_pcm_writei(alsa.ocard, frame, res)) == -EAGAIN) {
00270       usleep(1);
00271    }
00272    if (res > 0)
00273       return 0;
00274    return 0;
00275 }
00276 
00277 static void *sound_thread(void *unused)
00278 {
00279    fd_set rfds;
00280    fd_set wfds;
00281    int max, res;
00282 
00283    for (;;) {
00284       FD_ZERO(&rfds);
00285       FD_ZERO(&wfds);
00286       max = sndcmd[0];
00287       FD_SET(sndcmd[0], &rfds);
00288       if (cursound > -1) {
00289          FD_SET(writedev, &wfds);
00290          if (writedev > max)
00291             max = writedev;
00292       }
00293 #ifdef ALSA_MONITOR
00294       if (!alsa.owner) {
00295          FD_SET(readdev, &rfds);
00296          if (readdev > max)
00297             max = readdev;
00298       }
00299 #endif
00300       res = ast_select(max + 1, &rfds, &wfds, NULL, NULL);
00301       if (res < 1) {
00302          ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno));
00303          continue;
00304       }
00305 #ifdef ALSA_MONITOR
00306       if (FD_ISSET(readdev, &rfds)) {
00307          /* Keep the pipe going with read audio */
00308          snd_pcm_state_t state;
00309          short buf[FRAME_SIZE];
00310          int r;
00311 
00312          state = snd_pcm_state(alsa.ocard);
00313          if (state == SND_PCM_STATE_XRUN) {
00314             snd_pcm_prepare(alsa.ocard);
00315          }
00316          r = snd_pcm_readi(alsa.icard, buf, FRAME_SIZE);
00317          if (r == -EPIPE) {
00318 #if DEBUG
00319             ast_log(LOG_ERROR, "XRUN read\n");
00320 #endif
00321             snd_pcm_prepare(alsa.icard);
00322          } else if (r == -ESTRPIPE) {
00323             ast_log(LOG_ERROR, "-ESTRPIPE\n");
00324             snd_pcm_prepare(alsa.icard);
00325          } else if (r < 0) {
00326             ast_log(LOG_ERROR, "Read error: %s\n", snd_strerror(r));
00327          } else
00328             alsa_monitor_read((char *) buf, r * 2);
00329       }
00330 #endif
00331       if (FD_ISSET(sndcmd[0], &rfds)) {
00332          if (read(sndcmd[0], &cursound, sizeof(cursound)) < 0) {
00333             ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
00334          }
00335          silencelen = 0;
00336          offset = 0;
00337          sampsent = 0;
00338       }
00339       if (FD_ISSET(writedev, &wfds))
00340          if (send_sound())
00341             ast_log(LOG_WARNING, "Failed to write sound\n");
00342    }
00343    /* Never reached */
00344    return NULL;
00345 }
00346 
00347 static snd_pcm_t *alsa_card_init(char *dev, snd_pcm_stream_t stream)
00348 {
00349    int err;
00350    int direction;
00351    snd_pcm_t *handle = NULL;
00352    snd_pcm_hw_params_t *hwparams = NULL;
00353    snd_pcm_sw_params_t *swparams = NULL;
00354    struct pollfd pfd;
00355    snd_pcm_uframes_t period_size = PERIOD_FRAMES * 4;
00356    /* int period_bytes = 0; */
00357    snd_pcm_uframes_t buffer_size = 0;
00358 
00359    unsigned int rate = DESIRED_RATE;
00360 #if 0
00361    unsigned int per_min = 1;
00362 #endif
00363    /* unsigned int per_max = 8; */
00364    snd_pcm_uframes_t start_threshold, stop_threshold;
00365 
00366    err = snd_pcm_open(&handle, dev, stream, SND_PCM_NONBLOCK);
00367    if (err < 0) {
00368       ast_log(LOG_ERROR, "snd_pcm_open failed: %s\n", snd_strerror(err));
00369       return NULL;
00370    } else
00371       ast_log(LOG_DEBUG, "Opening device %s in %s mode\n", dev, (stream == SND_PCM_STREAM_CAPTURE) ? "read" : "write");
00372 
00373    hwparams = alloca(snd_pcm_hw_params_sizeof());
00374    memset(hwparams, 0, snd_pcm_hw_params_sizeof());
00375    snd_pcm_hw_params_any(handle, hwparams);
00376 
00377    err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
00378    if (err < 0)
00379       ast_log(LOG_ERROR, "set_access failed: %s\n", snd_strerror(err));
00380 
00381    err = snd_pcm_hw_params_set_format(handle, hwparams, format);
00382    if (err < 0)
00383       ast_log(LOG_ERROR, "set_format failed: %s\n", snd_strerror(err));
00384 
00385    err = snd_pcm_hw_params_set_channels(handle, hwparams, 1);
00386    if (err < 0)
00387       ast_log(LOG_ERROR, "set_channels failed: %s\n", snd_strerror(err));
00388 
00389    direction = 0;
00390    err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rate, &direction);
00391    if (rate != DESIRED_RATE)
00392       ast_log(LOG_WARNING, "Rate not correct, requested %d, got %d\n", DESIRED_RATE, rate);
00393 
00394    direction = 0;
00395    err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_size, &direction);
00396    if (err < 0)
00397       ast_log(LOG_ERROR, "period_size(%ld frames) is bad: %s\n", period_size, snd_strerror(err));
00398    else
00399       ast_log(LOG_DEBUG, "Period size is %d\n", err);
00400 
00401    buffer_size = 4096 * 2;    /* period_size * 16; */
00402    err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &buffer_size);
00403    if (err < 0)
00404       ast_log(LOG_WARNING, "Problem setting buffer size of %ld: %s\n", buffer_size, snd_strerror(err));
00405    else
00406       ast_log(LOG_DEBUG, "Buffer size is set to %d frames\n", err);
00407 
00408 #if 0
00409    direction = 0;
00410    err = snd_pcm_hw_params_set_periods_min(handle, hwparams, &per_min, &direction);
00411    if (err < 0)
00412       ast_log(LOG_ERROR, "periods_min: %s\n", snd_strerror(err));
00413 
00414    err = snd_pcm_hw_params_set_periods_max(handle, hwparams, &per_max, 0);
00415    if (err < 0)
00416       ast_log(LOG_ERROR, "periods_max: %s\n", snd_strerror(err));
00417 #endif
00418 
00419    err = snd_pcm_hw_params(handle, hwparams);
00420    if (err < 0)
00421       ast_log(LOG_ERROR, "Couldn't set the new hw params: %s\n", snd_strerror(err));
00422 
00423    swparams = alloca(snd_pcm_sw_params_sizeof());
00424    memset(swparams, 0, snd_pcm_sw_params_sizeof());
00425    snd_pcm_sw_params_current(handle, swparams);
00426 
00427 #if 1
00428    if (stream == SND_PCM_STREAM_PLAYBACK)
00429       start_threshold = period_size;
00430    else
00431       start_threshold = 1;
00432 
00433    err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold);
00434    if (err < 0)
00435       ast_log(LOG_ERROR, "start threshold: %s\n", snd_strerror(err));
00436 #endif
00437 
00438 #if 1
00439    if (stream == SND_PCM_STREAM_PLAYBACK)
00440       stop_threshold = buffer_size;
00441    else
00442       stop_threshold = buffer_size;
00443 
00444    err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold);
00445    if (err < 0)
00446       ast_log(LOG_ERROR, "stop threshold: %s\n", snd_strerror(err));
00447 #endif
00448 #if 0
00449    err = snd_pcm_sw_params_set_xfer_align(handle, swparams, PERIOD_FRAMES);
00450    if (err < 0)
00451       ast_log(LOG_ERROR, "Unable to set xfer alignment: %s\n", snd_strerror(err));
00452 #endif
00453 
00454 #if 0
00455    err = snd_pcm_sw_params_set_silence_threshold(handle, swparams, silencethreshold);
00456    if (err < 0)
00457       ast_log(LOG_ERROR, "Unable to set silence threshold: %s\n", snd_strerror(err));
00458 #endif
00459    err = snd_pcm_sw_params(handle, swparams);
00460    if (err < 0)
00461       ast_log(LOG_ERROR, "sw_params: %s\n", snd_strerror(err));
00462 
00463    err = snd_pcm_poll_descriptors_count(handle);
00464    if (err <= 0)
00465       ast_log(LOG_ERROR, "Unable to get a poll descriptors count, error is %s\n", snd_strerror(err));
00466    if (err != 1)
00467       ast_log(LOG_DEBUG, "Can't handle more than one device\n");
00468 
00469    snd_pcm_poll_descriptors(handle, &pfd, err);
00470    ast_log(LOG_DEBUG, "Acquired fd %d from the poll descriptor\n", pfd.fd);
00471 
00472    if (stream == SND_PCM_STREAM_CAPTURE)
00473       readdev = pfd.fd;
00474    else
00475       writedev = pfd.fd;
00476 
00477    return handle;
00478 }
00479 
00480 static int soundcard_init(void)
00481 {
00482    alsa.icard = alsa_card_init(indevname, SND_PCM_STREAM_CAPTURE);
00483    alsa.ocard = alsa_card_init(outdevname, SND_PCM_STREAM_PLAYBACK);
00484 
00485    if (!alsa.icard || !alsa.ocard) {
00486       ast_log(LOG_ERROR, "Problem opening alsa I/O devices\n");
00487       return -1;
00488    }
00489 
00490    return readdev;
00491 }
00492 
00493 static int alsa_digit(struct ast_channel *c, char digit, unsigned int duration)
00494 {
00495    ast_mutex_lock(&alsalock);
00496    ast_verbose(" << Console Received digit %c of duration %u ms >> \n", 
00497       digit, duration);
00498    ast_mutex_unlock(&alsalock);
00499    return 0;
00500 }
00501 
00502 static int alsa_text(struct ast_channel *c, const char *text)
00503 {
00504    ast_mutex_lock(&alsalock);
00505    ast_verbose(" << Console Received text %s >> \n", text);
00506    ast_mutex_unlock(&alsalock);
00507    return 0;
00508 }
00509 
00510 static void grab_owner(void)
00511 {
00512    while (alsa.owner && ast_mutex_trylock(&alsa.owner->lock)) {
00513       DEADLOCK_AVOIDANCE(&alsalock);
00514    }
00515 }
00516 
00517 static int alsa_call(struct ast_channel *c, char *dest, int timeout)
00518 {
00519    int res = 3;
00520    struct ast_frame f = { AST_FRAME_CONTROL };
00521    ast_mutex_lock(&alsalock);
00522    ast_verbose(" << Call placed to '%s' on console >> \n", dest);
00523    if (autoanswer) {
00524       ast_verbose(" << Auto-answered >> \n");
00525       grab_owner();
00526       if (alsa.owner) {
00527          f.subclass = AST_CONTROL_ANSWER;
00528          ast_queue_frame(alsa.owner, &f);
00529          ast_mutex_unlock(&alsa.owner->lock);
00530       }
00531    } else {
00532       ast_verbose(" << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
00533       grab_owner();
00534       if (alsa.owner) {
00535          f.subclass = AST_CONTROL_RINGING;
00536          ast_queue_frame(alsa.owner, &f);
00537          ast_mutex_unlock(&alsa.owner->lock);
00538       }
00539       if (write(sndcmd[1], &res, sizeof(res)) < 0) {
00540          ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
00541       }
00542    }
00543    snd_pcm_prepare(alsa.icard);
00544    snd_pcm_start(alsa.icard);
00545    ast_mutex_unlock(&alsalock);
00546    return 0;
00547 }
00548 
00549 static void answer_sound(void)
00550 {
00551    int res;
00552 
00553    nosound = 1;
00554    res = 4;
00555    if (write(sndcmd[1], &res, sizeof(res)) < 0) {
00556       ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
00557    }
00558 }
00559 
00560 static int alsa_answer(struct ast_channel *c)
00561 {
00562    ast_mutex_lock(&alsalock);
00563    ast_verbose(" << Console call has been answered >> \n");
00564    answer_sound();
00565    ast_setstate(c, AST_STATE_UP);
00566    cursound = -1;
00567    snd_pcm_prepare(alsa.icard);
00568    snd_pcm_start(alsa.icard);
00569    ast_mutex_unlock(&alsalock);
00570    return 0;
00571 }
00572 
00573 static int alsa_hangup(struct ast_channel *c)
00574 {
00575    int res;
00576    ast_mutex_lock(&alsalock);
00577    cursound = -1;
00578    c->tech_pvt = NULL;
00579    alsa.owner = NULL;
00580    ast_verbose(" << Hangup on console >> \n");
00581    ast_module_unref(ast_module_info->self);
00582    if (hookstate) {
00583       hookstate = 0;
00584       if (!autoanswer) {
00585          /* Congestion noise */
00586          res = 2;
00587          if (write(sndcmd[1], &res, sizeof(res)) < 0) {
00588             ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
00589          }
00590       }
00591    }
00592    snd_pcm_drop(alsa.icard);
00593    ast_mutex_unlock(&alsalock);
00594    return 0;
00595 }
00596 
00597 static int alsa_write(struct ast_channel *chan, struct ast_frame *f)
00598 {
00599    static char sizbuf[8000];
00600    static int sizpos = 0;
00601    int len = sizpos;
00602    int pos;
00603    int res = 0;
00604    /* size_t frames = 0; */
00605    snd_pcm_state_t state;
00606 
00607    /* Immediately return if no sound is enabled */
00608    if (nosound)
00609       return 0;
00610 
00611    ast_mutex_lock(&alsalock);
00612    /* Stop any currently playing sound */
00613    if (cursound != -1) {
00614       snd_pcm_drop(alsa.ocard);
00615       snd_pcm_prepare(alsa.ocard);
00616       cursound = -1;
00617    }
00618 
00619 
00620    /* We have to digest the frame in 160-byte portions */
00621    if (f->datalen > sizeof(sizbuf) - sizpos) {
00622       ast_log(LOG_WARNING, "Frame too large\n");
00623       res = -1;
00624    } else {
00625       memcpy(sizbuf + sizpos, f->data, f->datalen);
00626       len += f->datalen;
00627       pos = 0;
00628 #ifdef ALSA_MONITOR
00629       alsa_monitor_write(sizbuf, len);
00630 #endif
00631       state = snd_pcm_state(alsa.ocard);
00632       if (state == SND_PCM_STATE_XRUN)
00633          snd_pcm_prepare(alsa.ocard);
00634       while ((res = snd_pcm_writei(alsa.ocard, sizbuf, len / 2)) == -EAGAIN) {
00635          usleep(1);
00636       }
00637       if (res == -EPIPE) {
00638 #if DEBUG
00639          ast_log(LOG_DEBUG, "XRUN write\n");
00640 #endif
00641          snd_pcm_prepare(alsa.ocard);
00642          while ((res = snd_pcm_writei(alsa.ocard, sizbuf, len / 2)) == -EAGAIN) {
00643             usleep(1);
00644          }
00645          if (res != len / 2) {
00646             ast_log(LOG_ERROR, "Write error: %s\n", snd_strerror(res));
00647             res = -1;
00648          } else if (res < 0) {
00649             ast_log(LOG_ERROR, "Write error %s\n", snd_strerror(res));
00650             res = -1;
00651          }
00652       } else {
00653          if (res == -ESTRPIPE)
00654             ast_log(LOG_ERROR, "You've got some big problems\n");
00655          else if (res < 0)
00656             ast_log(LOG_NOTICE, "Error %d on write\n", res);
00657       }
00658    }
00659    ast_mutex_unlock(&alsalock);
00660    if (res > 0)
00661       res = 0;
00662    return res;
00663 }
00664 
00665 
00666 static struct ast_frame *alsa_read(struct ast_channel *chan)
00667 {
00668    static struct ast_frame f;
00669    static short __buf[FRAME_SIZE + AST_FRIENDLY_OFFSET / 2];
00670    short *buf;
00671    static int readpos = 0;
00672    static int left = FRAME_SIZE;
00673    snd_pcm_state_t state;
00674    int r = 0;
00675    int off = 0;
00676 
00677    ast_mutex_lock(&alsalock);
00678    /* Acknowledge any pending cmd */
00679    f.frametype = AST_FRAME_NULL;
00680    f.subclass = 0;
00681    f.samples = 0;
00682    f.datalen = 0;
00683    f.data = NULL;
00684    f.offset = 0;
00685    f.src = "Console";
00686    f.mallocd = 0;
00687    f.delivery.tv_sec = 0;
00688    f.delivery.tv_usec = 0;
00689 
00690    state = snd_pcm_state(alsa.icard);
00691    if ((state != SND_PCM_STATE_PREPARED) && (state != SND_PCM_STATE_RUNNING)) {
00692       snd_pcm_prepare(alsa.icard);
00693    }
00694 
00695    buf = __buf + AST_FRIENDLY_OFFSET / 2;
00696 
00697    r = snd_pcm_readi(alsa.icard, buf + readpos, left);
00698    if (r == -EPIPE) {
00699 #if DEBUG
00700       ast_log(LOG_ERROR, "XRUN read\n");
00701 #endif
00702       snd_pcm_prepare(alsa.icard);
00703    } else if (r == -ESTRPIPE) {
00704       ast_log(LOG_ERROR, "-ESTRPIPE\n");
00705       snd_pcm_prepare(alsa.icard);
00706    } else if (r < 0) {
00707       ast_log(LOG_ERROR, "Read error: %s\n", snd_strerror(r));
00708    } else if (r >= 0) {
00709       off -= r;
00710    }
00711    /* Update positions */
00712    readpos += r;
00713    left -= r;
00714 
00715    if (readpos >= FRAME_SIZE) {
00716       /* A real frame */
00717       readpos = 0;
00718       left = FRAME_SIZE;
00719       if (chan->_state != AST_STATE_UP) {
00720          /* Don't transmit unless it's up */
00721          ast_mutex_unlock(&alsalock);
00722          return &f;
00723       }
00724       f.frametype = AST_FRAME_VOICE;
00725       f.subclass = AST_FORMAT_SLINEAR;
00726       f.samples = FRAME_SIZE;
00727       f.datalen = FRAME_SIZE * 2;
00728       f.data = buf;
00729       f.offset = AST_FRIENDLY_OFFSET;
00730       f.src = "Console";
00731       f.mallocd = 0;
00732 #ifdef ALSA_MONITOR
00733       alsa_monitor_read((char *) buf, FRAME_SIZE * 2);
00734 #endif
00735 
00736    }
00737    ast_mutex_unlock(&alsalock);
00738    return &f;
00739 }
00740 
00741 static int alsa_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00742 {
00743    struct chan_alsa_pvt *p = newchan->tech_pvt;
00744    ast_mutex_lock(&alsalock);
00745    p->owner = newchan;
00746    ast_mutex_unlock(&alsalock);
00747    return 0;
00748 }
00749 
00750 static int alsa_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen)
00751 {
00752    int res = 0;
00753 
00754    ast_mutex_lock(&alsalock);
00755 
00756    switch (cond) {
00757    case AST_CONTROL_BUSY:
00758       res = 1;
00759       break;
00760    case AST_CONTROL_CONGESTION:
00761       res = 2;
00762       break;
00763    case AST_CONTROL_RINGING:
00764    case AST_CONTROL_PROGRESS:
00765       break;
00766    case -1:
00767       res = -1;
00768       break;
00769    case AST_CONTROL_VIDUPDATE:
00770       res = -1;
00771       break;
00772    case AST_CONTROL_HOLD:
00773       ast_verbose(" << Console Has Been Placed on Hold >> \n");
00774       ast_moh_start(chan, data, mohinterpret);
00775       break;
00776    case AST_CONTROL_UNHOLD:
00777       ast_verbose(" << Console Has Been Retrieved from Hold >> \n");
00778       ast_moh_stop(chan);
00779       break;
00780    case AST_CONTROL_SRCUPDATE:
00781       break;
00782    default:
00783       ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, chan->name);
00784       res = -1;
00785    }
00786 
00787    if (res > -1) {
00788       if (write(sndcmd[1], &res, sizeof(res)) < 0) {
00789          ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
00790       }
00791    }
00792 
00793    ast_mutex_unlock(&alsalock);
00794 
00795    return res;
00796 }
00797 
00798 static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state)
00799 {
00800    struct ast_channel *tmp = NULL;
00801    
00802    if (!(tmp = ast_channel_alloc(1, state, 0, 0, "", p->exten, p->context, 0, "ALSA/%s", indevname)))
00803       return NULL;
00804 
00805    tmp->tech = &alsa_tech;
00806    tmp->fds[0] = readdev;
00807    tmp->nativeformats = AST_FORMAT_SLINEAR;
00808    tmp->readformat = AST_FORMAT_SLINEAR;
00809    tmp->writeformat = AST_FORMAT_SLINEAR;
00810    tmp->tech_pvt = p;
00811    if (!ast_strlen_zero(p->context))
00812       ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
00813    if (!ast_strlen_zero(p->exten))
00814       ast_copy_string(tmp->exten, p->exten, sizeof(tmp->exten));
00815    if (!ast_strlen_zero(language))
00816       ast_string_field_set(tmp, language, language);
00817    p->owner = tmp;
00818    ast_module_ref(ast_module_info->self);
00819    ast_jb_configure(tmp, &global_jbconf);
00820    if (state != AST_STATE_DOWN) {
00821       if (ast_pbx_start(tmp)) {
00822          ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
00823          ast_hangup(tmp);
00824          tmp = NULL;
00825       }
00826    }
00827 
00828    return tmp;
00829 }
00830 
00831 static struct ast_channel *alsa_request(const char *type, int format, void *data, int *cause)
00832 {
00833    int oldformat = format;
00834    struct ast_channel *tmp = NULL;
00835 
00836    format &= AST_FORMAT_SLINEAR;
00837    if (!format) {
00838       ast_log(LOG_NOTICE, "Asked to get a channel of format '%d'\n", oldformat);
00839       return NULL;
00840    }
00841 
00842    ast_mutex_lock(&alsalock);
00843 
00844    if (alsa.owner) {
00845       ast_log(LOG_NOTICE, "Already have a call on the ALSA channel\n");
00846       *cause = AST_CAUSE_BUSY;
00847    } else if (!(tmp = alsa_new(&alsa, AST_STATE_DOWN)))
00848       ast_log(LOG_WARNING, "Unable to create new ALSA channel\n");
00849 
00850    ast_mutex_unlock(&alsalock);
00851 
00852    return tmp;
00853 }
00854 
00855 static int console_autoanswer_deprecated(int fd, int argc, char *argv[])
00856 {
00857    int res = RESULT_SUCCESS;
00858 
00859    if ((argc != 1) && (argc != 2))
00860       return RESULT_SHOWUSAGE;
00861 
00862    ast_mutex_lock(&alsalock);
00863 
00864    if (argc == 1) {
00865       ast_cli(fd, "Auto answer is %s.\n", autoanswer ? "on" : "off");
00866    } else {
00867       if (!strcasecmp(argv[1], "on"))
00868          autoanswer = -1;
00869       else if (!strcasecmp(argv[1], "off"))
00870          autoanswer = 0;
00871       else
00872          res = RESULT_SHOWUSAGE;
00873    }
00874 
00875    ast_mutex_unlock(&alsalock);
00876 
00877    return res;
00878 }
00879 
00880 static int console_autoanswer(int fd, int argc, char *argv[])
00881 {
00882    int res = RESULT_SUCCESS;;
00883    if ((argc != 2) && (argc != 3))
00884       return RESULT_SHOWUSAGE;
00885    ast_mutex_lock(&alsalock);
00886    if (argc == 2) {
00887       ast_cli(fd, "Auto answer is %s.\n", autoanswer ? "on" : "off");
00888    } else {
00889       if (!strcasecmp(argv[2], "on"))
00890          autoanswer = -1;
00891       else if (!strcasecmp(argv[2], "off"))
00892          autoanswer = 0;
00893       else
00894          res = RESULT_SHOWUSAGE;
00895    }
00896    ast_mutex_unlock(&alsalock);
00897    return res;
00898 }
00899 
00900 static char *autoanswer_complete(const char *line, const char *word, int pos, int state)
00901 {
00902 #ifndef MIN
00903 #define MIN(a,b) ((a) < (b) ? (a) : (b))
00904 #endif
00905    switch (state) {
00906       case 0:
00907          if (!ast_strlen_zero(word) && !strncasecmp(word, "on", MIN(strlen(word), 2)))
00908             return ast_strdup("on");
00909       case 1:
00910          if (!ast_strlen_zero(word) && !strncasecmp(word, "off", MIN(strlen(word), 3)))
00911             return ast_strdup("off");
00912       default:
00913          return NULL;
00914    }
00915    return NULL;
00916 }
00917 
00918 static const char autoanswer_usage[] =
00919    "Usage: console autoanswer [on|off]\n"
00920    "       Enables or disables autoanswer feature.  If used without\n"
00921    "       argument, displays the current on/off status of autoanswer.\n"
00922    "       The default value of autoanswer is in 'alsa.conf'.\n";
00923 
00924 static int console_answer_deprecated(int fd, int argc, char *argv[])
00925 {
00926    int res = RESULT_SUCCESS;
00927 
00928    if (argc != 1)
00929       return RESULT_SHOWUSAGE;
00930 
00931    ast_mutex_lock(&alsalock);
00932 
00933    if (!alsa.owner) {
00934       ast_cli(fd, "No one is calling us\n");
00935       res = RESULT_FAILURE;
00936    } else {
00937       hookstate = 1;
00938       cursound = -1;
00939       grab_owner();
00940       if (alsa.owner) {
00941          struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00942          ast_queue_frame(alsa.owner, &f);
00943          ast_mutex_unlock(&alsa.owner->lock);
00944       }
00945       answer_sound();
00946    }
00947 
00948    snd_pcm_prepare(alsa.icard);
00949    snd_pcm_start(alsa.icard);
00950 
00951    ast_mutex_unlock(&alsalock);
00952 
00953    return RESULT_SUCCESS;
00954 }
00955 
00956 static int console_answer(int fd, int argc, char *argv[])
00957 {
00958    int res = RESULT_SUCCESS;
00959 
00960    if (argc != 2)
00961       return RESULT_SHOWUSAGE;
00962 
00963    ast_mutex_lock(&alsalock);
00964 
00965    if (!alsa.owner) {
00966       ast_cli(fd, "No one is calling us\n");
00967       res = RESULT_FAILURE;
00968    } else {
00969       hookstate = 1;
00970       cursound = -1;
00971       grab_owner();
00972       if (alsa.owner) {
00973          struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00974          ast_queue_frame(alsa.owner, &f);
00975          ast_mutex_unlock(&alsa.owner->lock);
00976       }
00977       answer_sound();
00978    }
00979 
00980    snd_pcm_prepare(alsa.icard);
00981    snd_pcm_start(alsa.icard);
00982 
00983    ast_mutex_unlock(&alsalock);
00984 
00985    return RESULT_SUCCESS;
00986 }
00987 
00988 static char sendtext_usage[] =
00989    "Usage: console send text <message>\n"
00990    "       Sends a text message for display on the remote terminal.\n";
00991 
00992 static int console_sendtext_deprecated(int fd, int argc, char *argv[])
00993 {
00994    int tmparg = 2;
00995    int res = RESULT_SUCCESS;
00996 
00997    if (argc < 2)
00998       return RESULT_SHOWUSAGE;
00999 
01000    ast_mutex_lock(&alsalock);
01001 
01002    if (!alsa.owner) {
01003       ast_cli(fd, "No one is calling us\n");
01004       res = RESULT_FAILURE;
01005    } else {
01006       struct ast_frame f = { AST_FRAME_TEXT, 0 };
01007       char text2send[256] = "";
01008       text2send[0] = '\0';
01009       while (tmparg < argc) {
01010          strncat(text2send, argv[tmparg++], sizeof(text2send) - strlen(text2send) - 1);
01011          strncat(text2send, " ", sizeof(text2send) - strlen(text2send) - 1);
01012       }
01013       text2send[strlen(text2send) - 1] = '\n';
01014       f.data = text2send;
01015       f.datalen = strlen(text2send) + 1;
01016       grab_owner();
01017       if (alsa.owner) {
01018          ast_queue_frame(alsa.owner, &f);
01019          f.frametype = AST_FRAME_CONTROL;
01020          f.subclass = AST_CONTROL_ANSWER;
01021          f.data = NULL;
01022          f.datalen = 0;
01023          ast_queue_frame(alsa.owner, &f);
01024          ast_mutex_unlock(&alsa.owner->lock);
01025       }
01026    }
01027 
01028    ast_mutex_unlock(&alsalock);
01029 
01030    return res;
01031 }
01032 
01033 static int console_sendtext(int fd, int argc, char *argv[])
01034 {
01035    int tmparg = 3;
01036    int res = RESULT_SUCCESS;
01037 
01038    if (argc < 3)
01039       return RESULT_SHOWUSAGE;
01040 
01041    ast_mutex_lock(&alsalock);
01042 
01043    if (!alsa.owner) {
01044       ast_cli(fd, "No one is calling us\n");
01045       res = RESULT_FAILURE;
01046    } else {
01047       struct ast_frame f = { AST_FRAME_TEXT, 0 };
01048       char text2send[256] = "";
01049       text2send[0] = '\0';
01050       while (tmparg < argc) {
01051          strncat(text2send, argv[tmparg++], sizeof(text2send) - strlen(text2send) - 1);
01052          strncat(text2send, " ", sizeof(text2send) - strlen(text2send) - 1);
01053       }
01054       text2send[strlen(text2send) - 1] = '\n';
01055       f.data = text2send;
01056       f.datalen = strlen(text2send) + 1;
01057       grab_owner();
01058       if (alsa.owner) {
01059          ast_queue_frame(alsa.owner, &f);
01060          f.frametype = AST_FRAME_CONTROL;
01061          f.subclass = AST_CONTROL_ANSWER;
01062          f.data = NULL;
01063          f.datalen = 0;
01064          ast_queue_frame(alsa.owner, &f);
01065          ast_mutex_unlock(&alsa.owner->lock);
01066       }
01067    }
01068 
01069    ast_mutex_unlock(&alsalock);
01070 
01071    return res;
01072 }
01073 
01074 static char answer_usage[] =
01075    "Usage: console answer\n"
01076    "       Answers an incoming call on the console (ALSA) channel.\n";
01077 
01078 static int console_hangup_deprecated(int fd, int argc, char *argv[])
01079 {
01080    int res = RESULT_SUCCESS;
01081 
01082    if (argc != 1)
01083       return RESULT_SHOWUSAGE;
01084 
01085    cursound = -1;
01086 
01087    ast_mutex_lock(&alsalock);
01088 
01089    if (!alsa.owner && !hookstate) {
01090       ast_cli(fd, "No call to hangup up\n");
01091       res = RESULT_FAILURE;
01092    } else {
01093       hookstate = 0;
01094       grab_owner();
01095       if (alsa.owner) {
01096          ast_queue_hangup(alsa.owner);
01097          ast_mutex_unlock(&alsa.owner->lock);
01098       }
01099    }
01100 
01101    ast_mutex_unlock(&alsalock);
01102 
01103    return res;
01104 }
01105 
01106 static int console_hangup(int fd, int argc, char *argv[])
01107 {
01108    int res = RESULT_SUCCESS;
01109 
01110    if (argc != 2)
01111       return RESULT_SHOWUSAGE;
01112 
01113    cursound = -1;
01114 
01115    ast_mutex_lock(&alsalock);
01116 
01117    if (!alsa.owner && !hookstate) {
01118       ast_cli(fd, "No call to hangup up\n");
01119       res = RESULT_FAILURE;
01120    } else {
01121       hookstate = 0;
01122       grab_owner();
01123       if (alsa.owner) {
01124          ast_queue_hangup(alsa.owner);
01125          ast_mutex_unlock(&alsa.owner->lock);
01126       }
01127    }
01128 
01129    ast_mutex_unlock(&alsalock);
01130 
01131    return res;
01132 }
01133 
01134 static char hangup_usage[] =
01135    "Usage: console hangup\n"
01136    "       Hangs up any call currently placed on the console.\n";
01137 
01138 static int console_dial_deprecated(int fd, int argc, char *argv[])
01139 {
01140    char tmp[256], *tmp2;
01141    char *mye, *myc;
01142    char *d;
01143    int res = RESULT_SUCCESS;
01144 
01145    if ((argc != 1) && (argc != 2))
01146       return RESULT_SHOWUSAGE;
01147 
01148    ast_mutex_lock(&alsalock);
01149 
01150    if (alsa.owner) {
01151       if (argc == 2) {
01152          d = argv[1];
01153          grab_owner();
01154          if (alsa.owner) {
01155             struct ast_frame f = { AST_FRAME_DTMF };
01156             while (*d) {
01157                f.subclass = *d;
01158                ast_queue_frame(alsa.owner, &f);
01159                d++;
01160             }
01161             ast_mutex_unlock(&alsa.owner->lock);
01162          }
01163       } else {
01164          ast_cli(fd, "You're already in a call.  You can use this only to dial digits until you hangup\n");
01165          res = RESULT_FAILURE;
01166       }
01167    } else {
01168       mye = exten;
01169       myc = context;
01170       if (argc == 2) {
01171          char *stringp = NULL;
01172          ast_copy_string(tmp, argv[1], sizeof(tmp));
01173          stringp = tmp;
01174          strsep(&stringp, "@");
01175          tmp2 = strsep(&stringp, "@");
01176          if (!ast_strlen_zero(tmp))
01177             mye = tmp;
01178          if (!ast_strlen_zero(tmp2))
01179             myc = tmp2;
01180       }
01181       if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
01182          ast_copy_string(alsa.exten, mye, sizeof(alsa.exten));
01183          ast_copy_string(alsa.context, myc, sizeof(alsa.context));
01184          hookstate = 1;
01185          alsa_new(&alsa, AST_STATE_RINGING);
01186       } else
01187          ast_cli(fd, "No such extension '%s' in context '%s'\n", mye, myc);
01188    }
01189 
01190    ast_mutex_unlock(&alsalock);
01191 
01192    return res;
01193 }
01194 
01195 static int console_dial(int fd, int argc, char *argv[])
01196 {
01197    char tmp[256], *tmp2;
01198    char *mye, *myc;
01199    char *d;
01200    int res = RESULT_SUCCESS;
01201 
01202    if ((argc != 2) && (argc != 3))
01203       return RESULT_SHOWUSAGE;
01204 
01205    ast_mutex_lock(&alsalock);
01206 
01207    if (alsa.owner) {
01208       if (argc == 3) {
01209          d = argv[2];
01210          grab_owner();
01211          if (alsa.owner) {
01212             struct ast_frame f = { AST_FRAME_DTMF };
01213             while (*d) {
01214                f.subclass = *d;
01215                ast_queue_frame(alsa.owner, &f);
01216                d++;
01217             }
01218             ast_mutex_unlock(&alsa.owner->lock);
01219          }
01220       } else {
01221          ast_cli(fd, "You're already in a call.  You can use this only to dial digits until you hangup\n");
01222          res = RESULT_FAILURE;
01223       }
01224    } else {
01225       mye = exten;
01226       myc = context;
01227       if (argc == 3) {
01228          char *stringp = NULL;
01229          ast_copy_string(tmp, argv[2], sizeof(tmp));
01230          stringp = tmp;
01231          strsep(&stringp, "@");
01232          tmp2 = strsep(&stringp, "@");
01233          if (!ast_strlen_zero(tmp))
01234             mye = tmp;
01235          if (!ast_strlen_zero(tmp2))
01236             myc = tmp2;
01237       }
01238       if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
01239          ast_copy_string(alsa.exten, mye, sizeof(alsa.exten));
01240          ast_copy_string(alsa.context, myc, sizeof(alsa.context));
01241          hookstate = 1;
01242          alsa_new(&alsa, AST_STATE_RINGING);
01243       } else
01244          ast_cli(fd, "No such extension '%s' in context '%s'\n", mye, myc);
01245    }
01246 
01247    ast_mutex_unlock(&alsalock);
01248 
01249    return res;
01250 }
01251 
01252 static char dial_usage[] =
01253    "Usage: console dial [extension[@context]]\n"
01254    "       Dials a given extension (and context if specified)\n";
01255 
01256 static struct ast_cli_entry cli_alsa_answer_deprecated = {
01257    { "answer", NULL },
01258    console_answer_deprecated, NULL,
01259    NULL };
01260 
01261 static struct ast_cli_entry cli_alsa_hangup_deprecated = {
01262    { "hangup", NULL },
01263    console_hangup_deprecated, NULL,
01264    NULL };
01265 
01266 static struct ast_cli_entry cli_alsa_dial_deprecated = {
01267    { "dial", NULL },
01268    console_dial_deprecated, NULL,
01269    NULL };
01270 
01271 static struct ast_cli_entry cli_alsa_send_text_deprecated = {
01272    { "send", "text", NULL },
01273    console_sendtext_deprecated, NULL,
01274    NULL };
01275 
01276 static struct ast_cli_entry cli_alsa_autoanswer_deprecated = {
01277    { "autoanswer", NULL },
01278    console_autoanswer_deprecated, NULL,
01279    NULL, autoanswer_complete };
01280 
01281 static struct ast_cli_entry cli_alsa[] = {
01282    { { "console", "answer", NULL },
01283    console_answer, "Answer an incoming console call",
01284    answer_usage, NULL, &cli_alsa_answer_deprecated },
01285 
01286    { { "console", "hangup", NULL },
01287    console_hangup, "Hangup a call on the console",
01288    hangup_usage, NULL, &cli_alsa_hangup_deprecated },
01289 
01290    { { "console", "dial", NULL },
01291    console_dial, "Dial an extension on the console",
01292    dial_usage, NULL, &cli_alsa_dial_deprecated },
01293 
01294    { { "console", "send", "text", NULL },
01295    console_sendtext, "Send text to the remote device",
01296    sendtext_usage, NULL, &cli_alsa_send_text_deprecated },
01297 
01298    { { "console", "autoanswer", NULL },
01299    console_autoanswer, "Sets/displays autoanswer",
01300    autoanswer_usage, autoanswer_complete, &cli_alsa_autoanswer_deprecated },
01301 };
01302 
01303 static int load_module(void)
01304 {
01305    int res;
01306    struct ast_config *cfg;
01307    struct ast_variable *v;
01308 
01309    /* Copy the default jb config over global_jbconf */
01310    memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
01311 
01312    strcpy(mohinterpret, "default");
01313 
01314    if ((cfg = ast_config_load(config))) {
01315       v = ast_variable_browse(cfg, "general");
01316       for (; v; v = v->next) {
01317          /* handle jb conf */
01318          if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
01319             continue;
01320 
01321          if (!strcasecmp(v->name, "autoanswer"))
01322             autoanswer = ast_true(v->value);
01323          else if (!strcasecmp(v->name, "silencesuppression"))
01324             silencesuppression = ast_true(v->value);
01325          else if (!strcasecmp(v->name, "silencethreshold"))
01326             silencethreshold = atoi(v->value);
01327          else if (!strcasecmp(v->name, "context"))
01328             ast_copy_string(context, v->value, sizeof(context));
01329          else if (!strcasecmp(v->name, "language"))
01330             ast_copy_string(language, v->value, sizeof(language));
01331          else if (!strcasecmp(v->name, "extension"))
01332             ast_copy_string(exten, v->value, sizeof(exten));
01333          else if (!strcasecmp(v->name, "input_device"))
01334             ast_copy_string(indevname, v->value, sizeof(indevname));
01335          else if (!strcasecmp(v->name, "output_device"))
01336             ast_copy_string(outdevname, v->value, sizeof(outdevname));
01337          else if (!strcasecmp(v->name, "mohinterpret"))
01338             ast_copy_string(mohinterpret, v->value, sizeof(mohinterpret));
01339       }
01340       ast_config_destroy(cfg);
01341    }
01342    res = pipe(sndcmd);
01343    if (res) {
01344       ast_log(LOG_ERROR, "Unable to create pipe\n");
01345       return -1;
01346    }
01347    res = soundcard_init();
01348    if (res < 0) {
01349       if (option_verbose > 1) {
01350          ast_verbose(VERBOSE_PREFIX_2 "No sound card detected -- console channel will be unavailable\n");
01351          ast_verbose(VERBOSE_PREFIX_2 "Turn off ALSA support by adding 'noload=chan_alsa.so' in /etc/asterisk/modules.conf\n");
01352       }
01353       return 0;
01354    }
01355 
01356    res = ast_channel_register(&alsa_tech);
01357    if (res < 0) {
01358       ast_log(LOG_ERROR, "Unable to register channel class 'Console'\n");
01359       return -1;
01360    }
01361    ast_cli_register_multiple(cli_alsa, sizeof(cli_alsa) / sizeof(struct ast_cli_entry));
01362 
01363    ast_pthread_create_background(&sthread, NULL, sound_thread, NULL);
01364 #ifdef ALSA_MONITOR
01365    if (alsa_monitor_start())
01366       ast_log(LOG_ERROR, "Problem starting Monitoring\n");
01367 #endif
01368    return 0;
01369 }
01370 
01371 static int unload_module(void)
01372 {
01373    ast_channel_unregister(&alsa_tech);
01374    ast_cli_unregister_multiple(cli_alsa, sizeof(cli_alsa) / sizeof(struct ast_cli_entry));
01375 
01376    if (alsa.icard)
01377       snd_pcm_close(alsa.icard);
01378    if (alsa.ocard)
01379       snd_pcm_close(alsa.ocard);
01380    if (sndcmd[0] > 0) {
01381       close(sndcmd[0]);
01382       close(sndcmd[1]);
01383    }
01384    if (alsa.owner)
01385       ast_softhangup(alsa.owner, AST_SOFTHANGUP_APPUNLOAD);
01386    if (alsa.owner)
01387       return -1;
01388    return 0;
01389 }
01390 
01391 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ALSA Console Channel Driver");

Generated on Thu May 14 15:12:48 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7