Mon Mar 31 07:37:57 2008

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

Generated on Mon Mar 31 07:37:57 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1