Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:50 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  * \par See also
    00023  * \arg Config_alsa
    00024  *
    00025  * \ingroup channel_drivers
    00026  */
    00027
    00028
    00029 #include <unistd.h>
    00030 #include <fcntl.h>
    00031 #include <errno.h>
    00032 #include <sys/ioctl.h>
    00033 #include <sys/time.h>
    00034 #include <string.h>
    00035 #include <stdlib.h>
    00036 #include <stdio.h>
    00037
    00038 #define ALSA_PCM_NEW_HW_PARAMS_API
    00039 #define ALSA_PCM_NEW_SW_PARAMS_API
    00040 #include <alsa/asoundlib.h>
    00041
    00042 #include "asterisk.h"
    00043
    00044 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7582 $")
    00045
    00046 #include "asterisk/frame.h"
    00047 #include "asterisk/logger.h"
    00048 #include "asterisk/channel.h"
    00049 #include "asterisk/module.h"
    00050 #include "asterisk/options.h"
    00051 #include "asterisk/pbx.h"
    00052 #include "asterisk/config.h"
    00053 #include "asterisk/cli.h"
    00054 #include "asterisk/utils.h"
    00055 #include "asterisk/causes.h"
    00056 #include "asterisk/endian.h"
    00057
    00058 #include "busy.h"
    00059 #include "ringtone.h"
    00060 #include "ring10.h"
    00061 #include "answer.h"
    00062
    00063 #ifdef ALSA_MONITOR
    00064 #include "alsa-monitor.h"
    00065 #endif
    00066
    00067 #define DEBUG 0
    00068 /* Which device to use */
    00069 #define ALSA_INDEV "default"
    00070 #define ALSA_OUTDEV "default"
    00071 #define DESIRED_RATE 8000
    00072
    00073 /* Lets use 160 sample frames, just like GSM.  */
    00074 #define FRAME_SIZE 160
    00075 #define PERIOD_FRAMES 80 /* 80 Frames, at 2 bytes each */
    00076
    00077 /* When you set the frame size, you have to come up with
    00078    the right buffer format as well. */
    00079 /* 5 64-byte frames = one frame */
    00080 #define BUFFER_FMT ((buffersize * 10) << 16) | (0x0006);
    00081
    00082 /* Don't switch between read/write modes faster than every 300 ms */
    00083 #define MIN_SWITCH_TIME 600
    00084
    00085 #if __BYTE_ORDER == __LITTLE_ENDIAN
    00086 static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
    00087 #else
    00088 static snd_pcm_format_t format = SND_PCM_FORMAT_S16_BE;
    00089 #endif
    00090
    00091 /* static int block = O_NONBLOCK; */
    00092 static char indevname[50] = ALSA_INDEV;
    00093 static char outdevname[50] = ALSA_OUTDEV;
    00094
    00095 #if 0
    00096 static struct timeval lasttime;
    00097 #endif
    00098
    00099 static int usecnt;
    00100 static int silencesuppression = 0;
    00101 static int silencethreshold = 1000;
    00102
    00103 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
    00104 AST_MUTEX_DEFINE_STATIC(alsalock);
    00105
    00106 static const char type[] = "Console";
    00107 static const char desc[] = "ALSA Console Channel Driver";
    00108 static const char tdesc[] = "ALSA Console Channel Driver";
    00109 static const char config[] = "alsa.conf";
    00110
    00111 static char context[AST_MAX_CONTEXT] = "default";
    00112 static char language[MAX_LANGUAGE] = "";
    00113 static char exten[AST_MAX_EXTENSION] = "s";
    00114
    00115 static int hookstate=0;
    00116
    00117 static short silence[FRAME_SIZE] = {0, };
    00118
    00119 struct sound {
    00120    int ind;
    00121    short *data;
    00122    int datalen;
    00123    int samplen;
    00124    int silencelen;
    00125    int repeat;
    00126 };
    00127
    00128 static struct sound sounds[] = {
    00129    { AST_CONTROL_RINGING, ringtone, sizeof(ringtone)/2, 16000, 32000, 1 },
    00130    { AST_CONTROL_BUSY, busy, sizeof(busy)/2, 4000, 4000, 1 },
    00131    { AST_CONTROL_CONGESTION, busy, sizeof(busy)/2, 2000, 2000, 1 },
    00132    { AST_CONTROL_RING, ring10, sizeof(ring10)/2, 16000, 32000, 1 },
    00133    { AST_CONTROL_ANSWER, answer, sizeof(answer)/2, 2200, 0, 0 },
    00134 };
    00135
    00136 /* Sound command pipe */
    00137 static int sndcmd[2];
    00138
    00139 static struct chan_alsa_pvt {
    00140    /* We only have one ALSA structure -- near sighted perhaps, but it
    00141       keeps this driver as simple as possible -- as it should be. */
    00142    struct ast_channel *owner;
    00143    char exten[AST_MAX_EXTENSION];
    00144    char context[AST_MAX_CONTEXT];
    00145 #if 0
    00146    snd_pcm_t *card;
    00147 #endif
    00148    snd_pcm_t *icard, *ocard;
    00149
    00150 } alsa;
    00151
    00152 /* Number of buffers...  Each is FRAMESIZE/8 ms long.  For example
    00153    with 160 sample frames, and a buffer size of 3, we have a 60ms buffer,
    00154    usually plenty. */
    00155
    00156 pthread_t sthread;
    00157
    00158 #define MAX_BUFFER_SIZE 100
    00159
    00160 /* File descriptors for sound device */
    00161 static int readdev = -1;
    00162 static int writedev = -1;
    00163
    00164 static int autoanswer = 1;
    00165
    00166 static int cursound = -1;
    00167 static int sampsent = 0;
    00168 static int silencelen=0;
    00169 static int offset=0;
    00170 static int nosound=0;
    00171
    00172 /* ZZ */
    00173 static struct ast_channel *alsa_request(const char *type, int format, void *data, int *cause);
    00174 static int alsa_digit(struct ast_channel *c, char digit);
    00175 static int alsa_text(struct ast_channel *c, const char *text);
    00176 static int alsa_hangup(struct ast_channel *c);
    00177 static int alsa_answer(struct ast_channel *c);
    00178 static struct ast_frame *alsa_read(struct ast_channel *chan);
    00179 static int alsa_call(struct ast_channel *c, char *dest, int timeout);
    00180 static int alsa_write(struct ast_channel *chan, struct ast_frame *f);
    00181 static int alsa_indicate(struct ast_channel *chan, int cond);
    00182 static int alsa_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
    00183
    00184 static const struct ast_channel_tech alsa_tech = {
    00185    .type = type,
    00186    .description = tdesc,
    00187    .capabilities = AST_FORMAT_SLINEAR,
    00188    .requester = alsa_request,
    00189    .send_digit = alsa_digit,
    00190    .send_text = alsa_text,
    00191    .hangup = alsa_hangup,
    00192    .answer = alsa_answer,
    00193    .read = alsa_read,
    00194    .call = alsa_call,
    00195    .write = alsa_write,
    00196    .indicate = alsa_indicate,
    00197    .fixup = alsa_fixup,
    00198 };
    00199
    00200 static int send_sound(void)
    00201 {
    00202    short myframe[FRAME_SIZE];
    00203    int total = FRAME_SIZE;
    00204    short *frame = NULL;
    00205    int amt=0;
    00206    int res;
    00207    int myoff;
    00208    snd_pcm_state_t state;
    00209
    00210    if (cursound > -1) {
    00211       res = total;
    00212       if (sampsent < sounds[cursound].samplen) {
    00213          myoff=0;
    00214          while(total) {
    00215             amt = total;
    00216             if (amt > (sounds[cursound].datalen - offset))
    00217                amt = sounds[cursound].datalen - offset;
    00218             memcpy(myframe + myoff, sounds[cursound].data + offset, amt * 2);
    00219             total -= amt;
    00220             offset += amt;
    00221             sampsent += amt;
    00222             myoff += amt;
    00223             if (offset >= sounds[cursound].datalen)
    00224                offset = 0;
    00225          }
    00226          /* Set it up for silence */
    00227          if (sampsent >= sounds[cursound].samplen)
    00228             silencelen = sounds[cursound].silencelen;
    00229          frame = myframe;
    00230       } else {
    00231          if (silencelen > 0) {
    00232             frame = silence;
    00233             silencelen -= res;
    00234          } else {
    00235             if (sounds[cursound].repeat) {
    00236                /* Start over */
    00237                sampsent = 0;
    00238                offset = 0;
    00239             } else {
    00240                cursound = -1;
    00241                nosound = 0;
    00242             }
    00243          return 0;
    00244          }
    00245       }
    00246
    00247       if (res == 0 || !frame) {
    00248          return 0;
    00249       }
    00250 #ifdef ALSA_MONITOR
    00251       alsa_monitor_write((char *)frame, res * 2);
    00252 #endif
    00253       state = snd_pcm_state(alsa.ocard);
    00254       if (state == SND_PCM_STATE_XRUN) {
    00255          snd_pcm_prepare(alsa.ocard);
    00256       }
    00257       res = snd_pcm_writei(alsa.ocard, frame, res);
    00258       if (res > 0)
    00259          return 0;
    00260       return 0;
    00261    }
    00262    return 0;
    00263 }
    00264
    00265 static void *sound_thread(void *unused)
    00266 {
    00267    fd_set rfds;
    00268    fd_set wfds;
    00269    int max;
    00270    int res;
    00271    for(;;) {
    00272       FD_ZERO(&rfds);
    00273       FD_ZERO(&wfds);
    00274       max = sndcmd[0];
    00275       FD_SET(sndcmd[0], &rfds);
    00276       if (cursound > -1) {
    00277          FD_SET(writedev, &wfds);
    00278          if (writedev > max)
    00279             max = writedev;
    00280       }
    00281 #ifdef ALSA_MONITOR
    00282       if (!alsa.owner) {
    00283          FD_SET(readdev, &rfds);
    00284          if (readdev > max)
    00285             max = readdev;
    00286       }
    00287 #endif
    00288       res = ast_select(max + 1, &rfds, &wfds, NULL, NULL);
    00289       if (res < 1) {
    00290          ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno));
    00291          continue;
    00292       }
    00293 #ifdef ALSA_MONITOR
    00294       if (FD_ISSET(readdev, &rfds)) {
    00295          /* Keep the pipe going with read audio */
    00296          snd_pcm_state_t state;
    00297          short buf[FRAME_SIZE];
    00298          int r;
    00299
    00300          state = snd_pcm_state(alsa.ocard);
    00301          if (state == SND_PCM_STATE_XRUN) {
    00302             snd_pcm_prepare(alsa.ocard);
    00303          }
    00304          r = snd_pcm_readi(alsa.icard, buf, FRAME_SIZE);
    00305          if (r == -EPIPE) {
    00306 #if DEBUG
    00307             ast_log(LOG_ERROR, "XRUN read\n");
    00308 #endif
    00309             snd_pcm_prepare(alsa.icard);
    00310          } else if (r == -ESTRPIPE) {
    00311             ast_log(LOG_ERROR, "-ESTRPIPE\n");
    00312             snd_pcm_prepare(alsa.icard);
    00313          } else if (r < 0) {
    00314             ast_log(LOG_ERROR, "Read error: %s\n", snd_strerror(r));
    00315          } else
    00316             alsa_monitor_read((char *)buf, r * 2);
    00317       }
    00318 #endif
    00319       if (FD_ISSET(sndcmd[0], &rfds)) {
    00320          read(sndcmd[0], &cursound, sizeof(cursound));
    00321          silencelen = 0;
    00322          offset = 0;
    00323          sampsent = 0;
    00324       }
    00325       if (FD_ISSET(writedev, &wfds))
    00326          if (send_sound())
    00327             ast_log(LOG_WARNING, "Failed to write sound\n");
    00328    }
    00329    /* Never reached */
    00330    return NULL;
    00331 }
    00332
    00333 static snd_pcm_t *alsa_card_init(char *dev, snd_pcm_stream_t stream)
    00334 {
    00335    int err;
    00336    int direction;
    00337    snd_pcm_t *handle = NULL;
    00338    snd_pcm_hw_params_t *hwparams = NULL;
    00339    snd_pcm_sw_params_t *swparams = NULL;
    00340    struct pollfd pfd;
    00341    snd_pcm_uframes_t period_size = PERIOD_FRAMES * 4;
    00342    /* int period_bytes = 0; */
    00343    snd_pcm_uframes_t buffer_size = 0;
    00344
    00345    unsigned int rate = DESIRED_RATE;
    00346 #if 0
    00347    unsigned int per_min = 1;
    00348 #endif
    00349    /* unsigned int per_max = 8; */
    00350    snd_pcm_uframes_t start_threshold, stop_threshold;
    00351
    00352    err = snd_pcm_open(&handle, dev, stream, O_NONBLOCK);
    00353    if (err < 0) {
    00354       ast_log(LOG_ERROR, "snd_pcm_open failed: %s\n", snd_strerror(err));
    00355       return NULL;
    00356    } else {
    00357       ast_log(LOG_DEBUG, "Opening device %s in %s mode\n", dev, (stream == SND_PCM_STREAM_CAPTURE) ? "read" : "write");
    00358    }
    00359
    00360    snd_pcm_hw_params_alloca(&hwparams);
    00361    snd_pcm_hw_params_any(handle, hwparams);
    00362
    00363    err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
    00364    if (err < 0) {
    00365       ast_log(LOG_ERROR, "set_access failed: %s\n", snd_strerror(err));
    00366    }
    00367
    00368    err = snd_pcm_hw_params_set_format(handle, hwparams, format);
    00369    if (err < 0) {
    00370       ast_log(LOG_ERROR, "set_format failed: %s\n", snd_strerror(err));
    00371    }
    00372
    00373    err = snd_pcm_hw_params_set_channels(handle, hwparams, 1);
    00374    if (err < 0) {
    00375       ast_log(LOG_ERROR, "set_channels failed: %s\n", snd_strerror(err));
    00376    }
    00377
    00378    direction = 0;
    00379    err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rate, &direction);
    00380    if (rate != DESIRED_RATE) {
    00381       ast_log(LOG_WARNING, "Rate not correct, requested %d, got %d\n", DESIRED_RATE, rate);
    00382    }
    00383
    00384    direction = 0;
    00385    err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_size, &direction);
    00386    if (err < 0) {
    00387       ast_log(LOG_ERROR, "period_size(%ld frames) is bad: %s\n", period_size, snd_strerror(err));
    00388    } else {
    00389       ast_log(LOG_DEBUG, "Period size is %d\n", err);
    00390    }
    00391
    00392    buffer_size = 4096 * 2; /* period_size * 16; */
    00393    err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &buffer_size);
    00394    if (err < 0) {
    00395       ast_log(LOG_WARNING, "Problem setting buffer size of %ld: %s\n", buffer_size, snd_strerror(err));
    00396    } else {
    00397       ast_log(LOG_DEBUG, "Buffer size is set to %d frames\n", err);
    00398    }
    00399
    00400 #if 0
    00401    direction = 0;
    00402    err = snd_pcm_hw_params_set_periods_min(handle, hwparams, &per_min, &direction);
    00403    if (err < 0) {
    00404       ast_log(LOG_ERROR, "periods_min: %s\n", snd_strerror(err));
    00405    }
    00406
    00407    err = snd_pcm_hw_params_set_periods_max(handle, hwparams, &per_max, 0);
    00408    if (err < 0) {
    00409       ast_log(LOG_ERROR, "periods_max: %s\n", snd_strerror(err));
    00410    }
    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
    00418    snd_pcm_sw_params_alloca(&swparams);
    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
    00428    err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold);
    00429    if (err < 0) {
    00430       ast_log(LOG_ERROR, "start threshold: %s\n", snd_strerror(err));
    00431    }
    00432 #endif
    00433
    00434 #if 1
    00435    if (stream == SND_PCM_STREAM_PLAYBACK) {
    00436       stop_threshold = buffer_size;
    00437    } else {
    00438       stop_threshold = buffer_size;
    00439    }
    00440    err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold);
    00441    if (err < 0) {
    00442       ast_log(LOG_ERROR, "stop threshold: %s\n", snd_strerror(err));
    00443    }
    00444 #endif
    00445 #if 0
    00446    err = snd_pcm_sw_params_set_xfer_align(handle, swparams, PERIOD_FRAMES);
    00447    if (err < 0) {
    00448       ast_log(LOG_ERROR, "Unable to set xfer alignment: %s\n", snd_strerror(err));
    00449    }
    00450 #endif
    00451
    00452 #if 0
    00453    err = snd_pcm_sw_params_set_silence_threshold(handle, swparams, silencethreshold);
    00454    if (err < 0) {
    00455       ast_log(LOG_ERROR, "Unable to set silence threshold: %s\n", snd_strerror(err));
    00456    }
    00457 #endif
    00458    err = snd_pcm_sw_params(handle, swparams);
    00459    if (err < 0) {
    00460       ast_log(LOG_ERROR, "sw_params: %s\n", snd_strerror(err));
    00461    }
    00462
    00463    err = snd_pcm_poll_descriptors_count(handle);
    00464    if (err <= 0) {
    00465       ast_log(LOG_ERROR, "Unable to get a poll descriptors count, error is %s\n", snd_strerror(err));
    00466    }
    00467
    00468    if (err != 1) {
    00469       ast_log(LOG_DEBUG, "Can't handle more than one device\n");
    00470    }
    00471
    00472    snd_pcm_poll_descriptors(handle, &pfd, err);
    00473    ast_log(LOG_DEBUG, "Acquired fd %d from the poll descriptor\n", pfd.fd);
    00474
    00475    if (stream == SND_PCM_STREAM_CAPTURE)
    00476       readdev = pfd.fd;
    00477    else
    00478       writedev = pfd.fd;
    00479
    00480    return handle;
    00481 }
    00482
    00483 static int soundcard_init(void)
    00484 {
    00485    alsa.icard = alsa_card_init(indevname, SND_PCM_STREAM_CAPTURE);
    00486    alsa.ocard = alsa_card_init(outdevname, SND_PCM_STREAM_PLAYBACK);
    00487
    00488    if (!alsa.icard || !alsa.ocard) {
    00489       ast_log(LOG_ERROR, "Problem opening alsa I/O devices\n");
    00490       return -1;
    00491    }
    00492
    00493    return readdev;
    00494 }
    00495
    00496 static int alsa_digit(struct ast_channel *c, char digit)
    00497 {
    00498    ast_mutex_lock(&alsalock);
    00499    ast_verbose( " << Console Received digit %c >> \n", digit);
    00500    ast_mutex_unlock(&alsalock);
    00501    return 0;
    00502 }
    00503
    00504 static int alsa_text(struct ast_channel *c, const char *text)
    00505 {
    00506    ast_mutex_lock(&alsalock);
    00507    ast_verbose( " << Console Received text %s >> \n", text);
    00508    ast_mutex_unlock(&alsalock);
    00509    return 0;
    00510 }
    00511
    00512 static void grab_owner(void)
    00513 {
    00514    while(alsa.owner && ast_mutex_trylock(&alsa.owner->lock)) {
    00515       ast_mutex_unlock(&alsalock);
    00516       usleep(1);
    00517       ast_mutex_lock(&alsalock);
    00518    }
    00519 }
    00520
    00521 static int alsa_call(struct ast_channel *c, char *dest, int timeout)
    00522 {
    00523    int res = 3;
    00524    struct ast_frame f = { AST_FRAME_CONTROL };
    00525    ast_mutex_lock(&alsalock);
    00526    ast_verbose( " << Call placed to '%s' on console >> \n", dest);
    00527    if (autoanswer) {
    00528       ast_verbose( " << Auto-answered >> \n" );
    00529       grab_owner();
    00530       if (alsa.owner) {
    00531          f.subclass = AST_CONTROL_ANSWER;
    00532          ast_queue_frame(alsa.owner, &f);
    00533          ast_mutex_unlock(&alsa.owner->lock);
    00534       }
    00535    } else {
    00536       ast_verbose( " << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
    00537       grab_owner();
    00538       if (alsa.owner) {
    00539          f.subclass = AST_CONTROL_RINGING;
    00540          ast_queue_frame(alsa.owner, &f);
    00541          ast_mutex_unlock(&alsa.owner->lock);
    00542       }
    00543       write(sndcmd[1], &res, sizeof(res));
    00544    }
    00545    snd_pcm_prepare(alsa.icard);
    00546    snd_pcm_start(alsa.icard);
    00547    ast_mutex_unlock(&alsalock);
    00548    return 0;
    00549 }
    00550
    00551 static void answer_sound(void)
    00552 {
    00553    int res;
    00554    nosound = 1;
    00555    res = 4;
    00556    write(sndcmd[1], &res, sizeof(res));
    00557
    00558 }
    00559
    00560 static int alsa_answer(struct ast_channel *c)
    00561 {
    00562    ast_mutex_lock(&alsalock);
    00563    ast_verbose( " << Console call has been answered >> \n");
    00564    answer_sound();
    00565    ast_setstate(c, AST_STATE_UP);
    00566    cursound = -1;
    00567    snd_pcm_prepare(alsa.icard);
    00568    snd_pcm_start(alsa.icard);
    00569    ast_mutex_unlock(&alsalock);
    00570    return 0;
    00571 }
    00572
    00573 static int alsa_hangup(struct ast_channel *c)
    00574 {
    00575    int res;
    00576    ast_mutex_lock(&alsalock);
    00577    cursound = -1;
    00578    c->tech_pvt = NULL;
    00579    alsa.owner = NULL;
    00580    ast_verbose( " << Hangup on console >> \n");
    00581    ast_mutex_lock(&usecnt_lock);
    00582    usecnt--;
    00583    ast_mutex_unlock(&usecnt_lock);
    00584    if (hookstate) {
    00585       if (autoanswer) {
    00586          hookstate = 0;
    00587       } else {
    00588          /* Congestion noise */
    00589          res = 2;
    00590          write(sndcmd[1], &res, sizeof(res));
    00591          hookstate = 0;
    00592       }
    00593    }
    00594    snd_pcm_drop(alsa.icard);
    00595    ast_mutex_unlock(&alsalock);
    00596    return 0;
    00597 }
    00598
    00599 static int alsa_write(struct ast_channel *chan, struct ast_frame *f)
    00600 {
    00601    static char sizbuf[8000];
    00602    static int sizpos = 0;
    00603    int len = sizpos;
    00604    int pos;
    00605    int res = 0;
    00606    /* size_t frames = 0; */
    00607    snd_pcm_state_t state;
    00608    /* Immediately return if no sound is enabled */
    00609    if (nosound)
    00610       return 0;
    00611    ast_mutex_lock(&alsalock);
    00612    /* Stop any currently playing sound */
    00613    if (cursound != -1) {
    00614       snd_pcm_drop(alsa.ocard);
    00615       snd_pcm_prepare(alsa.ocard);
    00616       cursound = -1;
    00617    }
    00618
    00619
    00620    /* We have to digest the frame in 160-byte portions */
    00621    if (f->datalen > sizeof(sizbuf) - sizpos) {
    00622       ast_log(LOG_WARNING, "Frame too large\n");
    00623       res = -1;
    00624    } else {
    00625       memcpy(sizbuf + sizpos, f->data, f->datalen);
    00626       len += f->datalen;
    00627       pos = 0;
    00628 #ifdef ALSA_MONITOR
    00629       alsa_monitor_write(sizbuf, len);
    00630 #endif
    00631       state = snd_pcm_state(alsa.ocard);
    00632       if (state == SND_PCM_STATE_XRUN) {
    00633          snd_pcm_prepare(alsa.ocard);
    00634       }
    00635       res = snd_pcm_writei(alsa.ocard, sizbuf, len/2);
    00636       if (res == -EPIPE) {
    00637 #if DEBUG
    00638          ast_log(LOG_DEBUG, "XRUN write\n");
    00639 #endif
    00640          snd_pcm_prepare(alsa.ocard);
    00641          res = snd_pcm_writei(alsa.ocard, sizbuf, len/2);
    00642          if (res != len/2) {
    00643             ast_log(LOG_ERROR, "Write error: %s\n", snd_strerror(res));
    00644             res = -1;
    00645          } else if (res < 0) {
    00646             ast_log(LOG_ERROR, "Write error %s\n", snd_strerror(res));
    00647             res = -1;
    00648          }
    00649       } else {
    00650          if (res == -ESTRPIPE) {
    00651             ast_log(LOG_ERROR, "You've got some big problems\n");
    00652          } else if (res < 0)
    00653             ast_log(LOG_NOTICE, "Error %d on write\n", res);
    00654       }
    00655    }
    00656    ast_mutex_unlock(&alsalock);
    00657    if (res > 0)
    00658       res = 0;
    00659    return res;
    00660 }
    00661
    00662
    00663 static struct ast_frame *alsa_read(struct ast_channel *chan)
    00664 {
    00665    static struct ast_frame f;
    00666    static short __buf[FRAME_SIZE + AST_FRIENDLY_OFFSET/2];
    00667    short *buf;
    00668    static int readpos = 0;
    00669    static int left = FRAME_SIZE;
    00670    snd_pcm_state_t state;
    00671    int r = 0;
    00672    int off = 0;
    00673
    00674    ast_mutex_lock(&alsalock);
    00675    /* Acknowledge any pending cmd */
    00676    f.frametype = AST_FRAME_NULL;
    00677    f.subclass = 0;
    00678    f.samples = 0;
    00679    f.datalen = 0;
    00680    f.data = NULL;
    00681    f.offset = 0;
    00682    f.src = type;
    00683    f.mallocd = 0;
    00684    f.delivery.tv_sec = 0;
    00685    f.delivery.tv_usec = 0;
    00686
    00687    state = snd_pcm_state(alsa.icard);
    00688    if ((state != SND_PCM_STATE_PREPARED) &&
    00689        (state != SND_PCM_STATE_RUNNING)) {
    00690       snd_pcm_prepare(alsa.icard);
    00691    }
    00692
    00693    buf = __buf + AST_FRIENDLY_OFFSET/2;
    00694
    00695    r = snd_pcm_readi(alsa.icard, buf + readpos, left);
    00696    if (r == -EPIPE) {
    00697 #if DEBUG
    00698       ast_log(LOG_ERROR, "XRUN read\n");
    00699 #endif
    00700       snd_pcm_prepare(alsa.icard);
    00701    } else if (r == -ESTRPIPE) {
    00702       ast_log(LOG_ERROR, "-ESTRPIPE\n");
    00703       snd_pcm_prepare(alsa.icard);
    00704    } else if (r < 0) {
    00705       ast_log(LOG_ERROR, "Read error: %s\n", snd_strerror(r));
    00706    } else if (r >= 0) {
    00707       off -= r;
    00708    }
    00709    /* Update positions */
    00710    readpos += r;
    00711    left -= r;
    00712
    00713    if (readpos >= FRAME_SIZE) {
    00714       /* A real frame */
    00715       readpos = 0;
    00716       left = FRAME_SIZE;
    00717       if (chan->_state != AST_STATE_UP) {
    00718          /* Don't transmit unless it's up */
    00719          ast_mutex_unlock(&alsalock);
    00720          return &f;
    00721       }
    00722       f.frametype = AST_FRAME_VOICE;
    00723       f.subclass = AST_FORMAT_SLINEAR;
    00724       f.samples = FRAME_SIZE;
    00725       f.datalen = FRAME_SIZE * 2;
    00726       f.data = buf;
    00727       f.offset = AST_FRIENDLY_OFFSET;
    00728       f.src = type;
    00729       f.mallocd = 0;
    00730 #ifdef ALSA_MONITOR
    00731       alsa_monitor_read((char *)buf, FRAME_SIZE * 2);
    00732 #endif
    00733
    00734    }
    00735    ast_mutex_unlock(&alsalock);
    00736    return &f;
    00737 }
    00738
    00739 static int alsa_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
    00740 {
    00741    struct chan_alsa_pvt *p = newchan->tech_pvt;
    00742    ast_mutex_lock(&alsalock);
    00743    p->owner = newchan;
    00744    ast_mutex_unlock(&alsalock);
    00745    return 0;
    00746 }
    00747
    00748 static int alsa_indicate(struct ast_channel *chan, int cond)
    00749 {
    00750    int res = 0;
    00751    ast_mutex_lock(&alsalock);
    00752    switch(cond) {
    00753    case AST_CONTROL_BUSY:
    00754       res = 1;
    00755       break;
    00756    case AST_CONTROL_CONGESTION:
    00757       res = 2;
    00758       break;
    00759    case AST_CONTROL_RINGING:
    00760       res = 0;
    00761       break;
    00762    case -1:
    00763       res = -1;
    00764       break;
    00765    case AST_CONTROL_VIDUPDATE:
    00766       res = -1;
    00767       break;
    00768    default:
    00769       ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, chan->name);
    00770       res = -1;
    00771    }
    00772    if (res > -1) {
    00773       write(sndcmd[1], &res, sizeof(res));
    00774    }
    00775    ast_mutex_unlock(&alsalock);
    00776    return res;
    00777 }
    00778
    00779 static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state)
    00780 {
    00781    struct ast_channel *tmp;
    00782    tmp = ast_channel_alloc(1);
    00783    if (tmp) {
    00784       tmp->tech = &alsa_tech;
    00785       snprintf(tmp->name, sizeof(tmp->name), "ALSA/%s", indevname);
    00786       tmp->type = type;
    00787       tmp->fds[0] = readdev;
    00788       tmp->nativeformats = AST_FORMAT_SLINEAR;
    00789       tmp->readformat = AST_FORMAT_SLINEAR;
    00790       tmp->writeformat = AST_FORMAT_SLINEAR;
    00791       tmp->tech_pvt = p;
    00792       if (!ast_strlen_zero(p->context))
    00793          ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
    00794       if (!ast_strlen_zero(p->exten))
    00795          ast_copy_string(tmp->exten, p->exten, sizeof(tmp->exten));
    00796       if (!ast_strlen_zero(language))
    00797          ast_copy_string(tmp->language, language, sizeof(tmp->language));
    00798       p->owner = tmp;
    00799       ast_setstate(tmp, state);
    00800       ast_mutex_lock(&usecnt_lock);
    00801       usecnt++;
    00802       ast_mutex_unlock(&usecnt_lock);
    00803       ast_update_use_count();
    00804       if (state != AST_STATE_DOWN) {
    00805          if (ast_pbx_start(tmp)) {
    00806             ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
    00807             ast_hangup(tmp);
    00808             tmp = NULL;
    00809          }
    00810       }
    00811    }
    00812    return tmp;
    00813 }
    00814
    00815 static struct ast_channel *alsa_request(const char *type, int format, void *data, int *cause)
    00816 {
    00817    int oldformat = format;
    00818    struct ast_channel *tmp=NULL;
    00819    format &= AST_FORMAT_SLINEAR;
    00820    if (!format) {
    00821       ast_log(LOG_NOTICE, "Asked to get a channel of format '%d'\n", oldformat);
    00822       return NULL;
    00823    }
    00824    ast_mutex_lock(&alsalock);
    00825    if (alsa.owner) {
    00826       ast_log(LOG_NOTICE, "Already have a call on the ALSA channel\n");
    00827       *cause = AST_CAUSE_BUSY;
    00828    } else {
    00829       tmp= alsa_new(&alsa, AST_STATE_DOWN);
    00830       if (!tmp) {
    00831          ast_log(LOG_WARNING, "Unable to create new ALSA channel\n");
    00832       }
    00833    }
    00834    ast_mutex_unlock(&alsalock);
    00835    return tmp;
    00836 }
    00837
    00838 static int console_autoanswer(int fd, int argc, char *argv[])
    00839 {
    00840    int res = RESULT_SUCCESS;;
    00841    if ((argc != 1) && (argc != 2))
    00842       return RESULT_SHOWUSAGE;
    00843    ast_mutex_lock(&alsalock);
    00844    if (argc == 1) {
    00845       ast_cli(fd, "Auto answer is %s.\n", autoanswer ? "on" : "off");
    00846    } else {
    00847       if (!strcasecmp(argv[1], "on"))
    00848          autoanswer = -1;
    00849       else if (!strcasecmp(argv[1], "off"))
    00850          autoanswer = 0;
    00851       else
    00852          res = RESULT_SHOWUSAGE;
    00853    }
    00854    ast_mutex_unlock(&alsalock);
    00855    return res;
    00856 }
    00857
    00858 static char *autoanswer_complete(char *line, char *word, int pos, int state)
    00859 {
    00860 #ifndef MIN
    00861 #define MIN(a,b) ((a) < (b) ? (a) : (b))
    00862 #endif
    00863    switch(state) {
    00864    case 0:
    00865       if (!ast_strlen_zero(word) && !strncasecmp(word, "on", MIN(strlen(word), 2)))
    00866          return strdup("on");
    00867    case 1:
    00868       if (!ast_strlen_zero(word) && !strncasecmp(word, "off", MIN(strlen(word), 3)))
    00869          return strdup("off");
    00870    default:
    00871       return NULL;
    00872    }
    00873    return NULL;
    00874 }
    00875
    00876 static char autoanswer_usage[] =
    00877 "Usage: autoanswer [on|off]\n"
    00878 "       Enables or disables autoanswer feature.  If used without\n"
    00879 "       argument, displays the current on/off status of autoanswer.\n"
    00880 "       The default value of autoanswer is in 'alsa.conf'.\n";
    00881
    00882 static int console_answer(int fd, int argc, char *argv[])
    00883 {
    00884    int res = RESULT_SUCCESS;
    00885    if (argc != 1)
    00886       return RESULT_SHOWUSAGE;
    00887    ast_mutex_lock(&alsalock);
    00888    if (!alsa.owner) {
    00889       ast_cli(fd, "No one is calling us\n");
    00890       res = RESULT_FAILURE;
    00891    } else {
    00892       hookstate = 1;
    00893       cursound = -1;
    00894       grab_owner();
    00895       if (alsa.owner) {
    00896          struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
    00897          ast_queue_frame(alsa.owner, &f);
    00898          ast_mutex_unlock(&alsa.owner->lock);
    00899       }
    00900       answer_sound();
    00901    }
    00902    snd_pcm_prepare(alsa.icard);
    00903    snd_pcm_start(alsa.icard);
    00904    ast_mutex_unlock(&alsalock);
    00905    return RESULT_SUCCESS;
    00906 }
    00907
    00908 static char sendtext_usage[] =
    00909 "Usage: send text <message>\n"
    00910 "       Sends a text message for display on the remote terminal.\n";
    00911
    00912 static int console_sendtext(int fd, int argc, char *argv[])
    00913 {
    00914    int tmparg = 2;
    00915    int res = RESULT_SUCCESS;
    00916    if (argc < 2)
    00917       return RESULT_SHOWUSAGE;
    00918    ast_mutex_lock(&alsalock);
    00919    if (!alsa.owner) {
    00920       ast_cli(fd, "No one is calling us\n");
    00921       res = RESULT_FAILURE;
    00922    } else {
    00923       struct ast_frame f = { AST_FRAME_TEXT, 0 };
    00924       char text2send[256] = "";
    00925       text2send[0] = '\0';
    00926       while(tmparg < argc) {
    00927          strncat(text2send, argv[tmparg++], sizeof(text2send) - strlen(text2send) - 1);
    00928          strncat(text2send, " ", sizeof(text2send) - strlen(text2send) - 1);
    00929       }
    00930       text2send[strlen(text2send) - 1] = '\n';
    00931       f.data = text2send;
    00932       f.datalen = strlen(text2send) + 1;
    00933       grab_owner();
    00934       if (alsa.owner) {
    00935          ast_queue_frame(alsa.owner, &f);
    00936          f.frametype = AST_FRAME_CONTROL;
    00937          f.subclass = AST_CONTROL_ANSWER;
    00938          f.data = NULL;
    00939          f.datalen = 0;
    00940          ast_queue_frame(alsa.owner, &f);
    00941          ast_mutex_unlock(&alsa.owner->lock);
    00942       }
    00943    }
    00944    ast_mutex_unlock(&alsalock);
    00945    return res;
    00946 }
    00947
    00948 static char answer_usage[] =
    00949 "Usage: answer\n"
    00950 "       Answers an incoming call on the console (ALSA) channel.\n";
    00951
    00952 static int console_hangup(int fd, int argc, char *argv[])
    00953 {
    00954    int res = RESULT_SUCCESS;
    00955    if (argc != 1)
    00956       return RESULT_SHOWUSAGE;
    00957    cursound = -1;
    00958    ast_mutex_lock(&alsalock);
    00959    if (!alsa.owner && !hookstate) {
    00960       ast_cli(fd, "No call to hangup up\n");
    00961       res = RESULT_FAILURE;
    00962    } else {
    00963       hookstate = 0;
    00964       grab_owner();
    00965       if (alsa.owner) {
    00966          ast_queue_hangup(alsa.owner);
    00967          ast_mutex_unlock(&alsa.owner->lock);
    00968       }
    00969    }
    00970    ast_mutex_unlock(&alsalock);
    00971    return res;
    00972 }
    00973
    00974 static char hangup_usage[] =
    00975 "Usage: hangup\n"
    00976 "       Hangs up any call currently placed on the console.\n";
    00977
    00978
    00979 static int console_dial(int fd, int argc, char *argv[])
    00980 {
    00981    char tmp[256], *tmp2;
    00982    char *mye, *myc;
    00983    char *d;
    00984    int res = RESULT_SUCCESS;
    00985    if ((argc != 1) && (argc != 2))
    00986       return RESULT_SHOWUSAGE;
    00987    ast_mutex_lock(&alsalock);
    00988    if (alsa.owner) {
    00989       if (argc == 2) {
    00990          d = argv[1];
    00991          grab_owner();
    00992          if (alsa.owner) {
    00993             struct ast_frame f = { AST_FRAME_DTMF };
    00994             while(*d) {
    00995                f.subclass = *d;
    00996                ast_queue_frame(alsa.owner, &f);
    00997                d++;
    00998             }
    00999             ast_mutex_unlock(&alsa.owner->lock);
    01000          }
    01001       } else {
    01002          ast_cli(fd, "You're already in a call.  You can use this only to dial digits until you hangup\n");
    01003          res = RESULT_FAILURE;
    01004       }
    01005    } else {
    01006       mye = exten;
    01007       myc = context;
    01008       if (argc == 2) {
    01009          char *stringp=NULL;
    01010          strncpy(tmp, argv[1], sizeof(tmp)-1);
    01011          stringp=tmp;
    01012          strsep(&stringp, "@");
    01013          tmp2 = strsep(&stringp, "@");
    01014          if (!ast_strlen_zero(tmp))
    01015             mye = tmp;
    01016          if (!ast_strlen_zero(tmp2))
    01017             myc = tmp2;
    01018       }
    01019       if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
    01020          strncpy(alsa.exten, mye, sizeof(alsa.exten)-1);
    01021          strncpy(alsa.context, myc, sizeof(alsa.context)-1);
    01022          hookstate = 1;
    01023          alsa_new(&alsa, AST_STATE_RINGING);
    01024       } else
    01025          ast_cli(fd, "No such extension '%s' in context '%s'\n", mye, myc);
    01026    }
    01027    ast_mutex_unlock(&alsalock);
    01028    return res;
    01029 }
    01030
    01031 static char dial_usage[] =
    01032 "Usage: dial [extension[@context]]\n"
    01033 "       Dials a given extension (and context if specified)\n";
    01034
    01035
    01036 static struct ast_cli_entry myclis[] = {
    01037    { { "answer", NULL }, console_answer, "Answer an incoming console call", answer_usage },
    01038    { { "hangup", NULL }, console_hangup, "Hangup a call on the console", hangup_usage },
    01039    { { "dial", NULL }, console_dial, "Dial an extension on the console", dial_usage },
    01040    { { "send", "text", NULL }, console_sendtext, "Send text to the remote device", sendtext_usage },
    01041    { { "autoanswer", NULL }, console_autoanswer, "Sets/displays autoanswer", autoanswer_usage, autoanswer_complete }
    01042 };
    01043
    01044 int load_module()
    01045 {
    01046    int res;
    01047    int x;
    01048    struct ast_config *cfg;
    01049    struct ast_variable *v;
    01050    if ((cfg = ast_config_load(config))) {
    01051       v = ast_variable_browse(cfg, "general");
    01052       while(v) {
    01053          if (!strcasecmp(v->name, "autoanswer"))
    01054             autoanswer = ast_true(v->value);
    01055          else if (!strcasecmp(v->name, "silencesuppression"))
    01056             silencesuppression = ast_true(v->value);
    01057          else if (!strcasecmp(v->name, "silencethreshold"))
    01058             silencethreshold = atoi(v->value);
    01059          else if (!strcasecmp(v->name, "context"))
    01060             strncpy(context, v->value, sizeof(context)-1);
    01061          else if (!strcasecmp(v->name, "language"))
    01062             strncpy(language, v->value, sizeof(language)-1);
    01063          else if (!strcasecmp(v->name, "extension"))
    01064             strncpy(exten, v->value, sizeof(exten)-1);
    01065          else if (!strcasecmp(v->name, "input_device"))
    01066             strncpy(indevname, v->value, sizeof(indevname)-1);
    01067          else if (!strcasecmp(v->name, "output_device"))
    01068             strncpy(outdevname, v->value, sizeof(outdevname)-1);
    01069          v=v->next;
    01070       }
    01071       ast_config_destroy(cfg);
    01072    }
    01073    res = pipe(sndcmd);
    01074    if (res) {
    01075       ast_log(LOG_ERROR, "Unable to create pipe\n");
    01076       return -1;
    01077    }
    01078    res = soundcard_init();
    01079    if (res < 0) {
    01080       if (option_verbose > 1) {
    01081          ast_verbose(VERBOSE_PREFIX_2 "No sound card detected -- console channel will be unavailable\n");
    01082          ast_verbose(VERBOSE_PREFIX_2 "Turn off ALSA support by adding 'noload=chan_alsa.so' in /etc/asterisk/modules.conf\n");
    01083       }
    01084       return 0;
    01085    }
    01086
    01087    res = ast_channel_register(&alsa_tech);
    01088    if (res < 0) {
    01089       ast_log(LOG_ERROR, "Unable to register channel class '%s'\n", type);
    01090       return -1;
    01091    }
    01092    for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
    01093       ast_cli_register(myclis + x);
    01094    ast_pthread_create(&sthread, NULL, sound_thread, NULL);
    01095 #ifdef ALSA_MONITOR
    01096    if (alsa_monitor_start()) {
    01097       ast_log(LOG_ERROR, "Problem starting Monitoring\n");
    01098    }
    01099 #endif
    01100    return 0;
    01101 }
    01102
    01103
    01104
    01105 int unload_module()
    01106 {
    01107    int x;
    01108
    01109    ast_channel_unregister(&alsa_tech);
    01110    for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
    01111       ast_cli_unregister(myclis + x);
    01112    if (alsa.icard)
    01113       snd_pcm_close(alsa.icard);
    01114    if (alsa.ocard)
    01115       snd_pcm_close(alsa.ocard);
    01116    if (sndcmd[0] > 0) {
    01117       close(sndcmd[0]);
    01118       close(sndcmd[1]);
    01119    }
    01120    if (alsa.owner)
    01121       ast_softhangup(alsa.owner, AST_SOFTHANGUP_APPUNLOAD);
    01122    if (alsa.owner)
    01123       return -1;
    01124    return 0;
    01125 }
    01126
    01127 char *description()
    01128 {
    01129    return (char *) desc;
    01130 }
    01131
    01132 int usecount()
    01133 {
    01134    return usecnt;
    01135 }
    01136
    01137 char *key()
    01138 {
    01139    return ASTERISK_GPL_KEY;
    01140 }