Thu Dec 17 15:35:34 2009

Asterisk developer's documentation


chan_alsa.c

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

Generated on Thu Dec 17 15:35:34 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7