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

Generated on Sat Aug 6 00:39:23 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7