Sun Dec 18 20:55:38 2011

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

Generated on Sun Dec 18 20:55:38 2011 for Asterisk - the Open Source PBX by  doxygen 1.5.6