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 }

Generated on Wed Oct 28 15:47:50 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6