From 3b9233aa3f7a85bdf6eae1b9c733ca8f801e6980 Mon Sep 17 00:00:00 2001 From: markster Date: Sun, 4 Apr 2004 17:21:03 +0000 Subject: Merge changes from jcdutton (thanks!) git-svn-id: http://svn.digium.com/svn/asterisk/trunk@2612 f38db490-d61c-443f-a65b-d21fe96a405b --- channels/chan_alsa.c | 640 +++++++++++++++++++++++++-------------------------- 1 file changed, 311 insertions(+), 329 deletions(-) (limited to 'channels/chan_alsa.c') diff --git a/channels/chan_alsa.c b/channels/chan_alsa.c index 11cd6b269..07d8b32a1 100755 --- a/channels/chan_alsa.c +++ b/channels/chan_alsa.c @@ -36,10 +36,6 @@ #include "ring10.h" #include "answer.h" -#ifdef ALSA_MONITOR -#include "alsa-monitor.h" -#endif - #define DEBUG 0 /* Which device to use */ #define ALSA_INDEV "default" @@ -47,33 +43,21 @@ #define DESIRED_RATE 8000 /* Lets use 160 sample frames, just like GSM. */ -#define FRAME_SIZE 160 -#define PERIOD_FRAMES 80 /* 80 Frames, at 2 bytes each */ - -/* When you set the frame size, you have to come up with - the right buffer format as well. */ -/* 5 64-byte frames = one frame */ -#define BUFFER_FMT ((buffersize * 10) << 16) | (0x0006); - -/* Don't switch between read/write modes faster than every 300 ms */ -#define MIN_SWITCH_TIME 600 +#define PERIOD_SIZE 160 +#define ALSA_MAX_BUF PERIOD_SIZE*4 + AST_FRIENDLY_OFFSET static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; -//static int block = O_NONBLOCK; static char indevname[50] = ALSA_INDEV; static char outdevname[50] = ALSA_OUTDEV; -#if 0 -static struct timeval lasttime; -#endif - static int usecnt; -static int needanswer = 0; -static int needringing = 0; -static int needhangup = 0; static int silencesuppression = 0; static int silencethreshold = 1000; +#if 0 +static struct timeval lasttime; +#endif + static char digits[80] = ""; static char text2send[80] = ""; @@ -93,7 +77,7 @@ static int cmd[2]; int hookstate=0; -static short silence[FRAME_SIZE] = {0, }; +static short silence[PERIOD_SIZE] = {0, }; struct sound { int ind; @@ -115,223 +99,221 @@ static struct sound sounds[] = { /* Sound command pipe */ static int sndcmd[2]; -static struct chan_alsa_pvt { +typedef struct chan_alsa_pvt chan_alsa_pvt_t; +struct chan_alsa_pvt { /* We only have one ALSA structure -- near sighted perhaps, but it keeps this driver as simple as possible -- as it should be. */ struct ast_channel *owner; char exten[AST_MAX_EXTENSION]; char context[AST_MAX_EXTENSION]; -#if 0 - snd_pcm_t *card; -#endif - snd_pcm_t *icard, *ocard; + struct pollfd *pfd; + unsigned int playback_nfds; + unsigned int capture_nfds; + snd_pcm_t *playback_handle; + snd_pcm_t *capture_handle; + snd_pcm_uframes_t capture_period_size; + snd_pcm_uframes_t capture_buffer_size; -} alsa; - -#if 0 -static int time_has_passed(void) -{ - struct timeval tv; - int ms; - gettimeofday(&tv, NULL); - ms = (tv.tv_sec - lasttime.tv_sec) * 1000 + - (tv.tv_usec - lasttime.tv_usec) / 1000; - if (ms > MIN_SWITCH_TIME) - return -1; - return 0; -} -#endif - -/* Number of buffers... Each is FRAMESIZE/8 ms long. For example - with 160 sample frames, and a buffer size of 3, we have a 60ms buffer, - usually plenty. */ + pthread_t sound_thread; + char buf[ALSA_MAX_BUF]; /* buffer for reading frames */ + char *capture_buf; /* malloc buffer for reading frames */ + struct ast_frame fr; + int cursound; + int cursound_offset; + int nosound; +}; -pthread_t sthread; +static chan_alsa_pvt_t alsa; #define MAX_BUFFER_SIZE 100 -//static int buffersize = 3; - -//static int full_duplex = 0; - -/* Are we reading or writing (simulated full duplex) */ -//static int readmode = 1; - -/* File descriptors for sound device */ -static int readdev = -1; -static int writedev = -1; static int autoanswer = 1; -#if 0 -static int calc_loudness(short *frame) -{ - int sum = 0; - int x; - for (x=0;xcursound; snd_pcm_state_t state; if (cursound > -1) { - res = total; - if (sampsent < sounds[cursound].samplen) { - myoff=0; - while(total) { - amt = total; - if (amt > (sounds[cursound].datalen - offset)) - amt = sounds[cursound].datalen - offset; - memcpy(myframe + myoff, sounds[cursound].data + offset, amt * 2); - total -= amt; - offset += amt; - sampsent += amt; - myoff += amt; - if (offset >= sounds[cursound].datalen) - offset = 0; - } - /* Set it up for silence */ - if (sampsent >= sounds[cursound].samplen) - silencelen = sounds[cursound].silencelen; - frame = myframe; - } else { - if (silencelen > 0) { - frame = silence; - silencelen -= res; + driver->nosound=1; + state = snd_pcm_state(alsa.playback_handle); + if (state == SND_PCM_STATE_XRUN) { + snd_pcm_prepare(alsa.playback_handle); + } + frames = sounds[cursound].samplen - driver->cursound_offset; + if (frames >= PERIOD_SIZE) { + res = snd_pcm_writei(driver->playback_handle,sounds[cursound].data + (driver->cursound_offset*2), PERIOD_SIZE); + driver->cursound_offset+=PERIOD_SIZE; + } else if (frames > 0) { + res = snd_pcm_writei(driver->playback_handle,sounds[cursound].data + (driver->cursound_offset*2), frames); + res = snd_pcm_writei(driver->playback_handle,silence, PERIOD_SIZE - frames); + driver->cursound_offset+=PERIOD_SIZE; } else { + res = snd_pcm_writei(driver->playback_handle,silence, PERIOD_SIZE); + driver->cursound_offset+=PERIOD_SIZE; + } + if (driver->cursound_offset > ( sounds[cursound].samplen + sounds[cursound].silencelen ) ) { if (sounds[cursound].repeat) { - /* Start over */ - sampsent = 0; - offset = 0; + driver->cursound_offset=0; } else { - cursound = -1; - nosound = 0; + driver->cursound = -1; + driver->nosound=0; } - return 0; } } - - if (res == 0 || !frame) { return 0; +} + +static int sound_capture(chan_alsa_pvt_t *driver) +{ + struct ast_frame *fr = &driver->fr; + char *readbuf = ((char *)driver->buf) + AST_FRIENDLY_OFFSET; + snd_pcm_sframes_t err; + snd_pcm_sframes_t avail; + snd_pcm_state_t alsa_state; + + /* Update positions */ + while ((avail = snd_pcm_avail_update (driver->capture_handle)) >= PERIOD_SIZE) { + + /* capture samples from sound card */ + err = snd_pcm_readi(driver->capture_handle, readbuf, PERIOD_SIZE); + if (err == -EPIPE) { + ast_log(LOG_ERROR, "XRUN read avail=%ld\n", avail); + snd_pcm_prepare(driver->capture_handle); + alsa_state = snd_pcm_state(driver->capture_handle); + if (alsa_state == SND_PCM_STATE_PREPARED) { + snd_pcm_start(driver->capture_handle); } -#ifdef ALSA_MONITOR - alsa_monitor_write((char *)frame, res * 2); -#endif - state = snd_pcm_state(alsa.ocard); - if (state == SND_PCM_STATE_XRUN) { - snd_pcm_prepare(alsa.ocard); + continue; + } else if (err == -ESTRPIPE) { + ast_log(LOG_ERROR, "-ESTRPIPE\n"); + snd_pcm_prepare(driver->capture_handle); + alsa_state = snd_pcm_state(driver->capture_handle); + if (alsa_state == SND_PCM_STATE_PREPARED) { + snd_pcm_start(driver->capture_handle); } - res = snd_pcm_writei(alsa.ocard, frame, res); - if (res > 0) - return 0; - return 0; + continue; + } else if (err < 0) { + ast_log(LOG_ERROR, "Read error: %s\n", snd_strerror(err)); + return -1; } - return 0; + + /* Now send captures samples */ + fr->frametype = AST_FRAME_VOICE; + fr->src = type; + fr->mallocd = 0; + + fr->subclass = AST_FORMAT_SLINEAR; + fr->samples = PERIOD_SIZE; + fr->datalen = PERIOD_SIZE * 2 ; /* 16bit = X * 2 */ + fr->data = readbuf; + fr->offset = AST_FRIENDLY_OFFSET; + + if (driver->owner) ast_queue_frame(driver->owner, fr, 0); + } + return 0; /* 0 = OK, !=0 -> Error */ } -static void *sound_thread(void *unused) +static void *sound_thread(void *pvt) { - fd_set rfds; - fd_set wfds; - int max; + chan_alsa_pvt_t *driver = (chan_alsa_pvt_t *)pvt; + unsigned int nfds; + unsigned int ci; + unsigned short revents; + snd_pcm_state_t alsa_state; int res; - for(;;) { - FD_ZERO(&rfds); - FD_ZERO(&wfds); - max = sndcmd[0]; - FD_SET(sndcmd[0], &rfds); - if (cursound > -1) { - FD_SET(writedev, &wfds); - if (writedev > max) - max = writedev; + if (driver->playback_handle) { + driver->playback_nfds = + snd_pcm_poll_descriptors_count ( + driver->playback_handle); + } else { + driver->playback_nfds = 0; } -#ifdef ALSA_MONITOR - if (!alsa.owner) { - FD_SET(readdev, &rfds); - if (readdev > max) - max = readdev; + + if (driver->capture_handle) { + driver->capture_nfds = + snd_pcm_poll_descriptors_count (driver->capture_handle); + } else { + driver->capture_nfds = 0; } -#endif - res = ast_select(max + 1, &rfds, &wfds, NULL, NULL); - if (res < 1) { - ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno)); - continue; + + if (driver->pfd) { + free (driver->pfd); } -#ifdef ALSA_MONITOR - if (FD_ISSET(readdev, &rfds)) { - /* Keep the pipe going with read audio */ - snd_pcm_state_t state; - short buf[FRAME_SIZE]; - int r; - state = snd_pcm_state(alsa.ocard); - if (state == SND_PCM_STATE_XRUN) { - snd_pcm_prepare(alsa.ocard); + driver->pfd = (struct pollfd *) + malloc (sizeof (struct pollfd) * + (driver->playback_nfds + driver->capture_nfds + 2)); + + nfds = 0; + if (driver->playback_handle) { + snd_pcm_poll_descriptors (driver->playback_handle, + &driver->pfd[0], + driver->playback_nfds); + nfds += driver->playback_nfds; } - r = snd_pcm_readi(alsa.icard, buf, FRAME_SIZE); - if (r == -EPIPE) { -#if DEBUG - ast_log(LOG_ERROR, "XRUN read\n"); -#endif - snd_pcm_prepare(alsa.icard); - } else if (r == -ESTRPIPE) { - ast_log(LOG_ERROR, "-ESTRPIPE\n"); - snd_pcm_prepare(alsa.icard); - } else if (r < 0) { - ast_log(LOG_ERROR, "Read error: %s\n", snd_strerror(r)); - } else - alsa_monitor_read((char *)buf, r * 2); + ci = nfds; + + if (driver->capture_handle) { + snd_pcm_poll_descriptors (driver->capture_handle, + &driver->pfd[ci], + driver->capture_nfds); + nfds += driver->capture_nfds; } -#endif - if (FD_ISSET(sndcmd[0], &rfds)) { - read(sndcmd[0], &cursound, sizeof(cursound)); - silencelen = 0; - offset = 0; - sampsent = 0; + + while (hookstate) { + /* When no doing announcements */ + if (driver->cursound > -1) { + res = poll(&driver->pfd[0], driver->playback_nfds, -1); + } else { + res = poll(&driver->pfd[ci], driver->capture_nfds, -1); } - if (FD_ISSET(writedev, &wfds)) - if (send_sound()) + + /* When doing announcements */ + if (driver->cursound > -1) { + snd_pcm_poll_descriptors_revents(driver->playback_handle, &driver->pfd[0], driver->playback_nfds, &revents); + if (revents & POLLOUT) { + if (send_sound(driver)) { ast_log(LOG_WARNING, "Failed to write sound\n"); + } + } + } else { + snd_pcm_poll_descriptors_revents(driver->capture_handle, &driver->pfd[ci], driver->capture_nfds, &revents); + if (revents & POLLERR) { + alsa_state = snd_pcm_state(driver->capture_handle); + if (alsa_state == SND_PCM_STATE_XRUN) { + snd_pcm_prepare(driver->capture_handle); + } + alsa_state = snd_pcm_state(driver->capture_handle); + if (alsa_state == SND_PCM_STATE_PREPARED) { + snd_pcm_start(driver->capture_handle); + } + } + if (revents & POLLIN) { + if (sound_capture(driver)) { + ast_log(LOG_WARNING, "Failed to read sound\n"); + } + } + } } /* Never reached */ return NULL; } -static snd_pcm_t *alsa_card_init(char *dev, snd_pcm_stream_t stream) +static snd_pcm_t *alsa_card_init(chan_alsa_pvt_t *driver, char *dev, snd_pcm_stream_t stream) { int err; int direction; snd_pcm_t *handle = NULL; snd_pcm_hw_params_t *hwparams = NULL; snd_pcm_sw_params_t *swparams = NULL; - struct pollfd pfd; - snd_pcm_uframes_t period_size = PERIOD_FRAMES * 4; - //int period_bytes = 0; + snd_pcm_uframes_t period_size = PERIOD_SIZE; snd_pcm_uframes_t buffer_size = 0; unsigned int rate = DESIRED_RATE; - unsigned int per_min = 1; - //unsigned int per_max = 8; snd_pcm_uframes_t start_threshold, stop_threshold; err = snd_pcm_open(&handle, dev, stream, O_NONBLOCK); @@ -368,6 +350,7 @@ static snd_pcm_t *alsa_card_init(char *dev, snd_pcm_stream_t stream) } direction = 0; + buffer_size = 4096 * 2; /* period_size * 16; */ err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_size, &direction); if (err < 0) { ast_log(LOG_ERROR, "period_size(%ld frames) is bad: %s\n", period_size, snd_strerror(err)); @@ -375,7 +358,6 @@ static snd_pcm_t *alsa_card_init(char *dev, snd_pcm_stream_t stream) ast_log(LOG_DEBUG, "Period size is %d\n", err); } - buffer_size = 4096 * 2; //period_size * 16; err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &buffer_size); if (err < 0) { ast_log(LOG_WARNING, "Problem setting buffer size of %ld: %s\n", buffer_size, snd_strerror(err)); @@ -385,7 +367,7 @@ static snd_pcm_t *alsa_card_init(char *dev, snd_pcm_stream_t stream) #if 0 direction = 0; - err = snd_pcm_hw_params_set_periods_min(handle,hwparams, &per_min, &direction); + err = snd_pcm_hw_params_set_periods_min(handle, hwparams, &per_min, &direction); if (err < 0) { ast_log(LOG_ERROR, "periods_min: %s\n", snd_strerror(err)); } @@ -396,9 +378,15 @@ static snd_pcm_t *alsa_card_init(char *dev, snd_pcm_stream_t stream) } #endif + if (stream == SND_PCM_STREAM_CAPTURE) { + driver->capture_period_size=period_size; + driver->capture_buffer_size=buffer_size; + } + err = snd_pcm_hw_params(handle, hwparams); if (err < 0) { ast_log(LOG_ERROR, "Couldn't set the new hw params: %s\n", snd_strerror(err)); + return NULL; } snd_pcm_sw_params_alloca(&swparams); @@ -406,7 +394,7 @@ static snd_pcm_t *alsa_card_init(char *dev, snd_pcm_stream_t stream) #if 1 if (stream == SND_PCM_STREAM_PLAYBACK) { - start_threshold = period_size; + start_threshold = period_size*3; } else { start_threshold = 1; } @@ -421,7 +409,7 @@ static snd_pcm_t *alsa_card_init(char *dev, snd_pcm_stream_t stream) if (stream == SND_PCM_STREAM_PLAYBACK) { stop_threshold = buffer_size; } else { - stop_threshold = buffer_size; + stop_threshold = buffer_size+1; } err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold); if (err < 0) { @@ -429,7 +417,7 @@ static snd_pcm_t *alsa_card_init(char *dev, snd_pcm_stream_t stream) } #endif #if 0 - err = snd_pcm_sw_params_set_xfer_align(handle, swparams, PERIOD_FRAMES); + err = snd_pcm_sw_params_set_xfer_align(handle, swparams, PERIOD_SIZE); if (err < 0) { ast_log(LOG_ERROR, "Unable to set xfer alignment: %s\n", snd_strerror(err)); } @@ -455,28 +443,25 @@ static snd_pcm_t *alsa_card_init(char *dev, snd_pcm_stream_t stream) ast_log(LOG_DEBUG, "Can't handle more than one device\n"); } - snd_pcm_poll_descriptors(handle, &pfd, err); - ast_log(LOG_DEBUG, "Acquired fd %d from the poll descriptor\n", pfd.fd); - - if (stream == SND_PCM_STREAM_CAPTURE) - readdev = pfd.fd; - else - writedev = pfd.fd; - return handle; } static int soundcard_init(void) { - alsa.icard = alsa_card_init(indevname, SND_PCM_STREAM_CAPTURE); - alsa.ocard = alsa_card_init(outdevname, SND_PCM_STREAM_PLAYBACK); + alsa.capture_handle = alsa_card_init(&alsa, indevname, SND_PCM_STREAM_CAPTURE); + alsa.playback_handle = alsa_card_init(&alsa, outdevname, SND_PCM_STREAM_PLAYBACK); + if (!alsa.capture_buf) alsa.capture_buf=malloc(alsa.capture_buffer_size * 2); - if (!alsa.icard || !alsa.ocard) { + if (!alsa.capture_handle || !alsa.playback_handle) { ast_log(LOG_ERROR, "Problem opening alsa I/O devices\n"); + if (alsa.capture_buf) { + free (alsa.capture_buf); + alsa.capture_buf=0; + } return -1; } - return readdev; + return 0; /* Success */ } static int alsa_digit(struct ast_channel *c, char digit) @@ -493,135 +478,96 @@ static int alsa_text(struct ast_channel *c, char *text) static int alsa_call(struct ast_channel *c, char *dest, int timeout) { + chan_alsa_pvt_t *driver = (chan_alsa_pvt_t *)c->pvt->pvt; int res = 3; + struct ast_frame f = { 0, }; ast_verbose( " << Call placed to '%s' on console >> \n", dest); if (autoanswer) { ast_verbose( " << Auto-answered >> \n" ); - needanswer = 1; + f.frametype = AST_FRAME_CONTROL; + f.subclass = AST_CONTROL_ANSWER; + ast_queue_frame(c, &f, 0); } else { + driver->nosound = 1; ast_verbose( " << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n"); - needringing = 1; - write(sndcmd[1], &res, sizeof(res)); + f.frametype = AST_FRAME_CONTROL; + f.subclass = AST_CONTROL_RINGING; + ast_queue_frame(c, &f, 0); + driver->cursound = res; } return 0; } -static void answer_sound(void) +static void answer_sound(chan_alsa_pvt_t *driver) { int res; - nosound = 1; - res = 4; - write(sndcmd[1], &res, sizeof(res)); + driver->nosound = 1; + driver->cursound = 4; + driver->cursound_offset = 0; } static int alsa_answer(struct ast_channel *c) { + chan_alsa_pvt_t *driver = (chan_alsa_pvt_t *)c->pvt->pvt; ast_verbose( " << Console call has been answered >> \n"); - answer_sound(); + answer_sound(driver); ast_setstate(c, AST_STATE_UP); - cursound = -1; return 0; } +/* The new_channel is now freed. */ static int alsa_hangup(struct ast_channel *c) { int res; - cursound = -1; + chan_alsa_pvt_t *driver = (chan_alsa_pvt_t *)c->pvt->pvt; + + driver->cursound = -1; + driver->nosound = 0; + if (hookstate) { + hookstate = 0; + } + pthread_join(driver->sound_thread, NULL); +/* snd_pcm_drain(driver->capture_handle); */ + driver->owner = NULL; c->pvt->pvt = NULL; - alsa.owner = NULL; ast_verbose( " << Hangup on console >> \n"); ast_mutex_lock(&usecnt_lock); usecnt--; ast_mutex_unlock(&usecnt_lock); - needhangup = 0; - needanswer = 0; - if (hookstate) { - res = 2; - write(sndcmd[1], &res, sizeof(res)); - } return 0; } -#if 0 -static int soundcard_writeframe(short *data) -{ - /* Write an exactly FRAME_SIZE sized of frame */ - static int bufcnt = 0; - static short buffer[FRAME_SIZE * MAX_BUFFER_SIZE * 5]; - struct audio_buf_info info; - int res; - int fd = sounddev; - static int warned=0; - if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info)) { - if (!warned) - ast_log(LOG_WARNING, "Error reading output space\n"); - bufcnt = buffersize; - warned++; - } - if ((info.fragments >= buffersize * 5) && (bufcnt == buffersize)) { - /* We've run out of stuff, buffer again */ - bufcnt = 0; - } - if (bufcnt == buffersize) { - /* Write sample immediately */ - res = write(fd, ((void *)data), FRAME_SIZE * 2); - } else { - /* Copy the data into our buffer */ - res = FRAME_SIZE * 2; - memcpy(buffer + (bufcnt * FRAME_SIZE), data, FRAME_SIZE * 2); - bufcnt++; - if (bufcnt == buffersize) { - res = write(fd, ((void *)buffer), FRAME_SIZE * 2 * buffersize); - } - } - return res; -} -#endif - static int alsa_write(struct ast_channel *chan, struct ast_frame *f) { + chan_alsa_pvt_t *driver = (chan_alsa_pvt_t *)chan->pvt->pvt; int res; static char sizbuf[8000]; static int sizpos = 0; int len = sizpos; int pos; - //size_t frames = 0; snd_pcm_state_t state; - /* Immediately return if no sound is enabled */ - if (nosound) - return 0; - /* Stop any currently playing sound */ - if (cursound != -1) { - snd_pcm_drop(alsa.ocard); - snd_pcm_prepare(alsa.ocard); - cursound = -1; - } - + snd_pcm_sframes_t delay = 0; - /* We have to digest the frame in 160-byte portions */ - if (f->datalen > sizeof(sizbuf) - sizpos) { - ast_log(LOG_WARNING, "Frame too large\n"); - return -1; + if (driver->nosound) { + return 0; } - memcpy(sizbuf + sizpos, f->data, f->datalen); - len += f->datalen; - pos = 0; -#ifdef ALSA_MONITOR - alsa_monitor_write(sizbuf, len); -#endif - state = snd_pcm_state(alsa.ocard); + state = snd_pcm_state(driver->playback_handle); if (state == SND_PCM_STATE_XRUN) { - snd_pcm_prepare(alsa.ocard); + snd_pcm_prepare(driver->playback_handle); } - res = snd_pcm_writei(alsa.ocard, sizbuf, len/2); + res = snd_pcm_delay( driver->playback_handle, &delay ); + if (delay > 4 * PERIOD_SIZE) { + return 0; + } + res = snd_pcm_writei(driver->playback_handle, f->data, f->samples); if (res == -EPIPE) { #if DEBUG ast_log(LOG_DEBUG, "XRUN write\n"); #endif - snd_pcm_prepare(alsa.ocard); - res = snd_pcm_writei(alsa.ocard, sizbuf, len/2); - if (res != len/2) { + snd_pcm_prepare(driver->playback_handle); + res = snd_pcm_writei(driver->playback_handle, f->data, f->samples); + if (res != f->samples) { ast_log(LOG_ERROR, "Write error: %s\n", snd_strerror(res)); return -1; } else if (res < 0) { @@ -641,21 +587,26 @@ static int alsa_write(struct ast_channel *chan, struct ast_frame *f) static struct ast_frame *alsa_read(struct ast_channel *chan) { static struct ast_frame f; - static short __buf[FRAME_SIZE + AST_FRIENDLY_OFFSET/2]; + static short __buf[PERIOD_SIZE + AST_FRIENDLY_OFFSET/2]; short *buf; static int readpos = 0; - static int left = FRAME_SIZE; + static int left = PERIOD_SIZE; int res; int b; int nonull=0; snd_pcm_state_t state; int r = 0; int off = 0; - + /* FIXME: This should never been called */ + ast_log(LOG_WARNING, "ALSA_READ!!!!!\n"); + return NULL; +} +#if 0 /* Acknowledge any pending cmd */ res = read(cmd[0], &b, sizeof(b)); if (res > 0) nonull = 1; + ast_log(LOG_WARNING, "alsa: %s:%d\n", __FUNCTION__, __LINE__); f.frametype = AST_FRAME_NULL; f.subclass = 0; @@ -672,11 +623,13 @@ static struct ast_frame *alsa_read(struct ast_channel *chan) needringing = 0; return &f; } + ast_log(LOG_WARNING, "alsa: %s:%d\n", __FUNCTION__, __LINE__); if (needhangup) { needhangup = 0; return NULL; } + ast_log(LOG_WARNING, "alsa: %s:%d\n", __FUNCTION__, __LINE__); if (strlen(text2send)) { f.frametype = AST_FRAME_TEXT; f.subclass = 0; @@ -685,6 +638,7 @@ static struct ast_frame *alsa_read(struct ast_channel *chan) strcpy(text2send,""); return &f; } + ast_log(LOG_WARNING, "alsa: %s:%d\n", __FUNCTION__, __LINE__); if (strlen(digits)) { f.frametype = AST_FRAME_DTMF; f.subclass = digits[0]; @@ -693,6 +647,7 @@ static struct ast_frame *alsa_read(struct ast_channel *chan) return &f; } + ast_log(LOG_WARNING, "alsa: %s:%d\n", __FUNCTION__, __LINE__); if (needanswer) { needanswer = 0; f.frametype = AST_FRAME_CONTROL; @@ -701,26 +656,29 @@ static struct ast_frame *alsa_read(struct ast_channel *chan) return &f; } + ast_log(LOG_WARNING, "alsa: %s:%d\n", __FUNCTION__, __LINE__); if (nonull) return &f; + ast_log(LOG_WARNING, "alsa: %s:%d\n", __FUNCTION__, __LINE__); - state = snd_pcm_state(alsa.ocard); + state = snd_pcm_state(alsa.playback_handle); if (state == SND_PCM_STATE_XRUN) { - snd_pcm_prepare(alsa.ocard); + snd_pcm_prepare(alsa.playback_handle); } + ast_log(LOG_WARNING, "alsa: %s:%d\n", __FUNCTION__, __LINE__); buf = __buf + AST_FRIENDLY_OFFSET/2; - r = snd_pcm_readi(alsa.icard, buf + readpos, left); + r = snd_pcm_readi(alsa.capture_handle, buf + readpos, left); if (r == -EPIPE) { #if DEBUG ast_log(LOG_ERROR, "XRUN read\n"); #endif - snd_pcm_prepare(alsa.icard); + snd_pcm_prepare(alsa.capture_handle); } else if (r == -ESTRPIPE) { ast_log(LOG_ERROR, "-ESTRPIPE\n"); - snd_pcm_prepare(alsa.icard); + snd_pcm_prepare(alsa.capture_handle); } else if (r < 0) { ast_log(LOG_ERROR, "Read error: %s\n", snd_strerror(r)); return NULL; @@ -731,25 +689,22 @@ static struct ast_frame *alsa_read(struct ast_channel *chan) readpos += r; left -= r; - if (readpos >= FRAME_SIZE) { + if (readpos >= PERIOD_SIZE) { /* A real frame */ readpos = 0; - left = FRAME_SIZE; + left = PERIOD_SIZE; if (chan->_state != AST_STATE_UP) { /* Don't transmit unless it's up */ return &f; } f.frametype = AST_FRAME_VOICE; f.subclass = AST_FORMAT_SLINEAR; - f.samples = FRAME_SIZE; - f.datalen = FRAME_SIZE * 2; + f.samples = PERIOD_SIZE; + f.datalen = PERIOD_SIZE * 2; f.data = buf; f.offset = AST_FRIENDLY_OFFSET; f.src = type; f.mallocd = 0; -#ifdef ALSA_MONITOR - alsa_monitor_read((char *)buf, FRAME_SIZE * 2); -#endif #if 0 { static int fd = -1; @@ -761,6 +716,7 @@ static struct ast_frame *alsa_read(struct ast_channel *chan) } return &f; } +#endif static int alsa_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, int needlock) { @@ -771,6 +727,7 @@ static int alsa_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, static int alsa_indicate(struct ast_channel *chan, int cond) { + chan_alsa_pvt_t *driver = (chan_alsa_pvt_t *)chan->pvt->pvt; int res; switch(cond) { case AST_CONTROL_BUSY: @@ -787,20 +744,25 @@ static int alsa_indicate(struct ast_channel *chan, int cond) return -1; } if (res > -1) { - write(sndcmd[1], &res, sizeof(res)); + driver->cursound = res; + driver->cursound_offset = 0; + driver->nosound = 1; } return 0; } +/* New channel is about to be used */ static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state) { struct ast_channel *tmp; + snd_pcm_state_t alsa_state; + if (!p->capture_handle || !p->playback_handle) { + return 0; + } tmp = ast_channel_alloc(1); if (tmp) { snprintf(tmp->name, sizeof(tmp->name), "ALSA/%s", indevname); tmp->type = type; - tmp->fds[0] = readdev; - tmp->fds[1] = cmd[0]; tmp->nativeformats = AST_FORMAT_SLINEAR; tmp->pvt->pvt = p; tmp->pvt->send_digit = alsa_digit; @@ -819,6 +781,7 @@ static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state) if (strlen(language)) strncpy(tmp->language, language, sizeof(tmp->language)-1); p->owner = tmp; + p->pfd = NULL; ast_setstate(tmp, state); ast_mutex_lock(&usecnt_lock); usecnt++; @@ -831,6 +794,15 @@ static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state) tmp = NULL; } } + pthread_create(&p->sound_thread, NULL, sound_thread, (void *) p); + alsa_state = snd_pcm_state(p->capture_handle); + if (alsa_state == SND_PCM_STATE_XRUN) { + snd_pcm_prepare(p->capture_handle); + } + alsa_state = snd_pcm_state(p->capture_handle); + if (alsa_state == SND_PCM_STATE_PREPARED) { + snd_pcm_start(p->capture_handle); + } } return tmp; } @@ -899,6 +871,7 @@ static char autoanswer_usage[] = static int console_answer(int fd, int argc, char *argv[]) { + struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; if (argc != 1) return RESULT_SHOWUSAGE; if (!alsa.owner) { @@ -906,9 +879,8 @@ static int console_answer(int fd, int argc, char *argv[]) return RESULT_FAILURE; } hookstate = 1; - cursound = -1; - needanswer++; - answer_sound(); + ast_queue_frame(alsa.owner, &f, 1); + answer_sound(&alsa); return RESULT_SUCCESS; } @@ -919,6 +891,7 @@ static char sendtext_usage[] = static int console_sendtext(int fd, int argc, char *argv[]) { int tmparg = 2; + struct ast_frame f = { 0, }; if (argc < 2) return RESULT_SHOWUSAGE; if (!alsa.owner) { @@ -932,7 +905,13 @@ static int console_sendtext(int fd, int argc, char *argv[]) strncat(text2send, argv[tmparg++], sizeof(text2send) - strlen(text2send)); strncat(text2send, " ", sizeof(text2send) - strlen(text2send)); } - needanswer++; + if (strlen(text2send)) { + f.frametype = AST_FRAME_TEXT; + f.subclass = 0; + f.data = text2send; + f.datalen = strlen(text2send); + ast_queue_frame(alsa.owner, &f, 1); + } return RESULT_SUCCESS; } @@ -944,7 +923,8 @@ static int console_hangup(int fd, int argc, char *argv[]) { if (argc != 1) return RESULT_SHOWUSAGE; - cursound = -1; + alsa.cursound = -1; + alsa.nosound = 0; if (!alsa.owner && !hookstate) { ast_cli(fd, "No call to hangup up\n"); return RESULT_FAILURE; @@ -966,13 +946,16 @@ static int console_dial(int fd, int argc, char *argv[]) char tmp[256], *tmp2; char *mye, *myc; int b = 0; + int x; + struct ast_frame f = { AST_FRAME_DTMF, 0 }; if ((argc != 1) && (argc != 2)) return RESULT_SHOWUSAGE; if (alsa.owner) { if (argc == 2) { - strncat(digits, argv[1], sizeof(digits) - strlen(digits)); - /* Wake up the polling thread */ - write(cmd[1], &b, sizeof(b)); + for (x=0;x 1) { - ast_verbose(VERBOSE_PREFIX_2 "No sound card detected -- console channel will be unavailable\n"); - ast_verbose(VERBOSE_PREFIX_2 "Turn off ALSA support by adding 'noload=chan_alsa.so' in /etc/asterisk/modules.conf\n"); - } - return 0; - } +#endif #if 0 if (!full_duplex) ast_log(LOG_WARNING, "XXX I don't work right with non-full duplex sound cards XXX\n"); @@ -1068,20 +1044,24 @@ int load_module() strncpy(language, v->value, sizeof(language)-1); else if (!strcasecmp(v->name, "extension")) strncpy(exten, v->value, sizeof(exten)-1); - else if (!strcasecmp(v->name, "input_device")) + else if (!strcasecmp(v->name, "input_device")) { strncpy(indevname, v->value, sizeof(indevname)-1); - else if (!strcasecmp(v->name, "output_device")) + } else if (!strcasecmp(v->name, "output_device")) strncpy(outdevname, v->value, sizeof(outdevname)-1); v=v->next; } ast_destroy(cfg); } - pthread_create(&sthread, NULL, sound_thread, NULL); -#ifdef ALSA_MONITOR - if (alsa_monitor_start()) { - ast_log(LOG_ERROR, "Problem starting Monitoring\n"); + res = soundcard_init(); + if (res < 0) { + close(cmd[1]); + close(cmd[0]); + if (option_verbose > 1) { + ast_verbose(VERBOSE_PREFIX_2 "No sound card detected -- console channel will be unavailable\n"); + ast_verbose(VERBOSE_PREFIX_2 "Turn off ALSA support by adding 'noload=chan_alsa.so' in /etc/asterisk/modules.conf\n"); + } + return 0; } -#endif return 0; } @@ -1092,8 +1072,6 @@ int unload_module() int x; for (x=0;x 0) { close(cmd[0]); close(cmd[1]); @@ -1106,6 +1084,10 @@ int unload_module() ast_softhangup(alsa.owner, AST_SOFTHANGUP_APPUNLOAD); if (alsa.owner) return -1; + if (alsa.capture_buf) { + free (alsa.capture_buf); + alsa.capture_buf=0; + } return 0; } -- cgit v1.2.3