improve chan_usbradio to use indications just like chan_alsa/chan_oss do now
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@96621 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
parent
26729a461a
commit
99893cdf53
|
@ -114,12 +114,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||||
#include "asterisk/musiconhold.h"
|
#include "asterisk/musiconhold.h"
|
||||||
#include "asterisk/dsp.h"
|
#include "asterisk/dsp.h"
|
||||||
|
|
||||||
/* ringtones we use */
|
|
||||||
#include "busy.h"
|
|
||||||
#include "ringtone.h"
|
|
||||||
#include "ring10.h"
|
|
||||||
#include "answer.h"
|
|
||||||
|
|
||||||
#define C108_VENDOR_ID 0x0d8c
|
#define C108_VENDOR_ID 0x0d8c
|
||||||
#define C108_PRODUCT_ID 0x000c
|
#define C108_PRODUCT_ID 0x000c
|
||||||
#define C108_HID_INTERFACE 3
|
#define C108_HID_INTERFACE 3
|
||||||
|
@ -285,31 +279,6 @@ enum {TOC_NONE,TOC_PHASE,TOC_NOTONE};
|
||||||
|
|
||||||
/* DECLARE STRUCTURES */
|
/* DECLARE STRUCTURES */
|
||||||
|
|
||||||
/*
|
|
||||||
* Each sound is made of 'datalen' samples of sound, repeated as needed to
|
|
||||||
* generate 'samplen' samples of data, then followed by 'silencelen' samples
|
|
||||||
* of silence. The loop is repeated if 'repeat' is set.
|
|
||||||
*/
|
|
||||||
struct sound {
|
|
||||||
int ind;
|
|
||||||
char *desc;
|
|
||||||
short *data;
|
|
||||||
int datalen;
|
|
||||||
int samplen;
|
|
||||||
int silencelen;
|
|
||||||
int repeat;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct sound sounds[] = {
|
|
||||||
{ AST_CONTROL_RINGING, "RINGING", ringtone, sizeof(ringtone)/2, 16000, 32000, 1 },
|
|
||||||
{ AST_CONTROL_BUSY, "BUSY", busy, sizeof(busy)/2, 4000, 4000, 1 },
|
|
||||||
{ AST_CONTROL_CONGESTION, "CONGESTION", busy, sizeof(busy)/2, 2000, 2000, 1 },
|
|
||||||
{ AST_CONTROL_RING, "RING10", ring10, sizeof(ring10)/2, 16000, 32000, 1 },
|
|
||||||
{ AST_CONTROL_ANSWER, "ANSWER", answer, sizeof(answer)/2, 2200, 0, 0 },
|
|
||||||
{ -1, NULL, 0, 0, 0, 0 }, /* end marker */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* descriptor for one of our channels.
|
* descriptor for one of our channels.
|
||||||
* There is one used for 'default' values (from the [general] entry in
|
* There is one used for 'default' values (from the [general] entry in
|
||||||
|
@ -321,17 +290,6 @@ struct chan_usbradio_pvt {
|
||||||
struct chan_usbradio_pvt *next;
|
struct chan_usbradio_pvt *next;
|
||||||
|
|
||||||
char *name;
|
char *name;
|
||||||
/*
|
|
||||||
* cursound indicates which in struct sound we play. -1 means nothing,
|
|
||||||
* any other value is a valid sound, in which case sampsent indicates
|
|
||||||
* the next sample to send in [0..samplen + silencelen]
|
|
||||||
* nosound is set to disable the audio data from the channel
|
|
||||||
* (so we can play the tones etc.).
|
|
||||||
*/
|
|
||||||
int sndcmd[2]; /* Sound command pipe */
|
|
||||||
int cursound; /* index of sound to send */
|
|
||||||
int sampsent; /* # of sound samples sent */
|
|
||||||
int nosound; /* set to block audio from the PBX */
|
|
||||||
|
|
||||||
int total_blocks; /* total blocks in the output device */
|
int total_blocks; /* total blocks in the output device */
|
||||||
int sounddev;
|
int sounddev;
|
||||||
|
@ -460,7 +418,6 @@ struct chan_usbradio_pvt {
|
||||||
|
|
||||||
/* maw add additional defaults !!! */
|
/* maw add additional defaults !!! */
|
||||||
static struct chan_usbradio_pvt usbradio_default = {
|
static struct chan_usbradio_pvt usbradio_default = {
|
||||||
.cursound = -1,
|
|
||||||
.sounddev = -1,
|
.sounddev = -1,
|
||||||
.duplex = M_UNSET, /* XXX check this */
|
.duplex = M_UNSET, /* XXX check this */
|
||||||
.autoanswer = 1,
|
.autoanswer = 1,
|
||||||
|
@ -875,129 +832,6 @@ static int soundcard_writeframe(struct chan_usbradio_pvt *o, short *data)
|
||||||
return write(o->sounddev, ((void *) data), FRAME_SIZE * 2 * 12);
|
return write(o->sounddev, ((void *) data), FRAME_SIZE * 2 * 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief
|
|
||||||
* Handler for 'sound writable' events from the sound thread.
|
|
||||||
* Builds a frame from the high level description of the sounds,
|
|
||||||
* and passes it to the audio device.
|
|
||||||
* The actual sound is made of 1 or more sequences of sound samples
|
|
||||||
* (s->datalen, repeated to make s->samplen samples) followed by
|
|
||||||
* s->silencelen samples of silence. The position in the sequence is stored
|
|
||||||
* in o->sampsent, which goes between 0 .. s->samplen+s->silencelen.
|
|
||||||
* In case we fail to write a frame, don't update o->sampsent.
|
|
||||||
*/
|
|
||||||
static void send_sound(struct chan_usbradio_pvt *o)
|
|
||||||
{
|
|
||||||
short myframe[FRAME_SIZE];
|
|
||||||
int ofs, l, start;
|
|
||||||
int l_sampsent = o->sampsent;
|
|
||||||
struct sound *s;
|
|
||||||
|
|
||||||
if (o->cursound < 0) /* no sound to send */
|
|
||||||
return;
|
|
||||||
|
|
||||||
s = &sounds[o->cursound];
|
|
||||||
|
|
||||||
for (ofs = 0; ofs < FRAME_SIZE; ofs += l) {
|
|
||||||
l = s->samplen - l_sampsent; /* # of available samples */
|
|
||||||
if (l > 0) {
|
|
||||||
start = l_sampsent % s->datalen; /* source offset */
|
|
||||||
if (l > FRAME_SIZE - ofs) /* don't overflow the frame */
|
|
||||||
l = FRAME_SIZE - ofs;
|
|
||||||
if (l > s->datalen - start) /* don't overflow the source */
|
|
||||||
l = s->datalen - start;
|
|
||||||
memcpy(myframe + ofs, s->data + start, l * 2);
|
|
||||||
ast_debug(4, "send_sound sound %d/%d of %d into %d\n", l_sampsent, l, s->samplen, ofs);
|
|
||||||
l_sampsent += l;
|
|
||||||
} else { /* end of samples, maybe some silence */
|
|
||||||
static const short silence[FRAME_SIZE] = { 0, };
|
|
||||||
|
|
||||||
l += s->silencelen;
|
|
||||||
if (l > 0) {
|
|
||||||
if (l > FRAME_SIZE - ofs)
|
|
||||||
l = FRAME_SIZE - ofs;
|
|
||||||
memcpy(myframe + ofs, silence, l * 2);
|
|
||||||
l_sampsent += l;
|
|
||||||
} else { /* silence is over, restart sound if loop */
|
|
||||||
if (s->repeat == 0) { /* last block */
|
|
||||||
o->cursound = -1;
|
|
||||||
o->nosound = 0; /* allow audio data */
|
|
||||||
if (ofs < FRAME_SIZE) /* pad with silence */
|
|
||||||
memcpy(myframe + ofs, silence, (FRAME_SIZE - ofs) * 2);
|
|
||||||
}
|
|
||||||
l_sampsent = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
l = soundcard_writeframe(o, myframe);
|
|
||||||
if (l > 0)
|
|
||||||
o->sampsent = l_sampsent; /* update status */
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *sound_thread(void *arg)
|
|
||||||
{
|
|
||||||
char ign[4096];
|
|
||||||
struct chan_usbradio_pvt *o = arg;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Just in case, kick the driver by trying to read from it.
|
|
||||||
* Ignore errors - this read is almost guaranteed to fail.
|
|
||||||
*/
|
|
||||||
read(o->sounddev, ign, sizeof(ign));
|
|
||||||
for (;;) {
|
|
||||||
fd_set rfds, wfds;
|
|
||||||
int maxfd, res;
|
|
||||||
|
|
||||||
FD_ZERO(&rfds);
|
|
||||||
FD_ZERO(&wfds);
|
|
||||||
FD_SET(o->sndcmd[0], &rfds);
|
|
||||||
maxfd = o->sndcmd[0]; /* pipe from the main process */
|
|
||||||
if (o->cursound > -1 && o->sounddev < 0)
|
|
||||||
setformat(o, O_RDWR); /* need the channel, try to reopen */
|
|
||||||
else if (o->cursound == -1 && o->owner == NULL)
|
|
||||||
setformat(o, O_CLOSE); /* can close */
|
|
||||||
if (o->sounddev > -1) {
|
|
||||||
if (!o->owner) { /* no one owns the audio, so we must drain it */
|
|
||||||
FD_SET(o->sounddev, &rfds);
|
|
||||||
maxfd = MAX(o->sounddev, maxfd);
|
|
||||||
}
|
|
||||||
if (o->cursound > -1) {
|
|
||||||
FD_SET(o->sounddev, &wfds);
|
|
||||||
maxfd = MAX(o->sounddev, maxfd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* ast_select emulates linux behaviour in terms of timeout handling */
|
|
||||||
res = ast_select(maxfd + 1, &rfds, &wfds, NULL, NULL);
|
|
||||||
if (res < 1) {
|
|
||||||
ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno));
|
|
||||||
sleep(1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (FD_ISSET(o->sndcmd[0], &rfds)) {
|
|
||||||
/* read which sound to play from the pipe */
|
|
||||||
int i, what = -1;
|
|
||||||
|
|
||||||
read(o->sndcmd[0], &what, sizeof(what));
|
|
||||||
for (i = 0; sounds[i].ind != -1; i++) {
|
|
||||||
if (sounds[i].ind == what) {
|
|
||||||
o->cursound = i;
|
|
||||||
o->sampsent = 0;
|
|
||||||
o->nosound = 1; /* block audio from pbx */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sounds[i].ind == -1)
|
|
||||||
ast_log(LOG_WARNING, "invalid sound index: %d\n", what);
|
|
||||||
}
|
|
||||||
if (o->sounddev > -1) {
|
|
||||||
if (FD_ISSET(o->sounddev, &rfds)) /* read and ignore errors */
|
|
||||||
read(o->sounddev, ign, sizeof(ign));
|
|
||||||
if (FD_ISSET(o->sounddev, &wfds))
|
|
||||||
send_sound(o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL; /* Never reached */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* reset and close the device if opened,
|
* reset and close the device if opened,
|
||||||
* then open and initialize it in the desired mode,
|
* then open and initialize it in the desired mode,
|
||||||
|
@ -1125,12 +959,6 @@ static int usbradio_text(struct ast_channel *c, const char *text)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Play ringtone 'x' on device 'o' */
|
|
||||||
static void ring(struct chan_usbradio_pvt *o, int x)
|
|
||||||
{
|
|
||||||
write(o->sndcmd[1], &x, sizeof(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* handler for incoming calls. Either autoanswer, or start ringing
|
* handler for incoming calls. Either autoanswer, or start ringing
|
||||||
*/
|
*/
|
||||||
|
@ -1149,11 +977,8 @@ static int usbradio_call(struct ast_channel *c, char *dest, int timeout)
|
||||||
*/
|
*/
|
||||||
static int usbradio_answer(struct ast_channel *c)
|
static int usbradio_answer(struct ast_channel *c)
|
||||||
{
|
{
|
||||||
struct chan_usbradio_pvt *o = c->tech_pvt;
|
|
||||||
|
|
||||||
ast_setstate(c, AST_STATE_UP);
|
ast_setstate(c, AST_STATE_UP);
|
||||||
o->cursound = -1;
|
|
||||||
o->nosound = 0;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1161,8 +986,6 @@ static int usbradio_hangup(struct ast_channel *c)
|
||||||
{
|
{
|
||||||
struct chan_usbradio_pvt *o = c->tech_pvt;
|
struct chan_usbradio_pvt *o = c->tech_pvt;
|
||||||
|
|
||||||
o->cursound = -1;
|
|
||||||
o->nosound = 0;
|
|
||||||
c->tech_pvt = NULL;
|
c->tech_pvt = NULL;
|
||||||
o->owner = NULL;
|
o->owner = NULL;
|
||||||
ast_module_unref(ast_module_info->self);
|
ast_module_unref(ast_module_info->self);
|
||||||
|
@ -1171,9 +994,6 @@ static int usbradio_hangup(struct ast_channel *c)
|
||||||
/* Assume auto-hangup too */
|
/* Assume auto-hangup too */
|
||||||
o->hookstate = 0;
|
o->hookstate = 0;
|
||||||
setformat(o, O_CLOSE);
|
setformat(o, O_CLOSE);
|
||||||
} else {
|
|
||||||
/* Make congestion noise */
|
|
||||||
ring(o, AST_CONTROL_CONGESTION);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
o->stophid = 1;
|
o->stophid = 1;
|
||||||
|
@ -1190,11 +1010,6 @@ static int usbradio_write(struct ast_channel *c, struct ast_frame *f)
|
||||||
|
|
||||||
traceusb2("usbradio_write() o->nosound=%d\n", o->nosound); /*sph maw asdf */
|
traceusb2("usbradio_write() o->nosound=%d\n", o->nosound); /*sph maw asdf */
|
||||||
|
|
||||||
/* Immediately return if no sound is enabled */
|
|
||||||
if (o->nosound)
|
|
||||||
return 0;
|
|
||||||
/* Stop any currently playing sound */
|
|
||||||
o->cursound = -1;
|
|
||||||
/*
|
/*
|
||||||
* we could receive a block which is not a multiple of our
|
* we could receive a block which is not a multiple of our
|
||||||
* FRAME_SIZE, so buffer it locally and write to the device
|
* FRAME_SIZE, so buffer it locally and write to the device
|
||||||
|
@ -1417,56 +1232,43 @@ static int usbradio_fixup(struct ast_channel *oldchan, struct ast_channel *newch
|
||||||
static int usbradio_indicate(struct ast_channel *c, int cond, const void *data, size_t datalen)
|
static int usbradio_indicate(struct ast_channel *c, int cond, const void *data, size_t datalen)
|
||||||
{
|
{
|
||||||
struct chan_usbradio_pvt *o = c->tech_pvt;
|
struct chan_usbradio_pvt *o = c->tech_pvt;
|
||||||
int res = -1;
|
int res = 0;
|
||||||
|
|
||||||
switch (cond) {
|
switch (cond) {
|
||||||
case AST_CONTROL_BUSY:
|
case AST_CONTROL_BUSY:
|
||||||
case AST_CONTROL_CONGESTION:
|
case AST_CONTROL_CONGESTION:
|
||||||
case AST_CONTROL_RINGING:
|
case AST_CONTROL_RINGING:
|
||||||
res = cond;
|
case -1:
|
||||||
break;
|
res = -1;
|
||||||
|
break;
|
||||||
case -1:
|
case AST_CONTROL_PROGRESS:
|
||||||
o->cursound = -1;
|
case AST_CONTROL_PROCEEDING:
|
||||||
o->nosound = 0; /* when cursound is -1 nosound must be 0 */
|
case AST_CONTROL_VIDUPDATE:
|
||||||
return 0;
|
break;
|
||||||
|
case AST_CONTROL_HOLD:
|
||||||
case AST_CONTROL_VIDUPDATE:
|
ast_verbose(" << Console Has Been Placed on Hold >> \n");
|
||||||
res = -1;
|
ast_moh_start(c, data, o->mohinterpret);
|
||||||
break;
|
break;
|
||||||
case AST_CONTROL_HOLD:
|
case AST_CONTROL_UNHOLD:
|
||||||
ast_verbose(" << Console Has Been Placed on Hold >> \n");
|
ast_verbose(" << Console Has Been Retrieved from Hold >> \n");
|
||||||
ast_moh_start(c, data, o->mohinterpret);
|
ast_moh_stop(c);
|
||||||
break;
|
break;
|
||||||
case AST_CONTROL_UNHOLD:
|
case AST_CONTROL_RADIO_KEY:
|
||||||
ast_verbose(" << Console Has Been Retrieved from Hold >> \n");
|
o->txkeyed = 1;
|
||||||
ast_moh_stop(c);
|
if (o->debuglevel)
|
||||||
break;
|
ast_verbose(" << Radio Transmit On. >> \n");
|
||||||
case AST_CONTROL_PROCEEDING:
|
break;
|
||||||
ast_verbose(" << Call Proceeding... >> \n");
|
case AST_CONTROL_RADIO_UNKEY:
|
||||||
ast_moh_stop(c);
|
o->txkeyed = 0;
|
||||||
break;
|
if (o->debuglevel)
|
||||||
case AST_CONTROL_PROGRESS:
|
ast_verbose(" << Radio Transmit Off. >> \n");
|
||||||
ast_verbose(" << Call Progress... >> \n");
|
break;
|
||||||
ast_moh_stop(c);
|
default:
|
||||||
break;
|
ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, c->name);
|
||||||
case AST_CONTROL_RADIO_KEY:
|
return -1;
|
||||||
o->txkeyed = 1;
|
|
||||||
if(o->debuglevel)ast_verbose(" << Radio Transmit On. >> \n");
|
|
||||||
break;
|
|
||||||
case AST_CONTROL_RADIO_UNKEY:
|
|
||||||
o->txkeyed = 0;
|
|
||||||
if(o->debuglevel)ast_verbose(" << Radio Transmit Off. >> \n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, c->name);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res > -1)
|
return res;
|
||||||
ring(o, res);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2523,25 +2325,12 @@ static struct chan_usbradio_pvt *store_config(struct ast_config *cfg, char *ctg)
|
||||||
|
|
||||||
/* pmrdump(o); */
|
/* pmrdump(o); */
|
||||||
|
|
||||||
if (pipe(o->sndcmd) != 0) {
|
|
||||||
ast_log(LOG_ERROR, "Unable to create pipe\n");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
ast_debug(4, "creating sound thread\n");
|
|
||||||
ast_pthread_create_background(&o->sthread, NULL, sound_thread, o);
|
|
||||||
|
|
||||||
/* link into list of devices */
|
/* link into list of devices */
|
||||||
if (o != &usbradio_default) {
|
if (o != &usbradio_default) {
|
||||||
o->next = usbradio_default.next;
|
o->next = usbradio_default.next;
|
||||||
usbradio_default.next = o;
|
usbradio_default.next = o;
|
||||||
}
|
}
|
||||||
return o;
|
return o;
|
||||||
|
|
||||||
error:
|
|
||||||
if (o != &usbradio_default)
|
|
||||||
ast_free(o);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG_FILETEST == 1
|
#if DEBUG_FILETEST == 1
|
||||||
|
@ -2686,10 +2475,6 @@ static int unload_module(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
close(o->sounddev);
|
close(o->sounddev);
|
||||||
if (o->sndcmd[0] > 0) {
|
|
||||||
close(o->sndcmd[0]);
|
|
||||||
close(o->sndcmd[1]);
|
|
||||||
}
|
|
||||||
if (o->dsp)
|
if (o->dsp)
|
||||||
ast_dsp_free(o->dsp);
|
ast_dsp_free(o->dsp);
|
||||||
if (o->owner)
|
if (o->owner)
|
||||||
|
|
Reference in New Issue