fix a bug when no audio devices are available, remove some dead
code, cleanup comments. This version is more or less in line with the one that i submitted to the asterisk developers.
This commit is contained in:
parent
06509de513
commit
d0a81ab302
Notes:
svn2git
2021-03-31 03:12:20 +00:00
svn path=/head/; revision=135500
@ -8,7 +8,7 @@
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License
|
||||
*
|
||||
* FreeBSD changes and multiple device support by Luigi Rizzo, 2005.04.26
|
||||
* FreeBSD changes and multiple device support by Luigi Rizzo, 2005.05.02
|
||||
* note-this code best seen with ts=8 (8-spaces tabs) in the editor
|
||||
*/
|
||||
|
||||
@ -44,6 +44,28 @@
|
||||
#include "ring10.h"
|
||||
#include "answer.h"
|
||||
|
||||
/*
|
||||
* Helper macros to parse config arguments. They will go in a common
|
||||
* header file if their usage is globally accepted. In the meantime,
|
||||
* we define them here. Typical usage is as below, WITHOUT ; on each line.
|
||||
*
|
||||
* {
|
||||
* M_START(v->name, v->value)
|
||||
*
|
||||
* M_BOOL("dothis", x->flag1)
|
||||
* M_STR("name", x->somestring)
|
||||
* M_F("bar", some_c_code)
|
||||
* M_END(some_final_statement)
|
||||
*/
|
||||
#define M_START(var, val) \
|
||||
char *__s = var; char *__val = val;
|
||||
#define M_END(x) x;
|
||||
#define M_F(tag, f) if (!strcasecmp((__s), tag)) { f; } else
|
||||
#define M_BOOL(tag, dst) M_F(tag, (dst) = ast_true(__val) )
|
||||
#define M_UINT(tag, dst) M_F(tag, (dst) = strtoul(__val, NULL, 0) )
|
||||
#define M_STR(tag, dst) M_F(tag, strncpy(dst, __val, sizeof(dst) - 1) )
|
||||
|
||||
|
||||
/* Which device to use */
|
||||
#if defined( __OpenBSD__ ) || defined( __NetBSD__ )
|
||||
#define DEV_DSP "/dev/audio"
|
||||
@ -112,6 +134,7 @@ static char *desc = "OSS Console Channel Driver";
|
||||
static char *tdesc = "OSS Console Channel Driver";
|
||||
static char *config = "oss.conf"; /* default config file */
|
||||
|
||||
static int oss_debug;
|
||||
|
||||
/*
|
||||
* Each sound is made of 'datalen' samples of sound, repeated as needed to
|
||||
@ -181,7 +204,8 @@ struct chan_oss_pvt {
|
||||
|
||||
int silencesuppression;
|
||||
int silencethreshold;
|
||||
char device[64]; /* device to open */
|
||||
int playbackonly;
|
||||
char device[64]; /* device to open */
|
||||
|
||||
pthread_t sthread;
|
||||
|
||||
@ -271,7 +295,7 @@ static int soundcard_writeframe(struct chan_oss_pvt *o, short *data)
|
||||
*/
|
||||
res = used_blocks(o);
|
||||
if (res > o->queuesize) { /* no room to write a block */
|
||||
if (o->w_errors++ == 0 && 0)
|
||||
if (o->w_errors++ == 0 && (oss_debug & 0x4))
|
||||
ast_log(LOG_WARNING, "write: used %d blocks (%d)\n",
|
||||
res, o->w_errors);
|
||||
return 0;
|
||||
@ -345,9 +369,7 @@ static void *sound_thread(void *arg)
|
||||
struct chan_oss_pvt *o = (struct chan_oss_pvt *)arg;
|
||||
|
||||
/* kick the driver by trying to read from it. Ignore errors */
|
||||
if (read(o->sounddev, ign, sizeof(ign)) < 0)
|
||||
ast_log(LOG_WARNING, "Read error on sound device: %s\n",
|
||||
strerror(errno));
|
||||
read(o->sounddev, ign, sizeof(ign));
|
||||
for(;;) {
|
||||
fd_set rfds, wfds;
|
||||
int maxfd, res;
|
||||
@ -399,61 +421,6 @@ static void *sound_thread(void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int calc_loudness(short *frame)
|
||||
{
|
||||
int sum = 0;
|
||||
int x;
|
||||
for (x=0;x<FRAME_SIZE;x++) {
|
||||
if (frame[x] < 0)
|
||||
sum -= frame[x];
|
||||
else
|
||||
sum += frame[x];
|
||||
}
|
||||
sum = sum/FRAME_SIZE;
|
||||
return sum;
|
||||
}
|
||||
|
||||
static int silence_suppress(short *buf)
|
||||
{
|
||||
#define SILBUF 3
|
||||
int loudness;
|
||||
static int silentframes = 0;
|
||||
static char silbuf[FRAME_SIZE * 2 * SILBUF];
|
||||
static int silbufcnt=0;
|
||||
if (!oss.silencesuppression)
|
||||
return 0;
|
||||
loudness = calc_loudness((short *)(buf));
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "loudness is %d\n", loudness);
|
||||
if (loudness < silencethreshold) {
|
||||
silentframes++;
|
||||
silbufcnt++;
|
||||
/* Keep track of the last few bits of silence so we can play
|
||||
them as lead-in when the time is right */
|
||||
if (silbufcnt >= SILBUF) {
|
||||
/* Make way for more buffer */
|
||||
memmove(silbuf, silbuf + FRAME_SIZE * 2, FRAME_SIZE * 2 * (SILBUF - 1));
|
||||
silbufcnt--;
|
||||
}
|
||||
memcpy(silbuf + FRAME_SIZE * 2 * silbufcnt, buf, FRAME_SIZE * 2);
|
||||
if (silentframes > 10) {
|
||||
/* We've had plenty of silence, so compress it now */
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
silentframes=0;
|
||||
/* Write any buffered silence we have, it may have something
|
||||
important */
|
||||
if (silbufcnt) {
|
||||
write(oss.sounddev, silbuf, silbufcnt * FRAME_SIZE);
|
||||
silbufcnt = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* reset and close the device if opened,
|
||||
* then open and initialize it in the desired mode,
|
||||
@ -518,12 +485,14 @@ static int setformat(struct chan_oss_pvt *o, int mode)
|
||||
}
|
||||
if (fmt != desired) {
|
||||
if (!(o->warned & WARN_speed)) {
|
||||
ast_log(LOG_WARNING, "Requested %d Hz, got %d Hz -- sound may be choppy\n", desired, fmt);
|
||||
ast_log(LOG_WARNING,
|
||||
"Requested %d Hz, got %d Hz -- sound may be choppy\n",
|
||||
desired, fmt);
|
||||
o->warned |= WARN_speed;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* on freebsd, SETFRAGMENT does not work very well on some cards.
|
||||
* on Freebsd, SETFRAGMENT does not work very well on some cards.
|
||||
* Default to use 256 bytes, let the user override
|
||||
*/
|
||||
if (o->frags) {
|
||||
@ -531,7 +500,8 @@ static int setformat(struct chan_oss_pvt *o, int mode)
|
||||
res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
|
||||
if (res < 0) {
|
||||
if (!(o->warned & WARN_frag)) {
|
||||
ast_log(LOG_WARNING, "Unable to set fragment size -- sound may be choppy\n");
|
||||
ast_log(LOG_WARNING,
|
||||
"Unable to set fragment size -- sound may be choppy\n");
|
||||
o->warned |= WARN_frag;
|
||||
}
|
||||
}
|
||||
@ -573,21 +543,29 @@ static int soundcard_setinput(struct chan_oss_pvt *o, int force)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* some of the standard methods supported by channels.
|
||||
*/
|
||||
static int oss_digit(struct ast_channel *c, char digit)
|
||||
{
|
||||
/* no better use for received digits than print them */
|
||||
ast_verbose( " << Console Received digit %c >> \n", digit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int oss_text(struct ast_channel *c, char *text)
|
||||
{
|
||||
/* print received messages */
|
||||
ast_verbose( " << Console Received text %s >> \n", text);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* request to play a sound on the speaker XXX fix oss. */
|
||||
/* Play ringtone 'x' on device 'o' */
|
||||
#define RING(o, x) { int what = x; write((o)->sndcmd[1], &what, sizeof(what)); }
|
||||
|
||||
/*
|
||||
* handler for incoming calls. Either autoanswer, or start ringing
|
||||
*/
|
||||
static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
||||
{
|
||||
struct chan_oss_pvt *o = c->pvt->pvt;
|
||||
@ -600,7 +578,7 @@ static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
||||
f.subclass = AST_CONTROL_ANSWER;
|
||||
ast_queue_frame(c, &f);
|
||||
} else {
|
||||
ast_verbose( " << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
|
||||
ast_verbose(" << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
|
||||
f.frametype = AST_FRAME_CONTROL;
|
||||
f.subclass = AST_CONTROL_RINGING;
|
||||
ast_queue_frame(c, &f);
|
||||
@ -609,17 +587,18 @@ static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void answer_sound(struct chan_oss_pvt *o)
|
||||
{
|
||||
RING(o, AST_CONTROL_ANSWER);
|
||||
}
|
||||
|
||||
/*
|
||||
* remote side answered the phone
|
||||
*/
|
||||
static int oss_answer(struct ast_channel *c)
|
||||
{
|
||||
struct chan_oss_pvt *o = c->pvt->pvt;
|
||||
|
||||
ast_verbose( " << Console call has been answered >> \n");
|
||||
answer_sound(o); /* XXX do we really need it ? considering we shut down immediately... */
|
||||
#if 0
|
||||
/* play an answer tone (XXX do we really need it ?) */
|
||||
RING(o, AST_CONTROL_ANSWER);
|
||||
#endif
|
||||
ast_setstate(c, AST_STATE_UP);
|
||||
o->cursound = -1;
|
||||
o->nosound=0;
|
||||
@ -661,7 +640,7 @@ static int oss_write(struct ast_channel *c, struct ast_frame *f)
|
||||
return 0;
|
||||
/* Stop any currently playing sound */
|
||||
o->cursound = -1;
|
||||
if (o->duplex != M_FULL) {
|
||||
if (o->duplex != M_FULL && !o->playbackonly) {
|
||||
/* XXX check this, looks weird! */
|
||||
/* If we're half duplex, we have to switch to read mode
|
||||
to honor immediate needs if necessary */
|
||||
@ -710,9 +689,6 @@ static int oss_write(struct ast_channel *c, struct ast_frame *f)
|
||||
|
||||
static struct ast_frame *oss_read(struct ast_channel *c)
|
||||
{
|
||||
/* XXX if we want multiple devices, should move these static vars
|
||||
* into the device descriptor
|
||||
*/
|
||||
int res;
|
||||
struct chan_oss_pvt *o = c->pvt->pvt;
|
||||
struct ast_frame *f = &o->read_f;
|
||||
@ -812,12 +788,12 @@ static struct ast_channel *oss_new(struct chan_oss_pvt *o,
|
||||
pvt->indicate = oss_indicate;
|
||||
pvt->fixup = oss_fixup;
|
||||
|
||||
if (strlen(ctx))
|
||||
strncpy(c->context, ctx, sizeof(o->ctx)-1);
|
||||
if (strlen(ext))
|
||||
strncpy(c->exten, ext, sizeof(o->ext)-1);
|
||||
if (strlen(o->language))
|
||||
strncpy(c->language, o->language, sizeof(o->language)-1);
|
||||
#define S_OVERRIDE(dst, src) \
|
||||
{ if (src && src[0] != '\0') /* non-empty string */ \
|
||||
strncpy((dst), src, sizeof(dst)-1); }
|
||||
S_OVERRIDE(c->context, ctx);
|
||||
S_OVERRIDE(c->exten, ext);
|
||||
S_OVERRIDE(c->language, o->language);
|
||||
o->owner = c;
|
||||
ast_setstate(c, state);
|
||||
ast_mutex_lock(&usecnt_lock);
|
||||
@ -928,11 +904,14 @@ static char autoanswer_usage[] =
|
||||
" argument, displays the current on/off status of autoanswer.\n"
|
||||
" The default value of autoanswer is in 'oss.conf'.\n";
|
||||
|
||||
/*
|
||||
* answer command from the console
|
||||
*/
|
||||
static int console_answer(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
|
||||
struct chan_oss_pvt *o = find_desc(oss_active);
|
||||
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
|
||||
if (argc != 1)
|
||||
return RESULT_SHOWUSAGE;
|
||||
if (!o->owner) {
|
||||
@ -942,7 +921,7 @@ static int console_answer(int fd, int argc, char *argv[])
|
||||
o->hookstate = 1;
|
||||
o->cursound = -1;
|
||||
ast_queue_frame(o->owner, &f);
|
||||
answer_sound(o);
|
||||
RING(o, AST_CONTROL_ANSWER);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
@ -1007,6 +986,32 @@ static char hangup_usage[] =
|
||||
" Hangs up any call currently placed on the console.\n";
|
||||
|
||||
|
||||
static int console_flash(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_FLASH };
|
||||
struct chan_oss_pvt *o = find_desc(oss_active);
|
||||
|
||||
if (argc != 1)
|
||||
return RESULT_SHOWUSAGE;
|
||||
o->cursound = -1;
|
||||
if (!o->owner) { /* XXX maybe !o->hookstate too ? */
|
||||
ast_cli(fd, "No call to flash\n");
|
||||
return RESULT_FAILURE;
|
||||
}
|
||||
o->hookstate = 0;
|
||||
if (o->owner) { /* XXX must be true, right ? */
|
||||
ast_queue_frame(o->owner, &f);
|
||||
}
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static char flash_usage[] =
|
||||
"Usage: flash\n"
|
||||
" Flashes the call currently placed on the console.\n";
|
||||
|
||||
|
||||
|
||||
static int console_dial(int fd, int argc, char *argv[])
|
||||
{
|
||||
char *tmp = NULL, *mye = NULL, *myc = NULL;
|
||||
@ -1030,6 +1035,7 @@ static int console_dial(int fd, int argc, char *argv[])
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
/* if we have an argument split it into extension and context */
|
||||
|
||||
if (argc == 2) {
|
||||
tmp = myc = strdup(argv[1]); /* make a writable copy */
|
||||
mye = strsep(&myc, "@"); /* set exten, advance to context */
|
||||
@ -1055,19 +1061,17 @@ static char dial_usage[] =
|
||||
static int console_transfer(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct chan_oss_pvt *o = find_desc(oss_active);
|
||||
struct ast_channel *b;
|
||||
|
||||
struct ast_channel *b = NULL;
|
||||
char *ext, *ctx;
|
||||
|
||||
if (argc != 2)
|
||||
return RESULT_SHOWUSAGE;
|
||||
if (o == NULL)
|
||||
return RESULT_FAILURE;
|
||||
if (! (o->owner && o->owner->bridge)) {
|
||||
if (o->owner == NULL || (b = o->owner->bridge) == NULL) {
|
||||
ast_cli(fd, "There is no call to transfer\n");
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
b = o->owner->bridge;
|
||||
|
||||
ext = ctx = strdup(argv[1]); /* make a writable copy */
|
||||
strsep(&ctx, "@"); /* set exten, advance to context */
|
||||
@ -1116,6 +1120,7 @@ static int console_active(int fd, int argc, char *argv[])
|
||||
static struct ast_cli_entry myclis[] = {
|
||||
{ { "answer", NULL }, console_answer, "Answer an incoming console call", answer_usage },
|
||||
{ { "hangup", NULL }, console_hangup, "Hangup a call on the console", hangup_usage },
|
||||
{ { "flash", NULL }, console_flash, "Flash a call on the console", flash_usage },
|
||||
{ { "dial", NULL }, console_dial, "Dial an extension on the console", dial_usage },
|
||||
{ { "transfer", NULL }, console_transfer, "Transfer a call to a different extension", transfer_usage },
|
||||
{ { "send", "text", NULL }, console_sendtext, "Send text to the remote device", sendtext_usage },
|
||||
@ -1177,28 +1182,22 @@ static struct chan_oss_pvt * store_config(struct ast_config *cfg,
|
||||
/* fill other fields from configuration */
|
||||
v = ast_variable_browse(cfg, ctg);
|
||||
while(v) {
|
||||
if (!strcasecmp(v->name, "autoanswer"))
|
||||
o->autoanswer = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "autohangup"))
|
||||
o->autohangup = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "silencesuppression"))
|
||||
o->silencesuppression = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "silencethreshold"))
|
||||
o->silencethreshold = atoi(v->value);
|
||||
else if (!strcasecmp(v->name, "device"))
|
||||
strncpy(o->device, v->value, sizeof(o->device)-1);
|
||||
else if (!strcasecmp(v->name, "frags"))
|
||||
o->frags = strtoul(v->value, NULL, 0);
|
||||
else if (!strcasecmp(v->name, "queuesize"))
|
||||
o->queuesize = strtoul(v->value, NULL, 0);
|
||||
else if (!strcasecmp(v->name, "context"))
|
||||
strncpy(o->ctx, v->value, sizeof(o->ctx)-1);
|
||||
else if (!strcasecmp(v->name, "language"))
|
||||
strncpy(o->language, v->value, sizeof(o->language)-1);
|
||||
else if (!strcasecmp(v->name, "extension"))
|
||||
strncpy(o->ext, v->value, sizeof(o->ext)-1);
|
||||
else if (!strcasecmp(v->name, "mixer"))
|
||||
store_mixer(o, v->value);
|
||||
M_START(v->name, v->value);
|
||||
|
||||
M_BOOL("autoanswer", o->autoanswer)
|
||||
M_BOOL("autohangup", o->autohangup)
|
||||
M_BOOL("playbackonly", o->playbackonly)
|
||||
M_BOOL("silencesuppression", o->silencesuppression)
|
||||
M_UINT("silencethreshold", o->silencethreshold )
|
||||
M_STR("device", o->device)
|
||||
M_UINT("frags", o->frags)
|
||||
M_UINT("debug", oss_debug)
|
||||
M_UINT("queuesize", o->queuesize)
|
||||
M_STR("context", o->ctx)
|
||||
M_STR("language", o->language)
|
||||
M_STR("extension", o->ext)
|
||||
M_F("mixer", store_mixer(o, v->value))
|
||||
M_END(;);
|
||||
v=v->next;
|
||||
}
|
||||
if (!strlen(o->device))
|
||||
@ -1263,12 +1262,19 @@ int load_module()
|
||||
}
|
||||
ast_destroy(cfg);
|
||||
}
|
||||
if (find_desc(oss_active) == NULL) {
|
||||
ast_log(LOG_NOTICE, "Device %s not found\n", oss_active);
|
||||
/* XXX we could default to 'dsp' perhaps ? */
|
||||
/* XXX should cleanup allocated memory etc. */
|
||||
return -1;
|
||||
}
|
||||
i = ast_channel_register(oss_default.type, tdesc,
|
||||
AST_FORMAT_SLINEAR, oss_request);
|
||||
if (i < 0) {
|
||||
ast_log(LOG_ERROR, "Unable to register channel class '%s'\n",
|
||||
oss_default.type);
|
||||
return NULL;
|
||||
/* XXX should cleanup allocated memory etc. */
|
||||
return -1;
|
||||
}
|
||||
for (i=0; i<sizeof(myclis)/sizeof(struct ast_cli_entry); i++)
|
||||
ast_cli_register(myclis + i);
|
||||
@ -1281,6 +1287,7 @@ int unload_module()
|
||||
int x;
|
||||
struct chan_oss_pvt *o;
|
||||
|
||||
/* XXX do we need a ast_channel_unregister oss_request ? */
|
||||
for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
|
||||
ast_cli_unregister(myclis + x);
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License
|
||||
*
|
||||
* FreeBSD changes and multiple device support by Luigi Rizzo, 2005.04.26
|
||||
* FreeBSD changes and multiple device support by Luigi Rizzo, 2005.05.02
|
||||
* note-this code best seen with ts=8 (8-spaces tabs) in the editor
|
||||
*/
|
||||
|
||||
@ -44,6 +44,28 @@
|
||||
#include "ring10.h"
|
||||
#include "answer.h"
|
||||
|
||||
/*
|
||||
* Helper macros to parse config arguments. They will go in a common
|
||||
* header file if their usage is globally accepted. In the meantime,
|
||||
* we define them here. Typical usage is as below, WITHOUT ; on each line.
|
||||
*
|
||||
* {
|
||||
* M_START(v->name, v->value)
|
||||
*
|
||||
* M_BOOL("dothis", x->flag1)
|
||||
* M_STR("name", x->somestring)
|
||||
* M_F("bar", some_c_code)
|
||||
* M_END(some_final_statement)
|
||||
*/
|
||||
#define M_START(var, val) \
|
||||
char *__s = var; char *__val = val;
|
||||
#define M_END(x) x;
|
||||
#define M_F(tag, f) if (!strcasecmp((__s), tag)) { f; } else
|
||||
#define M_BOOL(tag, dst) M_F(tag, (dst) = ast_true(__val) )
|
||||
#define M_UINT(tag, dst) M_F(tag, (dst) = strtoul(__val, NULL, 0) )
|
||||
#define M_STR(tag, dst) M_F(tag, strncpy(dst, __val, sizeof(dst) - 1) )
|
||||
|
||||
|
||||
/* Which device to use */
|
||||
#if defined( __OpenBSD__ ) || defined( __NetBSD__ )
|
||||
#define DEV_DSP "/dev/audio"
|
||||
@ -112,6 +134,7 @@ static char *desc = "OSS Console Channel Driver";
|
||||
static char *tdesc = "OSS Console Channel Driver";
|
||||
static char *config = "oss.conf"; /* default config file */
|
||||
|
||||
static int oss_debug;
|
||||
|
||||
/*
|
||||
* Each sound is made of 'datalen' samples of sound, repeated as needed to
|
||||
@ -181,7 +204,8 @@ struct chan_oss_pvt {
|
||||
|
||||
int silencesuppression;
|
||||
int silencethreshold;
|
||||
char device[64]; /* device to open */
|
||||
int playbackonly;
|
||||
char device[64]; /* device to open */
|
||||
|
||||
pthread_t sthread;
|
||||
|
||||
@ -271,7 +295,7 @@ static int soundcard_writeframe(struct chan_oss_pvt *o, short *data)
|
||||
*/
|
||||
res = used_blocks(o);
|
||||
if (res > o->queuesize) { /* no room to write a block */
|
||||
if (o->w_errors++ == 0 && 0)
|
||||
if (o->w_errors++ == 0 && (oss_debug & 0x4))
|
||||
ast_log(LOG_WARNING, "write: used %d blocks (%d)\n",
|
||||
res, o->w_errors);
|
||||
return 0;
|
||||
@ -345,9 +369,7 @@ static void *sound_thread(void *arg)
|
||||
struct chan_oss_pvt *o = (struct chan_oss_pvt *)arg;
|
||||
|
||||
/* kick the driver by trying to read from it. Ignore errors */
|
||||
if (read(o->sounddev, ign, sizeof(ign)) < 0)
|
||||
ast_log(LOG_WARNING, "Read error on sound device: %s\n",
|
||||
strerror(errno));
|
||||
read(o->sounddev, ign, sizeof(ign));
|
||||
for(;;) {
|
||||
fd_set rfds, wfds;
|
||||
int maxfd, res;
|
||||
@ -399,61 +421,6 @@ static void *sound_thread(void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int calc_loudness(short *frame)
|
||||
{
|
||||
int sum = 0;
|
||||
int x;
|
||||
for (x=0;x<FRAME_SIZE;x++) {
|
||||
if (frame[x] < 0)
|
||||
sum -= frame[x];
|
||||
else
|
||||
sum += frame[x];
|
||||
}
|
||||
sum = sum/FRAME_SIZE;
|
||||
return sum;
|
||||
}
|
||||
|
||||
static int silence_suppress(short *buf)
|
||||
{
|
||||
#define SILBUF 3
|
||||
int loudness;
|
||||
static int silentframes = 0;
|
||||
static char silbuf[FRAME_SIZE * 2 * SILBUF];
|
||||
static int silbufcnt=0;
|
||||
if (!oss.silencesuppression)
|
||||
return 0;
|
||||
loudness = calc_loudness((short *)(buf));
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "loudness is %d\n", loudness);
|
||||
if (loudness < silencethreshold) {
|
||||
silentframes++;
|
||||
silbufcnt++;
|
||||
/* Keep track of the last few bits of silence so we can play
|
||||
them as lead-in when the time is right */
|
||||
if (silbufcnt >= SILBUF) {
|
||||
/* Make way for more buffer */
|
||||
memmove(silbuf, silbuf + FRAME_SIZE * 2, FRAME_SIZE * 2 * (SILBUF - 1));
|
||||
silbufcnt--;
|
||||
}
|
||||
memcpy(silbuf + FRAME_SIZE * 2 * silbufcnt, buf, FRAME_SIZE * 2);
|
||||
if (silentframes > 10) {
|
||||
/* We've had plenty of silence, so compress it now */
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
silentframes=0;
|
||||
/* Write any buffered silence we have, it may have something
|
||||
important */
|
||||
if (silbufcnt) {
|
||||
write(oss.sounddev, silbuf, silbufcnt * FRAME_SIZE);
|
||||
silbufcnt = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* reset and close the device if opened,
|
||||
* then open and initialize it in the desired mode,
|
||||
@ -518,12 +485,14 @@ static int setformat(struct chan_oss_pvt *o, int mode)
|
||||
}
|
||||
if (fmt != desired) {
|
||||
if (!(o->warned & WARN_speed)) {
|
||||
ast_log(LOG_WARNING, "Requested %d Hz, got %d Hz -- sound may be choppy\n", desired, fmt);
|
||||
ast_log(LOG_WARNING,
|
||||
"Requested %d Hz, got %d Hz -- sound may be choppy\n",
|
||||
desired, fmt);
|
||||
o->warned |= WARN_speed;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* on freebsd, SETFRAGMENT does not work very well on some cards.
|
||||
* on Freebsd, SETFRAGMENT does not work very well on some cards.
|
||||
* Default to use 256 bytes, let the user override
|
||||
*/
|
||||
if (o->frags) {
|
||||
@ -531,7 +500,8 @@ static int setformat(struct chan_oss_pvt *o, int mode)
|
||||
res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
|
||||
if (res < 0) {
|
||||
if (!(o->warned & WARN_frag)) {
|
||||
ast_log(LOG_WARNING, "Unable to set fragment size -- sound may be choppy\n");
|
||||
ast_log(LOG_WARNING,
|
||||
"Unable to set fragment size -- sound may be choppy\n");
|
||||
o->warned |= WARN_frag;
|
||||
}
|
||||
}
|
||||
@ -573,21 +543,29 @@ static int soundcard_setinput(struct chan_oss_pvt *o, int force)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* some of the standard methods supported by channels.
|
||||
*/
|
||||
static int oss_digit(struct ast_channel *c, char digit)
|
||||
{
|
||||
/* no better use for received digits than print them */
|
||||
ast_verbose( " << Console Received digit %c >> \n", digit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int oss_text(struct ast_channel *c, char *text)
|
||||
{
|
||||
/* print received messages */
|
||||
ast_verbose( " << Console Received text %s >> \n", text);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* request to play a sound on the speaker XXX fix oss. */
|
||||
/* Play ringtone 'x' on device 'o' */
|
||||
#define RING(o, x) { int what = x; write((o)->sndcmd[1], &what, sizeof(what)); }
|
||||
|
||||
/*
|
||||
* handler for incoming calls. Either autoanswer, or start ringing
|
||||
*/
|
||||
static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
||||
{
|
||||
struct chan_oss_pvt *o = c->pvt->pvt;
|
||||
@ -600,7 +578,7 @@ static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
||||
f.subclass = AST_CONTROL_ANSWER;
|
||||
ast_queue_frame(c, &f);
|
||||
} else {
|
||||
ast_verbose( " << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
|
||||
ast_verbose(" << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
|
||||
f.frametype = AST_FRAME_CONTROL;
|
||||
f.subclass = AST_CONTROL_RINGING;
|
||||
ast_queue_frame(c, &f);
|
||||
@ -609,17 +587,18 @@ static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void answer_sound(struct chan_oss_pvt *o)
|
||||
{
|
||||
RING(o, AST_CONTROL_ANSWER);
|
||||
}
|
||||
|
||||
/*
|
||||
* remote side answered the phone
|
||||
*/
|
||||
static int oss_answer(struct ast_channel *c)
|
||||
{
|
||||
struct chan_oss_pvt *o = c->pvt->pvt;
|
||||
|
||||
ast_verbose( " << Console call has been answered >> \n");
|
||||
answer_sound(o); /* XXX do we really need it ? considering we shut down immediately... */
|
||||
#if 0
|
||||
/* play an answer tone (XXX do we really need it ?) */
|
||||
RING(o, AST_CONTROL_ANSWER);
|
||||
#endif
|
||||
ast_setstate(c, AST_STATE_UP);
|
||||
o->cursound = -1;
|
||||
o->nosound=0;
|
||||
@ -661,7 +640,7 @@ static int oss_write(struct ast_channel *c, struct ast_frame *f)
|
||||
return 0;
|
||||
/* Stop any currently playing sound */
|
||||
o->cursound = -1;
|
||||
if (o->duplex != M_FULL) {
|
||||
if (o->duplex != M_FULL && !o->playbackonly) {
|
||||
/* XXX check this, looks weird! */
|
||||
/* If we're half duplex, we have to switch to read mode
|
||||
to honor immediate needs if necessary */
|
||||
@ -710,9 +689,6 @@ static int oss_write(struct ast_channel *c, struct ast_frame *f)
|
||||
|
||||
static struct ast_frame *oss_read(struct ast_channel *c)
|
||||
{
|
||||
/* XXX if we want multiple devices, should move these static vars
|
||||
* into the device descriptor
|
||||
*/
|
||||
int res;
|
||||
struct chan_oss_pvt *o = c->pvt->pvt;
|
||||
struct ast_frame *f = &o->read_f;
|
||||
@ -812,12 +788,12 @@ static struct ast_channel *oss_new(struct chan_oss_pvt *o,
|
||||
pvt->indicate = oss_indicate;
|
||||
pvt->fixup = oss_fixup;
|
||||
|
||||
if (strlen(ctx))
|
||||
strncpy(c->context, ctx, sizeof(o->ctx)-1);
|
||||
if (strlen(ext))
|
||||
strncpy(c->exten, ext, sizeof(o->ext)-1);
|
||||
if (strlen(o->language))
|
||||
strncpy(c->language, o->language, sizeof(o->language)-1);
|
||||
#define S_OVERRIDE(dst, src) \
|
||||
{ if (src && src[0] != '\0') /* non-empty string */ \
|
||||
strncpy((dst), src, sizeof(dst)-1); }
|
||||
S_OVERRIDE(c->context, ctx);
|
||||
S_OVERRIDE(c->exten, ext);
|
||||
S_OVERRIDE(c->language, o->language);
|
||||
o->owner = c;
|
||||
ast_setstate(c, state);
|
||||
ast_mutex_lock(&usecnt_lock);
|
||||
@ -928,11 +904,14 @@ static char autoanswer_usage[] =
|
||||
" argument, displays the current on/off status of autoanswer.\n"
|
||||
" The default value of autoanswer is in 'oss.conf'.\n";
|
||||
|
||||
/*
|
||||
* answer command from the console
|
||||
*/
|
||||
static int console_answer(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
|
||||
struct chan_oss_pvt *o = find_desc(oss_active);
|
||||
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
|
||||
if (argc != 1)
|
||||
return RESULT_SHOWUSAGE;
|
||||
if (!o->owner) {
|
||||
@ -942,7 +921,7 @@ static int console_answer(int fd, int argc, char *argv[])
|
||||
o->hookstate = 1;
|
||||
o->cursound = -1;
|
||||
ast_queue_frame(o->owner, &f);
|
||||
answer_sound(o);
|
||||
RING(o, AST_CONTROL_ANSWER);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
@ -1007,6 +986,32 @@ static char hangup_usage[] =
|
||||
" Hangs up any call currently placed on the console.\n";
|
||||
|
||||
|
||||
static int console_flash(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_FLASH };
|
||||
struct chan_oss_pvt *o = find_desc(oss_active);
|
||||
|
||||
if (argc != 1)
|
||||
return RESULT_SHOWUSAGE;
|
||||
o->cursound = -1;
|
||||
if (!o->owner) { /* XXX maybe !o->hookstate too ? */
|
||||
ast_cli(fd, "No call to flash\n");
|
||||
return RESULT_FAILURE;
|
||||
}
|
||||
o->hookstate = 0;
|
||||
if (o->owner) { /* XXX must be true, right ? */
|
||||
ast_queue_frame(o->owner, &f);
|
||||
}
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static char flash_usage[] =
|
||||
"Usage: flash\n"
|
||||
" Flashes the call currently placed on the console.\n";
|
||||
|
||||
|
||||
|
||||
static int console_dial(int fd, int argc, char *argv[])
|
||||
{
|
||||
char *tmp = NULL, *mye = NULL, *myc = NULL;
|
||||
@ -1030,6 +1035,7 @@ static int console_dial(int fd, int argc, char *argv[])
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
/* if we have an argument split it into extension and context */
|
||||
|
||||
if (argc == 2) {
|
||||
tmp = myc = strdup(argv[1]); /* make a writable copy */
|
||||
mye = strsep(&myc, "@"); /* set exten, advance to context */
|
||||
@ -1055,19 +1061,17 @@ static char dial_usage[] =
|
||||
static int console_transfer(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct chan_oss_pvt *o = find_desc(oss_active);
|
||||
struct ast_channel *b;
|
||||
|
||||
struct ast_channel *b = NULL;
|
||||
char *ext, *ctx;
|
||||
|
||||
if (argc != 2)
|
||||
return RESULT_SHOWUSAGE;
|
||||
if (o == NULL)
|
||||
return RESULT_FAILURE;
|
||||
if (! (o->owner && o->owner->bridge)) {
|
||||
if (o->owner == NULL || (b = o->owner->bridge) == NULL) {
|
||||
ast_cli(fd, "There is no call to transfer\n");
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
b = o->owner->bridge;
|
||||
|
||||
ext = ctx = strdup(argv[1]); /* make a writable copy */
|
||||
strsep(&ctx, "@"); /* set exten, advance to context */
|
||||
@ -1116,6 +1120,7 @@ static int console_active(int fd, int argc, char *argv[])
|
||||
static struct ast_cli_entry myclis[] = {
|
||||
{ { "answer", NULL }, console_answer, "Answer an incoming console call", answer_usage },
|
||||
{ { "hangup", NULL }, console_hangup, "Hangup a call on the console", hangup_usage },
|
||||
{ { "flash", NULL }, console_flash, "Flash a call on the console", flash_usage },
|
||||
{ { "dial", NULL }, console_dial, "Dial an extension on the console", dial_usage },
|
||||
{ { "transfer", NULL }, console_transfer, "Transfer a call to a different extension", transfer_usage },
|
||||
{ { "send", "text", NULL }, console_sendtext, "Send text to the remote device", sendtext_usage },
|
||||
@ -1177,28 +1182,22 @@ static struct chan_oss_pvt * store_config(struct ast_config *cfg,
|
||||
/* fill other fields from configuration */
|
||||
v = ast_variable_browse(cfg, ctg);
|
||||
while(v) {
|
||||
if (!strcasecmp(v->name, "autoanswer"))
|
||||
o->autoanswer = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "autohangup"))
|
||||
o->autohangup = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "silencesuppression"))
|
||||
o->silencesuppression = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "silencethreshold"))
|
||||
o->silencethreshold = atoi(v->value);
|
||||
else if (!strcasecmp(v->name, "device"))
|
||||
strncpy(o->device, v->value, sizeof(o->device)-1);
|
||||
else if (!strcasecmp(v->name, "frags"))
|
||||
o->frags = strtoul(v->value, NULL, 0);
|
||||
else if (!strcasecmp(v->name, "queuesize"))
|
||||
o->queuesize = strtoul(v->value, NULL, 0);
|
||||
else if (!strcasecmp(v->name, "context"))
|
||||
strncpy(o->ctx, v->value, sizeof(o->ctx)-1);
|
||||
else if (!strcasecmp(v->name, "language"))
|
||||
strncpy(o->language, v->value, sizeof(o->language)-1);
|
||||
else if (!strcasecmp(v->name, "extension"))
|
||||
strncpy(o->ext, v->value, sizeof(o->ext)-1);
|
||||
else if (!strcasecmp(v->name, "mixer"))
|
||||
store_mixer(o, v->value);
|
||||
M_START(v->name, v->value);
|
||||
|
||||
M_BOOL("autoanswer", o->autoanswer)
|
||||
M_BOOL("autohangup", o->autohangup)
|
||||
M_BOOL("playbackonly", o->playbackonly)
|
||||
M_BOOL("silencesuppression", o->silencesuppression)
|
||||
M_UINT("silencethreshold", o->silencethreshold )
|
||||
M_STR("device", o->device)
|
||||
M_UINT("frags", o->frags)
|
||||
M_UINT("debug", oss_debug)
|
||||
M_UINT("queuesize", o->queuesize)
|
||||
M_STR("context", o->ctx)
|
||||
M_STR("language", o->language)
|
||||
M_STR("extension", o->ext)
|
||||
M_F("mixer", store_mixer(o, v->value))
|
||||
M_END(;);
|
||||
v=v->next;
|
||||
}
|
||||
if (!strlen(o->device))
|
||||
@ -1263,12 +1262,19 @@ int load_module()
|
||||
}
|
||||
ast_destroy(cfg);
|
||||
}
|
||||
if (find_desc(oss_active) == NULL) {
|
||||
ast_log(LOG_NOTICE, "Device %s not found\n", oss_active);
|
||||
/* XXX we could default to 'dsp' perhaps ? */
|
||||
/* XXX should cleanup allocated memory etc. */
|
||||
return -1;
|
||||
}
|
||||
i = ast_channel_register(oss_default.type, tdesc,
|
||||
AST_FORMAT_SLINEAR, oss_request);
|
||||
if (i < 0) {
|
||||
ast_log(LOG_ERROR, "Unable to register channel class '%s'\n",
|
||||
oss_default.type);
|
||||
return NULL;
|
||||
/* XXX should cleanup allocated memory etc. */
|
||||
return -1;
|
||||
}
|
||||
for (i=0; i<sizeof(myclis)/sizeof(struct ast_cli_entry); i++)
|
||||
ast_cli_register(myclis + i);
|
||||
@ -1281,6 +1287,7 @@ int unload_module()
|
||||
int x;
|
||||
struct chan_oss_pvt *o;
|
||||
|
||||
/* XXX do we need a ast_channel_unregister oss_request ? */
|
||||
for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
|
||||
ast_cli_unregister(myclis + x);
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License
|
||||
*
|
||||
* FreeBSD changes and multiple device support by Luigi Rizzo, 2005.04.26
|
||||
* FreeBSD changes and multiple device support by Luigi Rizzo, 2005.05.02
|
||||
* note-this code best seen with ts=8 (8-spaces tabs) in the editor
|
||||
*/
|
||||
|
||||
@ -44,6 +44,28 @@
|
||||
#include "ring10.h"
|
||||
#include "answer.h"
|
||||
|
||||
/*
|
||||
* Helper macros to parse config arguments. They will go in a common
|
||||
* header file if their usage is globally accepted. In the meantime,
|
||||
* we define them here. Typical usage is as below, WITHOUT ; on each line.
|
||||
*
|
||||
* {
|
||||
* M_START(v->name, v->value)
|
||||
*
|
||||
* M_BOOL("dothis", x->flag1)
|
||||
* M_STR("name", x->somestring)
|
||||
* M_F("bar", some_c_code)
|
||||
* M_END(some_final_statement)
|
||||
*/
|
||||
#define M_START(var, val) \
|
||||
char *__s = var; char *__val = val;
|
||||
#define M_END(x) x;
|
||||
#define M_F(tag, f) if (!strcasecmp((__s), tag)) { f; } else
|
||||
#define M_BOOL(tag, dst) M_F(tag, (dst) = ast_true(__val) )
|
||||
#define M_UINT(tag, dst) M_F(tag, (dst) = strtoul(__val, NULL, 0) )
|
||||
#define M_STR(tag, dst) M_F(tag, strncpy(dst, __val, sizeof(dst) - 1) )
|
||||
|
||||
|
||||
/* Which device to use */
|
||||
#if defined( __OpenBSD__ ) || defined( __NetBSD__ )
|
||||
#define DEV_DSP "/dev/audio"
|
||||
@ -112,6 +134,7 @@ static char *desc = "OSS Console Channel Driver";
|
||||
static char *tdesc = "OSS Console Channel Driver";
|
||||
static char *config = "oss.conf"; /* default config file */
|
||||
|
||||
static int oss_debug;
|
||||
|
||||
/*
|
||||
* Each sound is made of 'datalen' samples of sound, repeated as needed to
|
||||
@ -181,7 +204,8 @@ struct chan_oss_pvt {
|
||||
|
||||
int silencesuppression;
|
||||
int silencethreshold;
|
||||
char device[64]; /* device to open */
|
||||
int playbackonly;
|
||||
char device[64]; /* device to open */
|
||||
|
||||
pthread_t sthread;
|
||||
|
||||
@ -271,7 +295,7 @@ static int soundcard_writeframe(struct chan_oss_pvt *o, short *data)
|
||||
*/
|
||||
res = used_blocks(o);
|
||||
if (res > o->queuesize) { /* no room to write a block */
|
||||
if (o->w_errors++ == 0 && 0)
|
||||
if (o->w_errors++ == 0 && (oss_debug & 0x4))
|
||||
ast_log(LOG_WARNING, "write: used %d blocks (%d)\n",
|
||||
res, o->w_errors);
|
||||
return 0;
|
||||
@ -345,9 +369,7 @@ static void *sound_thread(void *arg)
|
||||
struct chan_oss_pvt *o = (struct chan_oss_pvt *)arg;
|
||||
|
||||
/* kick the driver by trying to read from it. Ignore errors */
|
||||
if (read(o->sounddev, ign, sizeof(ign)) < 0)
|
||||
ast_log(LOG_WARNING, "Read error on sound device: %s\n",
|
||||
strerror(errno));
|
||||
read(o->sounddev, ign, sizeof(ign));
|
||||
for(;;) {
|
||||
fd_set rfds, wfds;
|
||||
int maxfd, res;
|
||||
@ -399,61 +421,6 @@ static void *sound_thread(void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int calc_loudness(short *frame)
|
||||
{
|
||||
int sum = 0;
|
||||
int x;
|
||||
for (x=0;x<FRAME_SIZE;x++) {
|
||||
if (frame[x] < 0)
|
||||
sum -= frame[x];
|
||||
else
|
||||
sum += frame[x];
|
||||
}
|
||||
sum = sum/FRAME_SIZE;
|
||||
return sum;
|
||||
}
|
||||
|
||||
static int silence_suppress(short *buf)
|
||||
{
|
||||
#define SILBUF 3
|
||||
int loudness;
|
||||
static int silentframes = 0;
|
||||
static char silbuf[FRAME_SIZE * 2 * SILBUF];
|
||||
static int silbufcnt=0;
|
||||
if (!oss.silencesuppression)
|
||||
return 0;
|
||||
loudness = calc_loudness((short *)(buf));
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "loudness is %d\n", loudness);
|
||||
if (loudness < silencethreshold) {
|
||||
silentframes++;
|
||||
silbufcnt++;
|
||||
/* Keep track of the last few bits of silence so we can play
|
||||
them as lead-in when the time is right */
|
||||
if (silbufcnt >= SILBUF) {
|
||||
/* Make way for more buffer */
|
||||
memmove(silbuf, silbuf + FRAME_SIZE * 2, FRAME_SIZE * 2 * (SILBUF - 1));
|
||||
silbufcnt--;
|
||||
}
|
||||
memcpy(silbuf + FRAME_SIZE * 2 * silbufcnt, buf, FRAME_SIZE * 2);
|
||||
if (silentframes > 10) {
|
||||
/* We've had plenty of silence, so compress it now */
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
silentframes=0;
|
||||
/* Write any buffered silence we have, it may have something
|
||||
important */
|
||||
if (silbufcnt) {
|
||||
write(oss.sounddev, silbuf, silbufcnt * FRAME_SIZE);
|
||||
silbufcnt = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* reset and close the device if opened,
|
||||
* then open and initialize it in the desired mode,
|
||||
@ -518,12 +485,14 @@ static int setformat(struct chan_oss_pvt *o, int mode)
|
||||
}
|
||||
if (fmt != desired) {
|
||||
if (!(o->warned & WARN_speed)) {
|
||||
ast_log(LOG_WARNING, "Requested %d Hz, got %d Hz -- sound may be choppy\n", desired, fmt);
|
||||
ast_log(LOG_WARNING,
|
||||
"Requested %d Hz, got %d Hz -- sound may be choppy\n",
|
||||
desired, fmt);
|
||||
o->warned |= WARN_speed;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* on freebsd, SETFRAGMENT does not work very well on some cards.
|
||||
* on Freebsd, SETFRAGMENT does not work very well on some cards.
|
||||
* Default to use 256 bytes, let the user override
|
||||
*/
|
||||
if (o->frags) {
|
||||
@ -531,7 +500,8 @@ static int setformat(struct chan_oss_pvt *o, int mode)
|
||||
res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
|
||||
if (res < 0) {
|
||||
if (!(o->warned & WARN_frag)) {
|
||||
ast_log(LOG_WARNING, "Unable to set fragment size -- sound may be choppy\n");
|
||||
ast_log(LOG_WARNING,
|
||||
"Unable to set fragment size -- sound may be choppy\n");
|
||||
o->warned |= WARN_frag;
|
||||
}
|
||||
}
|
||||
@ -573,21 +543,29 @@ static int soundcard_setinput(struct chan_oss_pvt *o, int force)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* some of the standard methods supported by channels.
|
||||
*/
|
||||
static int oss_digit(struct ast_channel *c, char digit)
|
||||
{
|
||||
/* no better use for received digits than print them */
|
||||
ast_verbose( " << Console Received digit %c >> \n", digit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int oss_text(struct ast_channel *c, char *text)
|
||||
{
|
||||
/* print received messages */
|
||||
ast_verbose( " << Console Received text %s >> \n", text);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* request to play a sound on the speaker XXX fix oss. */
|
||||
/* Play ringtone 'x' on device 'o' */
|
||||
#define RING(o, x) { int what = x; write((o)->sndcmd[1], &what, sizeof(what)); }
|
||||
|
||||
/*
|
||||
* handler for incoming calls. Either autoanswer, or start ringing
|
||||
*/
|
||||
static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
||||
{
|
||||
struct chan_oss_pvt *o = c->pvt->pvt;
|
||||
@ -600,7 +578,7 @@ static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
||||
f.subclass = AST_CONTROL_ANSWER;
|
||||
ast_queue_frame(c, &f);
|
||||
} else {
|
||||
ast_verbose( " << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
|
||||
ast_verbose(" << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
|
||||
f.frametype = AST_FRAME_CONTROL;
|
||||
f.subclass = AST_CONTROL_RINGING;
|
||||
ast_queue_frame(c, &f);
|
||||
@ -609,17 +587,18 @@ static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void answer_sound(struct chan_oss_pvt *o)
|
||||
{
|
||||
RING(o, AST_CONTROL_ANSWER);
|
||||
}
|
||||
|
||||
/*
|
||||
* remote side answered the phone
|
||||
*/
|
||||
static int oss_answer(struct ast_channel *c)
|
||||
{
|
||||
struct chan_oss_pvt *o = c->pvt->pvt;
|
||||
|
||||
ast_verbose( " << Console call has been answered >> \n");
|
||||
answer_sound(o); /* XXX do we really need it ? considering we shut down immediately... */
|
||||
#if 0
|
||||
/* play an answer tone (XXX do we really need it ?) */
|
||||
RING(o, AST_CONTROL_ANSWER);
|
||||
#endif
|
||||
ast_setstate(c, AST_STATE_UP);
|
||||
o->cursound = -1;
|
||||
o->nosound=0;
|
||||
@ -661,7 +640,7 @@ static int oss_write(struct ast_channel *c, struct ast_frame *f)
|
||||
return 0;
|
||||
/* Stop any currently playing sound */
|
||||
o->cursound = -1;
|
||||
if (o->duplex != M_FULL) {
|
||||
if (o->duplex != M_FULL && !o->playbackonly) {
|
||||
/* XXX check this, looks weird! */
|
||||
/* If we're half duplex, we have to switch to read mode
|
||||
to honor immediate needs if necessary */
|
||||
@ -710,9 +689,6 @@ static int oss_write(struct ast_channel *c, struct ast_frame *f)
|
||||
|
||||
static struct ast_frame *oss_read(struct ast_channel *c)
|
||||
{
|
||||
/* XXX if we want multiple devices, should move these static vars
|
||||
* into the device descriptor
|
||||
*/
|
||||
int res;
|
||||
struct chan_oss_pvt *o = c->pvt->pvt;
|
||||
struct ast_frame *f = &o->read_f;
|
||||
@ -812,12 +788,12 @@ static struct ast_channel *oss_new(struct chan_oss_pvt *o,
|
||||
pvt->indicate = oss_indicate;
|
||||
pvt->fixup = oss_fixup;
|
||||
|
||||
if (strlen(ctx))
|
||||
strncpy(c->context, ctx, sizeof(o->ctx)-1);
|
||||
if (strlen(ext))
|
||||
strncpy(c->exten, ext, sizeof(o->ext)-1);
|
||||
if (strlen(o->language))
|
||||
strncpy(c->language, o->language, sizeof(o->language)-1);
|
||||
#define S_OVERRIDE(dst, src) \
|
||||
{ if (src && src[0] != '\0') /* non-empty string */ \
|
||||
strncpy((dst), src, sizeof(dst)-1); }
|
||||
S_OVERRIDE(c->context, ctx);
|
||||
S_OVERRIDE(c->exten, ext);
|
||||
S_OVERRIDE(c->language, o->language);
|
||||
o->owner = c;
|
||||
ast_setstate(c, state);
|
||||
ast_mutex_lock(&usecnt_lock);
|
||||
@ -928,11 +904,14 @@ static char autoanswer_usage[] =
|
||||
" argument, displays the current on/off status of autoanswer.\n"
|
||||
" The default value of autoanswer is in 'oss.conf'.\n";
|
||||
|
||||
/*
|
||||
* answer command from the console
|
||||
*/
|
||||
static int console_answer(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
|
||||
struct chan_oss_pvt *o = find_desc(oss_active);
|
||||
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
|
||||
if (argc != 1)
|
||||
return RESULT_SHOWUSAGE;
|
||||
if (!o->owner) {
|
||||
@ -942,7 +921,7 @@ static int console_answer(int fd, int argc, char *argv[])
|
||||
o->hookstate = 1;
|
||||
o->cursound = -1;
|
||||
ast_queue_frame(o->owner, &f);
|
||||
answer_sound(o);
|
||||
RING(o, AST_CONTROL_ANSWER);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
@ -1007,6 +986,32 @@ static char hangup_usage[] =
|
||||
" Hangs up any call currently placed on the console.\n";
|
||||
|
||||
|
||||
static int console_flash(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_FLASH };
|
||||
struct chan_oss_pvt *o = find_desc(oss_active);
|
||||
|
||||
if (argc != 1)
|
||||
return RESULT_SHOWUSAGE;
|
||||
o->cursound = -1;
|
||||
if (!o->owner) { /* XXX maybe !o->hookstate too ? */
|
||||
ast_cli(fd, "No call to flash\n");
|
||||
return RESULT_FAILURE;
|
||||
}
|
||||
o->hookstate = 0;
|
||||
if (o->owner) { /* XXX must be true, right ? */
|
||||
ast_queue_frame(o->owner, &f);
|
||||
}
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static char flash_usage[] =
|
||||
"Usage: flash\n"
|
||||
" Flashes the call currently placed on the console.\n";
|
||||
|
||||
|
||||
|
||||
static int console_dial(int fd, int argc, char *argv[])
|
||||
{
|
||||
char *tmp = NULL, *mye = NULL, *myc = NULL;
|
||||
@ -1030,6 +1035,7 @@ static int console_dial(int fd, int argc, char *argv[])
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
/* if we have an argument split it into extension and context */
|
||||
|
||||
if (argc == 2) {
|
||||
tmp = myc = strdup(argv[1]); /* make a writable copy */
|
||||
mye = strsep(&myc, "@"); /* set exten, advance to context */
|
||||
@ -1055,19 +1061,17 @@ static char dial_usage[] =
|
||||
static int console_transfer(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct chan_oss_pvt *o = find_desc(oss_active);
|
||||
struct ast_channel *b;
|
||||
|
||||
struct ast_channel *b = NULL;
|
||||
char *ext, *ctx;
|
||||
|
||||
if (argc != 2)
|
||||
return RESULT_SHOWUSAGE;
|
||||
if (o == NULL)
|
||||
return RESULT_FAILURE;
|
||||
if (! (o->owner && o->owner->bridge)) {
|
||||
if (o->owner == NULL || (b = o->owner->bridge) == NULL) {
|
||||
ast_cli(fd, "There is no call to transfer\n");
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
b = o->owner->bridge;
|
||||
|
||||
ext = ctx = strdup(argv[1]); /* make a writable copy */
|
||||
strsep(&ctx, "@"); /* set exten, advance to context */
|
||||
@ -1116,6 +1120,7 @@ static int console_active(int fd, int argc, char *argv[])
|
||||
static struct ast_cli_entry myclis[] = {
|
||||
{ { "answer", NULL }, console_answer, "Answer an incoming console call", answer_usage },
|
||||
{ { "hangup", NULL }, console_hangup, "Hangup a call on the console", hangup_usage },
|
||||
{ { "flash", NULL }, console_flash, "Flash a call on the console", flash_usage },
|
||||
{ { "dial", NULL }, console_dial, "Dial an extension on the console", dial_usage },
|
||||
{ { "transfer", NULL }, console_transfer, "Transfer a call to a different extension", transfer_usage },
|
||||
{ { "send", "text", NULL }, console_sendtext, "Send text to the remote device", sendtext_usage },
|
||||
@ -1177,28 +1182,22 @@ static struct chan_oss_pvt * store_config(struct ast_config *cfg,
|
||||
/* fill other fields from configuration */
|
||||
v = ast_variable_browse(cfg, ctg);
|
||||
while(v) {
|
||||
if (!strcasecmp(v->name, "autoanswer"))
|
||||
o->autoanswer = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "autohangup"))
|
||||
o->autohangup = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "silencesuppression"))
|
||||
o->silencesuppression = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "silencethreshold"))
|
||||
o->silencethreshold = atoi(v->value);
|
||||
else if (!strcasecmp(v->name, "device"))
|
||||
strncpy(o->device, v->value, sizeof(o->device)-1);
|
||||
else if (!strcasecmp(v->name, "frags"))
|
||||
o->frags = strtoul(v->value, NULL, 0);
|
||||
else if (!strcasecmp(v->name, "queuesize"))
|
||||
o->queuesize = strtoul(v->value, NULL, 0);
|
||||
else if (!strcasecmp(v->name, "context"))
|
||||
strncpy(o->ctx, v->value, sizeof(o->ctx)-1);
|
||||
else if (!strcasecmp(v->name, "language"))
|
||||
strncpy(o->language, v->value, sizeof(o->language)-1);
|
||||
else if (!strcasecmp(v->name, "extension"))
|
||||
strncpy(o->ext, v->value, sizeof(o->ext)-1);
|
||||
else if (!strcasecmp(v->name, "mixer"))
|
||||
store_mixer(o, v->value);
|
||||
M_START(v->name, v->value);
|
||||
|
||||
M_BOOL("autoanswer", o->autoanswer)
|
||||
M_BOOL("autohangup", o->autohangup)
|
||||
M_BOOL("playbackonly", o->playbackonly)
|
||||
M_BOOL("silencesuppression", o->silencesuppression)
|
||||
M_UINT("silencethreshold", o->silencethreshold )
|
||||
M_STR("device", o->device)
|
||||
M_UINT("frags", o->frags)
|
||||
M_UINT("debug", oss_debug)
|
||||
M_UINT("queuesize", o->queuesize)
|
||||
M_STR("context", o->ctx)
|
||||
M_STR("language", o->language)
|
||||
M_STR("extension", o->ext)
|
||||
M_F("mixer", store_mixer(o, v->value))
|
||||
M_END(;);
|
||||
v=v->next;
|
||||
}
|
||||
if (!strlen(o->device))
|
||||
@ -1263,12 +1262,19 @@ int load_module()
|
||||
}
|
||||
ast_destroy(cfg);
|
||||
}
|
||||
if (find_desc(oss_active) == NULL) {
|
||||
ast_log(LOG_NOTICE, "Device %s not found\n", oss_active);
|
||||
/* XXX we could default to 'dsp' perhaps ? */
|
||||
/* XXX should cleanup allocated memory etc. */
|
||||
return -1;
|
||||
}
|
||||
i = ast_channel_register(oss_default.type, tdesc,
|
||||
AST_FORMAT_SLINEAR, oss_request);
|
||||
if (i < 0) {
|
||||
ast_log(LOG_ERROR, "Unable to register channel class '%s'\n",
|
||||
oss_default.type);
|
||||
return NULL;
|
||||
/* XXX should cleanup allocated memory etc. */
|
||||
return -1;
|
||||
}
|
||||
for (i=0; i<sizeof(myclis)/sizeof(struct ast_cli_entry); i++)
|
||||
ast_cli_register(myclis + i);
|
||||
@ -1281,6 +1287,7 @@ int unload_module()
|
||||
int x;
|
||||
struct chan_oss_pvt *o;
|
||||
|
||||
/* XXX do we need a ast_channel_unregister oss_request ? */
|
||||
for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
|
||||
ast_cli_unregister(myclis + x);
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License
|
||||
*
|
||||
* FreeBSD changes and multiple device support by Luigi Rizzo, 2005.04.26
|
||||
* FreeBSD changes and multiple device support by Luigi Rizzo, 2005.05.02
|
||||
* note-this code best seen with ts=8 (8-spaces tabs) in the editor
|
||||
*/
|
||||
|
||||
@ -44,6 +44,28 @@
|
||||
#include "ring10.h"
|
||||
#include "answer.h"
|
||||
|
||||
/*
|
||||
* Helper macros to parse config arguments. They will go in a common
|
||||
* header file if their usage is globally accepted. In the meantime,
|
||||
* we define them here. Typical usage is as below, WITHOUT ; on each line.
|
||||
*
|
||||
* {
|
||||
* M_START(v->name, v->value)
|
||||
*
|
||||
* M_BOOL("dothis", x->flag1)
|
||||
* M_STR("name", x->somestring)
|
||||
* M_F("bar", some_c_code)
|
||||
* M_END(some_final_statement)
|
||||
*/
|
||||
#define M_START(var, val) \
|
||||
char *__s = var; char *__val = val;
|
||||
#define M_END(x) x;
|
||||
#define M_F(tag, f) if (!strcasecmp((__s), tag)) { f; } else
|
||||
#define M_BOOL(tag, dst) M_F(tag, (dst) = ast_true(__val) )
|
||||
#define M_UINT(tag, dst) M_F(tag, (dst) = strtoul(__val, NULL, 0) )
|
||||
#define M_STR(tag, dst) M_F(tag, strncpy(dst, __val, sizeof(dst) - 1) )
|
||||
|
||||
|
||||
/* Which device to use */
|
||||
#if defined( __OpenBSD__ ) || defined( __NetBSD__ )
|
||||
#define DEV_DSP "/dev/audio"
|
||||
@ -112,6 +134,7 @@ static char *desc = "OSS Console Channel Driver";
|
||||
static char *tdesc = "OSS Console Channel Driver";
|
||||
static char *config = "oss.conf"; /* default config file */
|
||||
|
||||
static int oss_debug;
|
||||
|
||||
/*
|
||||
* Each sound is made of 'datalen' samples of sound, repeated as needed to
|
||||
@ -181,7 +204,8 @@ struct chan_oss_pvt {
|
||||
|
||||
int silencesuppression;
|
||||
int silencethreshold;
|
||||
char device[64]; /* device to open */
|
||||
int playbackonly;
|
||||
char device[64]; /* device to open */
|
||||
|
||||
pthread_t sthread;
|
||||
|
||||
@ -271,7 +295,7 @@ static int soundcard_writeframe(struct chan_oss_pvt *o, short *data)
|
||||
*/
|
||||
res = used_blocks(o);
|
||||
if (res > o->queuesize) { /* no room to write a block */
|
||||
if (o->w_errors++ == 0 && 0)
|
||||
if (o->w_errors++ == 0 && (oss_debug & 0x4))
|
||||
ast_log(LOG_WARNING, "write: used %d blocks (%d)\n",
|
||||
res, o->w_errors);
|
||||
return 0;
|
||||
@ -345,9 +369,7 @@ static void *sound_thread(void *arg)
|
||||
struct chan_oss_pvt *o = (struct chan_oss_pvt *)arg;
|
||||
|
||||
/* kick the driver by trying to read from it. Ignore errors */
|
||||
if (read(o->sounddev, ign, sizeof(ign)) < 0)
|
||||
ast_log(LOG_WARNING, "Read error on sound device: %s\n",
|
||||
strerror(errno));
|
||||
read(o->sounddev, ign, sizeof(ign));
|
||||
for(;;) {
|
||||
fd_set rfds, wfds;
|
||||
int maxfd, res;
|
||||
@ -399,61 +421,6 @@ static void *sound_thread(void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int calc_loudness(short *frame)
|
||||
{
|
||||
int sum = 0;
|
||||
int x;
|
||||
for (x=0;x<FRAME_SIZE;x++) {
|
||||
if (frame[x] < 0)
|
||||
sum -= frame[x];
|
||||
else
|
||||
sum += frame[x];
|
||||
}
|
||||
sum = sum/FRAME_SIZE;
|
||||
return sum;
|
||||
}
|
||||
|
||||
static int silence_suppress(short *buf)
|
||||
{
|
||||
#define SILBUF 3
|
||||
int loudness;
|
||||
static int silentframes = 0;
|
||||
static char silbuf[FRAME_SIZE * 2 * SILBUF];
|
||||
static int silbufcnt=0;
|
||||
if (!oss.silencesuppression)
|
||||
return 0;
|
||||
loudness = calc_loudness((short *)(buf));
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "loudness is %d\n", loudness);
|
||||
if (loudness < silencethreshold) {
|
||||
silentframes++;
|
||||
silbufcnt++;
|
||||
/* Keep track of the last few bits of silence so we can play
|
||||
them as lead-in when the time is right */
|
||||
if (silbufcnt >= SILBUF) {
|
||||
/* Make way for more buffer */
|
||||
memmove(silbuf, silbuf + FRAME_SIZE * 2, FRAME_SIZE * 2 * (SILBUF - 1));
|
||||
silbufcnt--;
|
||||
}
|
||||
memcpy(silbuf + FRAME_SIZE * 2 * silbufcnt, buf, FRAME_SIZE * 2);
|
||||
if (silentframes > 10) {
|
||||
/* We've had plenty of silence, so compress it now */
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
silentframes=0;
|
||||
/* Write any buffered silence we have, it may have something
|
||||
important */
|
||||
if (silbufcnt) {
|
||||
write(oss.sounddev, silbuf, silbufcnt * FRAME_SIZE);
|
||||
silbufcnt = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* reset and close the device if opened,
|
||||
* then open and initialize it in the desired mode,
|
||||
@ -518,12 +485,14 @@ static int setformat(struct chan_oss_pvt *o, int mode)
|
||||
}
|
||||
if (fmt != desired) {
|
||||
if (!(o->warned & WARN_speed)) {
|
||||
ast_log(LOG_WARNING, "Requested %d Hz, got %d Hz -- sound may be choppy\n", desired, fmt);
|
||||
ast_log(LOG_WARNING,
|
||||
"Requested %d Hz, got %d Hz -- sound may be choppy\n",
|
||||
desired, fmt);
|
||||
o->warned |= WARN_speed;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* on freebsd, SETFRAGMENT does not work very well on some cards.
|
||||
* on Freebsd, SETFRAGMENT does not work very well on some cards.
|
||||
* Default to use 256 bytes, let the user override
|
||||
*/
|
||||
if (o->frags) {
|
||||
@ -531,7 +500,8 @@ static int setformat(struct chan_oss_pvt *o, int mode)
|
||||
res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
|
||||
if (res < 0) {
|
||||
if (!(o->warned & WARN_frag)) {
|
||||
ast_log(LOG_WARNING, "Unable to set fragment size -- sound may be choppy\n");
|
||||
ast_log(LOG_WARNING,
|
||||
"Unable to set fragment size -- sound may be choppy\n");
|
||||
o->warned |= WARN_frag;
|
||||
}
|
||||
}
|
||||
@ -573,21 +543,29 @@ static int soundcard_setinput(struct chan_oss_pvt *o, int force)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* some of the standard methods supported by channels.
|
||||
*/
|
||||
static int oss_digit(struct ast_channel *c, char digit)
|
||||
{
|
||||
/* no better use for received digits than print them */
|
||||
ast_verbose( " << Console Received digit %c >> \n", digit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int oss_text(struct ast_channel *c, char *text)
|
||||
{
|
||||
/* print received messages */
|
||||
ast_verbose( " << Console Received text %s >> \n", text);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* request to play a sound on the speaker XXX fix oss. */
|
||||
/* Play ringtone 'x' on device 'o' */
|
||||
#define RING(o, x) { int what = x; write((o)->sndcmd[1], &what, sizeof(what)); }
|
||||
|
||||
/*
|
||||
* handler for incoming calls. Either autoanswer, or start ringing
|
||||
*/
|
||||
static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
||||
{
|
||||
struct chan_oss_pvt *o = c->pvt->pvt;
|
||||
@ -600,7 +578,7 @@ static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
||||
f.subclass = AST_CONTROL_ANSWER;
|
||||
ast_queue_frame(c, &f);
|
||||
} else {
|
||||
ast_verbose( " << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
|
||||
ast_verbose(" << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
|
||||
f.frametype = AST_FRAME_CONTROL;
|
||||
f.subclass = AST_CONTROL_RINGING;
|
||||
ast_queue_frame(c, &f);
|
||||
@ -609,17 +587,18 @@ static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void answer_sound(struct chan_oss_pvt *o)
|
||||
{
|
||||
RING(o, AST_CONTROL_ANSWER);
|
||||
}
|
||||
|
||||
/*
|
||||
* remote side answered the phone
|
||||
*/
|
||||
static int oss_answer(struct ast_channel *c)
|
||||
{
|
||||
struct chan_oss_pvt *o = c->pvt->pvt;
|
||||
|
||||
ast_verbose( " << Console call has been answered >> \n");
|
||||
answer_sound(o); /* XXX do we really need it ? considering we shut down immediately... */
|
||||
#if 0
|
||||
/* play an answer tone (XXX do we really need it ?) */
|
||||
RING(o, AST_CONTROL_ANSWER);
|
||||
#endif
|
||||
ast_setstate(c, AST_STATE_UP);
|
||||
o->cursound = -1;
|
||||
o->nosound=0;
|
||||
@ -661,7 +640,7 @@ static int oss_write(struct ast_channel *c, struct ast_frame *f)
|
||||
return 0;
|
||||
/* Stop any currently playing sound */
|
||||
o->cursound = -1;
|
||||
if (o->duplex != M_FULL) {
|
||||
if (o->duplex != M_FULL && !o->playbackonly) {
|
||||
/* XXX check this, looks weird! */
|
||||
/* If we're half duplex, we have to switch to read mode
|
||||
to honor immediate needs if necessary */
|
||||
@ -710,9 +689,6 @@ static int oss_write(struct ast_channel *c, struct ast_frame *f)
|
||||
|
||||
static struct ast_frame *oss_read(struct ast_channel *c)
|
||||
{
|
||||
/* XXX if we want multiple devices, should move these static vars
|
||||
* into the device descriptor
|
||||
*/
|
||||
int res;
|
||||
struct chan_oss_pvt *o = c->pvt->pvt;
|
||||
struct ast_frame *f = &o->read_f;
|
||||
@ -812,12 +788,12 @@ static struct ast_channel *oss_new(struct chan_oss_pvt *o,
|
||||
pvt->indicate = oss_indicate;
|
||||
pvt->fixup = oss_fixup;
|
||||
|
||||
if (strlen(ctx))
|
||||
strncpy(c->context, ctx, sizeof(o->ctx)-1);
|
||||
if (strlen(ext))
|
||||
strncpy(c->exten, ext, sizeof(o->ext)-1);
|
||||
if (strlen(o->language))
|
||||
strncpy(c->language, o->language, sizeof(o->language)-1);
|
||||
#define S_OVERRIDE(dst, src) \
|
||||
{ if (src && src[0] != '\0') /* non-empty string */ \
|
||||
strncpy((dst), src, sizeof(dst)-1); }
|
||||
S_OVERRIDE(c->context, ctx);
|
||||
S_OVERRIDE(c->exten, ext);
|
||||
S_OVERRIDE(c->language, o->language);
|
||||
o->owner = c;
|
||||
ast_setstate(c, state);
|
||||
ast_mutex_lock(&usecnt_lock);
|
||||
@ -928,11 +904,14 @@ static char autoanswer_usage[] =
|
||||
" argument, displays the current on/off status of autoanswer.\n"
|
||||
" The default value of autoanswer is in 'oss.conf'.\n";
|
||||
|
||||
/*
|
||||
* answer command from the console
|
||||
*/
|
||||
static int console_answer(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
|
||||
struct chan_oss_pvt *o = find_desc(oss_active);
|
||||
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
|
||||
if (argc != 1)
|
||||
return RESULT_SHOWUSAGE;
|
||||
if (!o->owner) {
|
||||
@ -942,7 +921,7 @@ static int console_answer(int fd, int argc, char *argv[])
|
||||
o->hookstate = 1;
|
||||
o->cursound = -1;
|
||||
ast_queue_frame(o->owner, &f);
|
||||
answer_sound(o);
|
||||
RING(o, AST_CONTROL_ANSWER);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
@ -1007,6 +986,32 @@ static char hangup_usage[] =
|
||||
" Hangs up any call currently placed on the console.\n";
|
||||
|
||||
|
||||
static int console_flash(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_FLASH };
|
||||
struct chan_oss_pvt *o = find_desc(oss_active);
|
||||
|
||||
if (argc != 1)
|
||||
return RESULT_SHOWUSAGE;
|
||||
o->cursound = -1;
|
||||
if (!o->owner) { /* XXX maybe !o->hookstate too ? */
|
||||
ast_cli(fd, "No call to flash\n");
|
||||
return RESULT_FAILURE;
|
||||
}
|
||||
o->hookstate = 0;
|
||||
if (o->owner) { /* XXX must be true, right ? */
|
||||
ast_queue_frame(o->owner, &f);
|
||||
}
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static char flash_usage[] =
|
||||
"Usage: flash\n"
|
||||
" Flashes the call currently placed on the console.\n";
|
||||
|
||||
|
||||
|
||||
static int console_dial(int fd, int argc, char *argv[])
|
||||
{
|
||||
char *tmp = NULL, *mye = NULL, *myc = NULL;
|
||||
@ -1030,6 +1035,7 @@ static int console_dial(int fd, int argc, char *argv[])
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
/* if we have an argument split it into extension and context */
|
||||
|
||||
if (argc == 2) {
|
||||
tmp = myc = strdup(argv[1]); /* make a writable copy */
|
||||
mye = strsep(&myc, "@"); /* set exten, advance to context */
|
||||
@ -1055,19 +1061,17 @@ static char dial_usage[] =
|
||||
static int console_transfer(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct chan_oss_pvt *o = find_desc(oss_active);
|
||||
struct ast_channel *b;
|
||||
|
||||
struct ast_channel *b = NULL;
|
||||
char *ext, *ctx;
|
||||
|
||||
if (argc != 2)
|
||||
return RESULT_SHOWUSAGE;
|
||||
if (o == NULL)
|
||||
return RESULT_FAILURE;
|
||||
if (! (o->owner && o->owner->bridge)) {
|
||||
if (o->owner == NULL || (b = o->owner->bridge) == NULL) {
|
||||
ast_cli(fd, "There is no call to transfer\n");
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
b = o->owner->bridge;
|
||||
|
||||
ext = ctx = strdup(argv[1]); /* make a writable copy */
|
||||
strsep(&ctx, "@"); /* set exten, advance to context */
|
||||
@ -1116,6 +1120,7 @@ static int console_active(int fd, int argc, char *argv[])
|
||||
static struct ast_cli_entry myclis[] = {
|
||||
{ { "answer", NULL }, console_answer, "Answer an incoming console call", answer_usage },
|
||||
{ { "hangup", NULL }, console_hangup, "Hangup a call on the console", hangup_usage },
|
||||
{ { "flash", NULL }, console_flash, "Flash a call on the console", flash_usage },
|
||||
{ { "dial", NULL }, console_dial, "Dial an extension on the console", dial_usage },
|
||||
{ { "transfer", NULL }, console_transfer, "Transfer a call to a different extension", transfer_usage },
|
||||
{ { "send", "text", NULL }, console_sendtext, "Send text to the remote device", sendtext_usage },
|
||||
@ -1177,28 +1182,22 @@ static struct chan_oss_pvt * store_config(struct ast_config *cfg,
|
||||
/* fill other fields from configuration */
|
||||
v = ast_variable_browse(cfg, ctg);
|
||||
while(v) {
|
||||
if (!strcasecmp(v->name, "autoanswer"))
|
||||
o->autoanswer = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "autohangup"))
|
||||
o->autohangup = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "silencesuppression"))
|
||||
o->silencesuppression = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "silencethreshold"))
|
||||
o->silencethreshold = atoi(v->value);
|
||||
else if (!strcasecmp(v->name, "device"))
|
||||
strncpy(o->device, v->value, sizeof(o->device)-1);
|
||||
else if (!strcasecmp(v->name, "frags"))
|
||||
o->frags = strtoul(v->value, NULL, 0);
|
||||
else if (!strcasecmp(v->name, "queuesize"))
|
||||
o->queuesize = strtoul(v->value, NULL, 0);
|
||||
else if (!strcasecmp(v->name, "context"))
|
||||
strncpy(o->ctx, v->value, sizeof(o->ctx)-1);
|
||||
else if (!strcasecmp(v->name, "language"))
|
||||
strncpy(o->language, v->value, sizeof(o->language)-1);
|
||||
else if (!strcasecmp(v->name, "extension"))
|
||||
strncpy(o->ext, v->value, sizeof(o->ext)-1);
|
||||
else if (!strcasecmp(v->name, "mixer"))
|
||||
store_mixer(o, v->value);
|
||||
M_START(v->name, v->value);
|
||||
|
||||
M_BOOL("autoanswer", o->autoanswer)
|
||||
M_BOOL("autohangup", o->autohangup)
|
||||
M_BOOL("playbackonly", o->playbackonly)
|
||||
M_BOOL("silencesuppression", o->silencesuppression)
|
||||
M_UINT("silencethreshold", o->silencethreshold )
|
||||
M_STR("device", o->device)
|
||||
M_UINT("frags", o->frags)
|
||||
M_UINT("debug", oss_debug)
|
||||
M_UINT("queuesize", o->queuesize)
|
||||
M_STR("context", o->ctx)
|
||||
M_STR("language", o->language)
|
||||
M_STR("extension", o->ext)
|
||||
M_F("mixer", store_mixer(o, v->value))
|
||||
M_END(;);
|
||||
v=v->next;
|
||||
}
|
||||
if (!strlen(o->device))
|
||||
@ -1263,12 +1262,19 @@ int load_module()
|
||||
}
|
||||
ast_destroy(cfg);
|
||||
}
|
||||
if (find_desc(oss_active) == NULL) {
|
||||
ast_log(LOG_NOTICE, "Device %s not found\n", oss_active);
|
||||
/* XXX we could default to 'dsp' perhaps ? */
|
||||
/* XXX should cleanup allocated memory etc. */
|
||||
return -1;
|
||||
}
|
||||
i = ast_channel_register(oss_default.type, tdesc,
|
||||
AST_FORMAT_SLINEAR, oss_request);
|
||||
if (i < 0) {
|
||||
ast_log(LOG_ERROR, "Unable to register channel class '%s'\n",
|
||||
oss_default.type);
|
||||
return NULL;
|
||||
/* XXX should cleanup allocated memory etc. */
|
||||
return -1;
|
||||
}
|
||||
for (i=0; i<sizeof(myclis)/sizeof(struct ast_cli_entry); i++)
|
||||
ast_cli_register(myclis + i);
|
||||
@ -1281,6 +1287,7 @@ int unload_module()
|
||||
int x;
|
||||
struct chan_oss_pvt *o;
|
||||
|
||||
/* XXX do we need a ast_channel_unregister oss_request ? */
|
||||
for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
|
||||
ast_cli_unregister(myclis + x);
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License
|
||||
*
|
||||
* FreeBSD changes and multiple device support by Luigi Rizzo, 2005.04.26
|
||||
* FreeBSD changes and multiple device support by Luigi Rizzo, 2005.05.02
|
||||
* note-this code best seen with ts=8 (8-spaces tabs) in the editor
|
||||
*/
|
||||
|
||||
@ -44,6 +44,28 @@
|
||||
#include "ring10.h"
|
||||
#include "answer.h"
|
||||
|
||||
/*
|
||||
* Helper macros to parse config arguments. They will go in a common
|
||||
* header file if their usage is globally accepted. In the meantime,
|
||||
* we define them here. Typical usage is as below, WITHOUT ; on each line.
|
||||
*
|
||||
* {
|
||||
* M_START(v->name, v->value)
|
||||
*
|
||||
* M_BOOL("dothis", x->flag1)
|
||||
* M_STR("name", x->somestring)
|
||||
* M_F("bar", some_c_code)
|
||||
* M_END(some_final_statement)
|
||||
*/
|
||||
#define M_START(var, val) \
|
||||
char *__s = var; char *__val = val;
|
||||
#define M_END(x) x;
|
||||
#define M_F(tag, f) if (!strcasecmp((__s), tag)) { f; } else
|
||||
#define M_BOOL(tag, dst) M_F(tag, (dst) = ast_true(__val) )
|
||||
#define M_UINT(tag, dst) M_F(tag, (dst) = strtoul(__val, NULL, 0) )
|
||||
#define M_STR(tag, dst) M_F(tag, strncpy(dst, __val, sizeof(dst) - 1) )
|
||||
|
||||
|
||||
/* Which device to use */
|
||||
#if defined( __OpenBSD__ ) || defined( __NetBSD__ )
|
||||
#define DEV_DSP "/dev/audio"
|
||||
@ -112,6 +134,7 @@ static char *desc = "OSS Console Channel Driver";
|
||||
static char *tdesc = "OSS Console Channel Driver";
|
||||
static char *config = "oss.conf"; /* default config file */
|
||||
|
||||
static int oss_debug;
|
||||
|
||||
/*
|
||||
* Each sound is made of 'datalen' samples of sound, repeated as needed to
|
||||
@ -181,7 +204,8 @@ struct chan_oss_pvt {
|
||||
|
||||
int silencesuppression;
|
||||
int silencethreshold;
|
||||
char device[64]; /* device to open */
|
||||
int playbackonly;
|
||||
char device[64]; /* device to open */
|
||||
|
||||
pthread_t sthread;
|
||||
|
||||
@ -271,7 +295,7 @@ static int soundcard_writeframe(struct chan_oss_pvt *o, short *data)
|
||||
*/
|
||||
res = used_blocks(o);
|
||||
if (res > o->queuesize) { /* no room to write a block */
|
||||
if (o->w_errors++ == 0 && 0)
|
||||
if (o->w_errors++ == 0 && (oss_debug & 0x4))
|
||||
ast_log(LOG_WARNING, "write: used %d blocks (%d)\n",
|
||||
res, o->w_errors);
|
||||
return 0;
|
||||
@ -345,9 +369,7 @@ static void *sound_thread(void *arg)
|
||||
struct chan_oss_pvt *o = (struct chan_oss_pvt *)arg;
|
||||
|
||||
/* kick the driver by trying to read from it. Ignore errors */
|
||||
if (read(o->sounddev, ign, sizeof(ign)) < 0)
|
||||
ast_log(LOG_WARNING, "Read error on sound device: %s\n",
|
||||
strerror(errno));
|
||||
read(o->sounddev, ign, sizeof(ign));
|
||||
for(;;) {
|
||||
fd_set rfds, wfds;
|
||||
int maxfd, res;
|
||||
@ -399,61 +421,6 @@ static void *sound_thread(void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int calc_loudness(short *frame)
|
||||
{
|
||||
int sum = 0;
|
||||
int x;
|
||||
for (x=0;x<FRAME_SIZE;x++) {
|
||||
if (frame[x] < 0)
|
||||
sum -= frame[x];
|
||||
else
|
||||
sum += frame[x];
|
||||
}
|
||||
sum = sum/FRAME_SIZE;
|
||||
return sum;
|
||||
}
|
||||
|
||||
static int silence_suppress(short *buf)
|
||||
{
|
||||
#define SILBUF 3
|
||||
int loudness;
|
||||
static int silentframes = 0;
|
||||
static char silbuf[FRAME_SIZE * 2 * SILBUF];
|
||||
static int silbufcnt=0;
|
||||
if (!oss.silencesuppression)
|
||||
return 0;
|
||||
loudness = calc_loudness((short *)(buf));
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "loudness is %d\n", loudness);
|
||||
if (loudness < silencethreshold) {
|
||||
silentframes++;
|
||||
silbufcnt++;
|
||||
/* Keep track of the last few bits of silence so we can play
|
||||
them as lead-in when the time is right */
|
||||
if (silbufcnt >= SILBUF) {
|
||||
/* Make way for more buffer */
|
||||
memmove(silbuf, silbuf + FRAME_SIZE * 2, FRAME_SIZE * 2 * (SILBUF - 1));
|
||||
silbufcnt--;
|
||||
}
|
||||
memcpy(silbuf + FRAME_SIZE * 2 * silbufcnt, buf, FRAME_SIZE * 2);
|
||||
if (silentframes > 10) {
|
||||
/* We've had plenty of silence, so compress it now */
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
silentframes=0;
|
||||
/* Write any buffered silence we have, it may have something
|
||||
important */
|
||||
if (silbufcnt) {
|
||||
write(oss.sounddev, silbuf, silbufcnt * FRAME_SIZE);
|
||||
silbufcnt = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* reset and close the device if opened,
|
||||
* then open and initialize it in the desired mode,
|
||||
@ -518,12 +485,14 @@ static int setformat(struct chan_oss_pvt *o, int mode)
|
||||
}
|
||||
if (fmt != desired) {
|
||||
if (!(o->warned & WARN_speed)) {
|
||||
ast_log(LOG_WARNING, "Requested %d Hz, got %d Hz -- sound may be choppy\n", desired, fmt);
|
||||
ast_log(LOG_WARNING,
|
||||
"Requested %d Hz, got %d Hz -- sound may be choppy\n",
|
||||
desired, fmt);
|
||||
o->warned |= WARN_speed;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* on freebsd, SETFRAGMENT does not work very well on some cards.
|
||||
* on Freebsd, SETFRAGMENT does not work very well on some cards.
|
||||
* Default to use 256 bytes, let the user override
|
||||
*/
|
||||
if (o->frags) {
|
||||
@ -531,7 +500,8 @@ static int setformat(struct chan_oss_pvt *o, int mode)
|
||||
res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
|
||||
if (res < 0) {
|
||||
if (!(o->warned & WARN_frag)) {
|
||||
ast_log(LOG_WARNING, "Unable to set fragment size -- sound may be choppy\n");
|
||||
ast_log(LOG_WARNING,
|
||||
"Unable to set fragment size -- sound may be choppy\n");
|
||||
o->warned |= WARN_frag;
|
||||
}
|
||||
}
|
||||
@ -573,21 +543,29 @@ static int soundcard_setinput(struct chan_oss_pvt *o, int force)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* some of the standard methods supported by channels.
|
||||
*/
|
||||
static int oss_digit(struct ast_channel *c, char digit)
|
||||
{
|
||||
/* no better use for received digits than print them */
|
||||
ast_verbose( " << Console Received digit %c >> \n", digit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int oss_text(struct ast_channel *c, char *text)
|
||||
{
|
||||
/* print received messages */
|
||||
ast_verbose( " << Console Received text %s >> \n", text);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* request to play a sound on the speaker XXX fix oss. */
|
||||
/* Play ringtone 'x' on device 'o' */
|
||||
#define RING(o, x) { int what = x; write((o)->sndcmd[1], &what, sizeof(what)); }
|
||||
|
||||
/*
|
||||
* handler for incoming calls. Either autoanswer, or start ringing
|
||||
*/
|
||||
static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
||||
{
|
||||
struct chan_oss_pvt *o = c->pvt->pvt;
|
||||
@ -600,7 +578,7 @@ static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
||||
f.subclass = AST_CONTROL_ANSWER;
|
||||
ast_queue_frame(c, &f);
|
||||
} else {
|
||||
ast_verbose( " << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
|
||||
ast_verbose(" << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
|
||||
f.frametype = AST_FRAME_CONTROL;
|
||||
f.subclass = AST_CONTROL_RINGING;
|
||||
ast_queue_frame(c, &f);
|
||||
@ -609,17 +587,18 @@ static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void answer_sound(struct chan_oss_pvt *o)
|
||||
{
|
||||
RING(o, AST_CONTROL_ANSWER);
|
||||
}
|
||||
|
||||
/*
|
||||
* remote side answered the phone
|
||||
*/
|
||||
static int oss_answer(struct ast_channel *c)
|
||||
{
|
||||
struct chan_oss_pvt *o = c->pvt->pvt;
|
||||
|
||||
ast_verbose( " << Console call has been answered >> \n");
|
||||
answer_sound(o); /* XXX do we really need it ? considering we shut down immediately... */
|
||||
#if 0
|
||||
/* play an answer tone (XXX do we really need it ?) */
|
||||
RING(o, AST_CONTROL_ANSWER);
|
||||
#endif
|
||||
ast_setstate(c, AST_STATE_UP);
|
||||
o->cursound = -1;
|
||||
o->nosound=0;
|
||||
@ -661,7 +640,7 @@ static int oss_write(struct ast_channel *c, struct ast_frame *f)
|
||||
return 0;
|
||||
/* Stop any currently playing sound */
|
||||
o->cursound = -1;
|
||||
if (o->duplex != M_FULL) {
|
||||
if (o->duplex != M_FULL && !o->playbackonly) {
|
||||
/* XXX check this, looks weird! */
|
||||
/* If we're half duplex, we have to switch to read mode
|
||||
to honor immediate needs if necessary */
|
||||
@ -710,9 +689,6 @@ static int oss_write(struct ast_channel *c, struct ast_frame *f)
|
||||
|
||||
static struct ast_frame *oss_read(struct ast_channel *c)
|
||||
{
|
||||
/* XXX if we want multiple devices, should move these static vars
|
||||
* into the device descriptor
|
||||
*/
|
||||
int res;
|
||||
struct chan_oss_pvt *o = c->pvt->pvt;
|
||||
struct ast_frame *f = &o->read_f;
|
||||
@ -812,12 +788,12 @@ static struct ast_channel *oss_new(struct chan_oss_pvt *o,
|
||||
pvt->indicate = oss_indicate;
|
||||
pvt->fixup = oss_fixup;
|
||||
|
||||
if (strlen(ctx))
|
||||
strncpy(c->context, ctx, sizeof(o->ctx)-1);
|
||||
if (strlen(ext))
|
||||
strncpy(c->exten, ext, sizeof(o->ext)-1);
|
||||
if (strlen(o->language))
|
||||
strncpy(c->language, o->language, sizeof(o->language)-1);
|
||||
#define S_OVERRIDE(dst, src) \
|
||||
{ if (src && src[0] != '\0') /* non-empty string */ \
|
||||
strncpy((dst), src, sizeof(dst)-1); }
|
||||
S_OVERRIDE(c->context, ctx);
|
||||
S_OVERRIDE(c->exten, ext);
|
||||
S_OVERRIDE(c->language, o->language);
|
||||
o->owner = c;
|
||||
ast_setstate(c, state);
|
||||
ast_mutex_lock(&usecnt_lock);
|
||||
@ -928,11 +904,14 @@ static char autoanswer_usage[] =
|
||||
" argument, displays the current on/off status of autoanswer.\n"
|
||||
" The default value of autoanswer is in 'oss.conf'.\n";
|
||||
|
||||
/*
|
||||
* answer command from the console
|
||||
*/
|
||||
static int console_answer(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
|
||||
struct chan_oss_pvt *o = find_desc(oss_active);
|
||||
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
|
||||
if (argc != 1)
|
||||
return RESULT_SHOWUSAGE;
|
||||
if (!o->owner) {
|
||||
@ -942,7 +921,7 @@ static int console_answer(int fd, int argc, char *argv[])
|
||||
o->hookstate = 1;
|
||||
o->cursound = -1;
|
||||
ast_queue_frame(o->owner, &f);
|
||||
answer_sound(o);
|
||||
RING(o, AST_CONTROL_ANSWER);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
@ -1007,6 +986,32 @@ static char hangup_usage[] =
|
||||
" Hangs up any call currently placed on the console.\n";
|
||||
|
||||
|
||||
static int console_flash(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_FLASH };
|
||||
struct chan_oss_pvt *o = find_desc(oss_active);
|
||||
|
||||
if (argc != 1)
|
||||
return RESULT_SHOWUSAGE;
|
||||
o->cursound = -1;
|
||||
if (!o->owner) { /* XXX maybe !o->hookstate too ? */
|
||||
ast_cli(fd, "No call to flash\n");
|
||||
return RESULT_FAILURE;
|
||||
}
|
||||
o->hookstate = 0;
|
||||
if (o->owner) { /* XXX must be true, right ? */
|
||||
ast_queue_frame(o->owner, &f);
|
||||
}
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static char flash_usage[] =
|
||||
"Usage: flash\n"
|
||||
" Flashes the call currently placed on the console.\n";
|
||||
|
||||
|
||||
|
||||
static int console_dial(int fd, int argc, char *argv[])
|
||||
{
|
||||
char *tmp = NULL, *mye = NULL, *myc = NULL;
|
||||
@ -1030,6 +1035,7 @@ static int console_dial(int fd, int argc, char *argv[])
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
/* if we have an argument split it into extension and context */
|
||||
|
||||
if (argc == 2) {
|
||||
tmp = myc = strdup(argv[1]); /* make a writable copy */
|
||||
mye = strsep(&myc, "@"); /* set exten, advance to context */
|
||||
@ -1055,19 +1061,17 @@ static char dial_usage[] =
|
||||
static int console_transfer(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct chan_oss_pvt *o = find_desc(oss_active);
|
||||
struct ast_channel *b;
|
||||
|
||||
struct ast_channel *b = NULL;
|
||||
char *ext, *ctx;
|
||||
|
||||
if (argc != 2)
|
||||
return RESULT_SHOWUSAGE;
|
||||
if (o == NULL)
|
||||
return RESULT_FAILURE;
|
||||
if (! (o->owner && o->owner->bridge)) {
|
||||
if (o->owner == NULL || (b = o->owner->bridge) == NULL) {
|
||||
ast_cli(fd, "There is no call to transfer\n");
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
b = o->owner->bridge;
|
||||
|
||||
ext = ctx = strdup(argv[1]); /* make a writable copy */
|
||||
strsep(&ctx, "@"); /* set exten, advance to context */
|
||||
@ -1116,6 +1120,7 @@ static int console_active(int fd, int argc, char *argv[])
|
||||
static struct ast_cli_entry myclis[] = {
|
||||
{ { "answer", NULL }, console_answer, "Answer an incoming console call", answer_usage },
|
||||
{ { "hangup", NULL }, console_hangup, "Hangup a call on the console", hangup_usage },
|
||||
{ { "flash", NULL }, console_flash, "Flash a call on the console", flash_usage },
|
||||
{ { "dial", NULL }, console_dial, "Dial an extension on the console", dial_usage },
|
||||
{ { "transfer", NULL }, console_transfer, "Transfer a call to a different extension", transfer_usage },
|
||||
{ { "send", "text", NULL }, console_sendtext, "Send text to the remote device", sendtext_usage },
|
||||
@ -1177,28 +1182,22 @@ static struct chan_oss_pvt * store_config(struct ast_config *cfg,
|
||||
/* fill other fields from configuration */
|
||||
v = ast_variable_browse(cfg, ctg);
|
||||
while(v) {
|
||||
if (!strcasecmp(v->name, "autoanswer"))
|
||||
o->autoanswer = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "autohangup"))
|
||||
o->autohangup = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "silencesuppression"))
|
||||
o->silencesuppression = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "silencethreshold"))
|
||||
o->silencethreshold = atoi(v->value);
|
||||
else if (!strcasecmp(v->name, "device"))
|
||||
strncpy(o->device, v->value, sizeof(o->device)-1);
|
||||
else if (!strcasecmp(v->name, "frags"))
|
||||
o->frags = strtoul(v->value, NULL, 0);
|
||||
else if (!strcasecmp(v->name, "queuesize"))
|
||||
o->queuesize = strtoul(v->value, NULL, 0);
|
||||
else if (!strcasecmp(v->name, "context"))
|
||||
strncpy(o->ctx, v->value, sizeof(o->ctx)-1);
|
||||
else if (!strcasecmp(v->name, "language"))
|
||||
strncpy(o->language, v->value, sizeof(o->language)-1);
|
||||
else if (!strcasecmp(v->name, "extension"))
|
||||
strncpy(o->ext, v->value, sizeof(o->ext)-1);
|
||||
else if (!strcasecmp(v->name, "mixer"))
|
||||
store_mixer(o, v->value);
|
||||
M_START(v->name, v->value);
|
||||
|
||||
M_BOOL("autoanswer", o->autoanswer)
|
||||
M_BOOL("autohangup", o->autohangup)
|
||||
M_BOOL("playbackonly", o->playbackonly)
|
||||
M_BOOL("silencesuppression", o->silencesuppression)
|
||||
M_UINT("silencethreshold", o->silencethreshold )
|
||||
M_STR("device", o->device)
|
||||
M_UINT("frags", o->frags)
|
||||
M_UINT("debug", oss_debug)
|
||||
M_UINT("queuesize", o->queuesize)
|
||||
M_STR("context", o->ctx)
|
||||
M_STR("language", o->language)
|
||||
M_STR("extension", o->ext)
|
||||
M_F("mixer", store_mixer(o, v->value))
|
||||
M_END(;);
|
||||
v=v->next;
|
||||
}
|
||||
if (!strlen(o->device))
|
||||
@ -1263,12 +1262,19 @@ int load_module()
|
||||
}
|
||||
ast_destroy(cfg);
|
||||
}
|
||||
if (find_desc(oss_active) == NULL) {
|
||||
ast_log(LOG_NOTICE, "Device %s not found\n", oss_active);
|
||||
/* XXX we could default to 'dsp' perhaps ? */
|
||||
/* XXX should cleanup allocated memory etc. */
|
||||
return -1;
|
||||
}
|
||||
i = ast_channel_register(oss_default.type, tdesc,
|
||||
AST_FORMAT_SLINEAR, oss_request);
|
||||
if (i < 0) {
|
||||
ast_log(LOG_ERROR, "Unable to register channel class '%s'\n",
|
||||
oss_default.type);
|
||||
return NULL;
|
||||
/* XXX should cleanup allocated memory etc. */
|
||||
return -1;
|
||||
}
|
||||
for (i=0; i<sizeof(myclis)/sizeof(struct ast_cli_entry); i++)
|
||||
ast_cli_register(myclis + i);
|
||||
@ -1281,6 +1287,7 @@ int unload_module()
|
||||
int x;
|
||||
struct chan_oss_pvt *o;
|
||||
|
||||
/* XXX do we need a ast_channel_unregister oss_request ? */
|
||||
for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
|
||||
ast_cli_unregister(myclis + x);
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License
|
||||
*
|
||||
* FreeBSD changes and multiple device support by Luigi Rizzo, 2005.04.26
|
||||
* FreeBSD changes and multiple device support by Luigi Rizzo, 2005.05.02
|
||||
* note-this code best seen with ts=8 (8-spaces tabs) in the editor
|
||||
*/
|
||||
|
||||
@ -44,6 +44,28 @@
|
||||
#include "ring10.h"
|
||||
#include "answer.h"
|
||||
|
||||
/*
|
||||
* Helper macros to parse config arguments. They will go in a common
|
||||
* header file if their usage is globally accepted. In the meantime,
|
||||
* we define them here. Typical usage is as below, WITHOUT ; on each line.
|
||||
*
|
||||
* {
|
||||
* M_START(v->name, v->value)
|
||||
*
|
||||
* M_BOOL("dothis", x->flag1)
|
||||
* M_STR("name", x->somestring)
|
||||
* M_F("bar", some_c_code)
|
||||
* M_END(some_final_statement)
|
||||
*/
|
||||
#define M_START(var, val) \
|
||||
char *__s = var; char *__val = val;
|
||||
#define M_END(x) x;
|
||||
#define M_F(tag, f) if (!strcasecmp((__s), tag)) { f; } else
|
||||
#define M_BOOL(tag, dst) M_F(tag, (dst) = ast_true(__val) )
|
||||
#define M_UINT(tag, dst) M_F(tag, (dst) = strtoul(__val, NULL, 0) )
|
||||
#define M_STR(tag, dst) M_F(tag, strncpy(dst, __val, sizeof(dst) - 1) )
|
||||
|
||||
|
||||
/* Which device to use */
|
||||
#if defined( __OpenBSD__ ) || defined( __NetBSD__ )
|
||||
#define DEV_DSP "/dev/audio"
|
||||
@ -112,6 +134,7 @@ static char *desc = "OSS Console Channel Driver";
|
||||
static char *tdesc = "OSS Console Channel Driver";
|
||||
static char *config = "oss.conf"; /* default config file */
|
||||
|
||||
static int oss_debug;
|
||||
|
||||
/*
|
||||
* Each sound is made of 'datalen' samples of sound, repeated as needed to
|
||||
@ -181,7 +204,8 @@ struct chan_oss_pvt {
|
||||
|
||||
int silencesuppression;
|
||||
int silencethreshold;
|
||||
char device[64]; /* device to open */
|
||||
int playbackonly;
|
||||
char device[64]; /* device to open */
|
||||
|
||||
pthread_t sthread;
|
||||
|
||||
@ -271,7 +295,7 @@ static int soundcard_writeframe(struct chan_oss_pvt *o, short *data)
|
||||
*/
|
||||
res = used_blocks(o);
|
||||
if (res > o->queuesize) { /* no room to write a block */
|
||||
if (o->w_errors++ == 0 && 0)
|
||||
if (o->w_errors++ == 0 && (oss_debug & 0x4))
|
||||
ast_log(LOG_WARNING, "write: used %d blocks (%d)\n",
|
||||
res, o->w_errors);
|
||||
return 0;
|
||||
@ -345,9 +369,7 @@ static void *sound_thread(void *arg)
|
||||
struct chan_oss_pvt *o = (struct chan_oss_pvt *)arg;
|
||||
|
||||
/* kick the driver by trying to read from it. Ignore errors */
|
||||
if (read(o->sounddev, ign, sizeof(ign)) < 0)
|
||||
ast_log(LOG_WARNING, "Read error on sound device: %s\n",
|
||||
strerror(errno));
|
||||
read(o->sounddev, ign, sizeof(ign));
|
||||
for(;;) {
|
||||
fd_set rfds, wfds;
|
||||
int maxfd, res;
|
||||
@ -399,61 +421,6 @@ static void *sound_thread(void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int calc_loudness(short *frame)
|
||||
{
|
||||
int sum = 0;
|
||||
int x;
|
||||
for (x=0;x<FRAME_SIZE;x++) {
|
||||
if (frame[x] < 0)
|
||||
sum -= frame[x];
|
||||
else
|
||||
sum += frame[x];
|
||||
}
|
||||
sum = sum/FRAME_SIZE;
|
||||
return sum;
|
||||
}
|
||||
|
||||
static int silence_suppress(short *buf)
|
||||
{
|
||||
#define SILBUF 3
|
||||
int loudness;
|
||||
static int silentframes = 0;
|
||||
static char silbuf[FRAME_SIZE * 2 * SILBUF];
|
||||
static int silbufcnt=0;
|
||||
if (!oss.silencesuppression)
|
||||
return 0;
|
||||
loudness = calc_loudness((short *)(buf));
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "loudness is %d\n", loudness);
|
||||
if (loudness < silencethreshold) {
|
||||
silentframes++;
|
||||
silbufcnt++;
|
||||
/* Keep track of the last few bits of silence so we can play
|
||||
them as lead-in when the time is right */
|
||||
if (silbufcnt >= SILBUF) {
|
||||
/* Make way for more buffer */
|
||||
memmove(silbuf, silbuf + FRAME_SIZE * 2, FRAME_SIZE * 2 * (SILBUF - 1));
|
||||
silbufcnt--;
|
||||
}
|
||||
memcpy(silbuf + FRAME_SIZE * 2 * silbufcnt, buf, FRAME_SIZE * 2);
|
||||
if (silentframes > 10) {
|
||||
/* We've had plenty of silence, so compress it now */
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
silentframes=0;
|
||||
/* Write any buffered silence we have, it may have something
|
||||
important */
|
||||
if (silbufcnt) {
|
||||
write(oss.sounddev, silbuf, silbufcnt * FRAME_SIZE);
|
||||
silbufcnt = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* reset and close the device if opened,
|
||||
* then open and initialize it in the desired mode,
|
||||
@ -518,12 +485,14 @@ static int setformat(struct chan_oss_pvt *o, int mode)
|
||||
}
|
||||
if (fmt != desired) {
|
||||
if (!(o->warned & WARN_speed)) {
|
||||
ast_log(LOG_WARNING, "Requested %d Hz, got %d Hz -- sound may be choppy\n", desired, fmt);
|
||||
ast_log(LOG_WARNING,
|
||||
"Requested %d Hz, got %d Hz -- sound may be choppy\n",
|
||||
desired, fmt);
|
||||
o->warned |= WARN_speed;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* on freebsd, SETFRAGMENT does not work very well on some cards.
|
||||
* on Freebsd, SETFRAGMENT does not work very well on some cards.
|
||||
* Default to use 256 bytes, let the user override
|
||||
*/
|
||||
if (o->frags) {
|
||||
@ -531,7 +500,8 @@ static int setformat(struct chan_oss_pvt *o, int mode)
|
||||
res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
|
||||
if (res < 0) {
|
||||
if (!(o->warned & WARN_frag)) {
|
||||
ast_log(LOG_WARNING, "Unable to set fragment size -- sound may be choppy\n");
|
||||
ast_log(LOG_WARNING,
|
||||
"Unable to set fragment size -- sound may be choppy\n");
|
||||
o->warned |= WARN_frag;
|
||||
}
|
||||
}
|
||||
@ -573,21 +543,29 @@ static int soundcard_setinput(struct chan_oss_pvt *o, int force)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* some of the standard methods supported by channels.
|
||||
*/
|
||||
static int oss_digit(struct ast_channel *c, char digit)
|
||||
{
|
||||
/* no better use for received digits than print them */
|
||||
ast_verbose( " << Console Received digit %c >> \n", digit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int oss_text(struct ast_channel *c, char *text)
|
||||
{
|
||||
/* print received messages */
|
||||
ast_verbose( " << Console Received text %s >> \n", text);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* request to play a sound on the speaker XXX fix oss. */
|
||||
/* Play ringtone 'x' on device 'o' */
|
||||
#define RING(o, x) { int what = x; write((o)->sndcmd[1], &what, sizeof(what)); }
|
||||
|
||||
/*
|
||||
* handler for incoming calls. Either autoanswer, or start ringing
|
||||
*/
|
||||
static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
||||
{
|
||||
struct chan_oss_pvt *o = c->pvt->pvt;
|
||||
@ -600,7 +578,7 @@ static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
||||
f.subclass = AST_CONTROL_ANSWER;
|
||||
ast_queue_frame(c, &f);
|
||||
} else {
|
||||
ast_verbose( " << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
|
||||
ast_verbose(" << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
|
||||
f.frametype = AST_FRAME_CONTROL;
|
||||
f.subclass = AST_CONTROL_RINGING;
|
||||
ast_queue_frame(c, &f);
|
||||
@ -609,17 +587,18 @@ static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void answer_sound(struct chan_oss_pvt *o)
|
||||
{
|
||||
RING(o, AST_CONTROL_ANSWER);
|
||||
}
|
||||
|
||||
/*
|
||||
* remote side answered the phone
|
||||
*/
|
||||
static int oss_answer(struct ast_channel *c)
|
||||
{
|
||||
struct chan_oss_pvt *o = c->pvt->pvt;
|
||||
|
||||
ast_verbose( " << Console call has been answered >> \n");
|
||||
answer_sound(o); /* XXX do we really need it ? considering we shut down immediately... */
|
||||
#if 0
|
||||
/* play an answer tone (XXX do we really need it ?) */
|
||||
RING(o, AST_CONTROL_ANSWER);
|
||||
#endif
|
||||
ast_setstate(c, AST_STATE_UP);
|
||||
o->cursound = -1;
|
||||
o->nosound=0;
|
||||
@ -661,7 +640,7 @@ static int oss_write(struct ast_channel *c, struct ast_frame *f)
|
||||
return 0;
|
||||
/* Stop any currently playing sound */
|
||||
o->cursound = -1;
|
||||
if (o->duplex != M_FULL) {
|
||||
if (o->duplex != M_FULL && !o->playbackonly) {
|
||||
/* XXX check this, looks weird! */
|
||||
/* If we're half duplex, we have to switch to read mode
|
||||
to honor immediate needs if necessary */
|
||||
@ -710,9 +689,6 @@ static int oss_write(struct ast_channel *c, struct ast_frame *f)
|
||||
|
||||
static struct ast_frame *oss_read(struct ast_channel *c)
|
||||
{
|
||||
/* XXX if we want multiple devices, should move these static vars
|
||||
* into the device descriptor
|
||||
*/
|
||||
int res;
|
||||
struct chan_oss_pvt *o = c->pvt->pvt;
|
||||
struct ast_frame *f = &o->read_f;
|
||||
@ -812,12 +788,12 @@ static struct ast_channel *oss_new(struct chan_oss_pvt *o,
|
||||
pvt->indicate = oss_indicate;
|
||||
pvt->fixup = oss_fixup;
|
||||
|
||||
if (strlen(ctx))
|
||||
strncpy(c->context, ctx, sizeof(o->ctx)-1);
|
||||
if (strlen(ext))
|
||||
strncpy(c->exten, ext, sizeof(o->ext)-1);
|
||||
if (strlen(o->language))
|
||||
strncpy(c->language, o->language, sizeof(o->language)-1);
|
||||
#define S_OVERRIDE(dst, src) \
|
||||
{ if (src && src[0] != '\0') /* non-empty string */ \
|
||||
strncpy((dst), src, sizeof(dst)-1); }
|
||||
S_OVERRIDE(c->context, ctx);
|
||||
S_OVERRIDE(c->exten, ext);
|
||||
S_OVERRIDE(c->language, o->language);
|
||||
o->owner = c;
|
||||
ast_setstate(c, state);
|
||||
ast_mutex_lock(&usecnt_lock);
|
||||
@ -928,11 +904,14 @@ static char autoanswer_usage[] =
|
||||
" argument, displays the current on/off status of autoanswer.\n"
|
||||
" The default value of autoanswer is in 'oss.conf'.\n";
|
||||
|
||||
/*
|
||||
* answer command from the console
|
||||
*/
|
||||
static int console_answer(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
|
||||
struct chan_oss_pvt *o = find_desc(oss_active);
|
||||
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
|
||||
if (argc != 1)
|
||||
return RESULT_SHOWUSAGE;
|
||||
if (!o->owner) {
|
||||
@ -942,7 +921,7 @@ static int console_answer(int fd, int argc, char *argv[])
|
||||
o->hookstate = 1;
|
||||
o->cursound = -1;
|
||||
ast_queue_frame(o->owner, &f);
|
||||
answer_sound(o);
|
||||
RING(o, AST_CONTROL_ANSWER);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
@ -1007,6 +986,32 @@ static char hangup_usage[] =
|
||||
" Hangs up any call currently placed on the console.\n";
|
||||
|
||||
|
||||
static int console_flash(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_FLASH };
|
||||
struct chan_oss_pvt *o = find_desc(oss_active);
|
||||
|
||||
if (argc != 1)
|
||||
return RESULT_SHOWUSAGE;
|
||||
o->cursound = -1;
|
||||
if (!o->owner) { /* XXX maybe !o->hookstate too ? */
|
||||
ast_cli(fd, "No call to flash\n");
|
||||
return RESULT_FAILURE;
|
||||
}
|
||||
o->hookstate = 0;
|
||||
if (o->owner) { /* XXX must be true, right ? */
|
||||
ast_queue_frame(o->owner, &f);
|
||||
}
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static char flash_usage[] =
|
||||
"Usage: flash\n"
|
||||
" Flashes the call currently placed on the console.\n";
|
||||
|
||||
|
||||
|
||||
static int console_dial(int fd, int argc, char *argv[])
|
||||
{
|
||||
char *tmp = NULL, *mye = NULL, *myc = NULL;
|
||||
@ -1030,6 +1035,7 @@ static int console_dial(int fd, int argc, char *argv[])
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
/* if we have an argument split it into extension and context */
|
||||
|
||||
if (argc == 2) {
|
||||
tmp = myc = strdup(argv[1]); /* make a writable copy */
|
||||
mye = strsep(&myc, "@"); /* set exten, advance to context */
|
||||
@ -1055,19 +1061,17 @@ static char dial_usage[] =
|
||||
static int console_transfer(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct chan_oss_pvt *o = find_desc(oss_active);
|
||||
struct ast_channel *b;
|
||||
|
||||
struct ast_channel *b = NULL;
|
||||
char *ext, *ctx;
|
||||
|
||||
if (argc != 2)
|
||||
return RESULT_SHOWUSAGE;
|
||||
if (o == NULL)
|
||||
return RESULT_FAILURE;
|
||||
if (! (o->owner && o->owner->bridge)) {
|
||||
if (o->owner == NULL || (b = o->owner->bridge) == NULL) {
|
||||
ast_cli(fd, "There is no call to transfer\n");
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
b = o->owner->bridge;
|
||||
|
||||
ext = ctx = strdup(argv[1]); /* make a writable copy */
|
||||
strsep(&ctx, "@"); /* set exten, advance to context */
|
||||
@ -1116,6 +1120,7 @@ static int console_active(int fd, int argc, char *argv[])
|
||||
static struct ast_cli_entry myclis[] = {
|
||||
{ { "answer", NULL }, console_answer, "Answer an incoming console call", answer_usage },
|
||||
{ { "hangup", NULL }, console_hangup, "Hangup a call on the console", hangup_usage },
|
||||
{ { "flash", NULL }, console_flash, "Flash a call on the console", flash_usage },
|
||||
{ { "dial", NULL }, console_dial, "Dial an extension on the console", dial_usage },
|
||||
{ { "transfer", NULL }, console_transfer, "Transfer a call to a different extension", transfer_usage },
|
||||
{ { "send", "text", NULL }, console_sendtext, "Send text to the remote device", sendtext_usage },
|
||||
@ -1177,28 +1182,22 @@ static struct chan_oss_pvt * store_config(struct ast_config *cfg,
|
||||
/* fill other fields from configuration */
|
||||
v = ast_variable_browse(cfg, ctg);
|
||||
while(v) {
|
||||
if (!strcasecmp(v->name, "autoanswer"))
|
||||
o->autoanswer = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "autohangup"))
|
||||
o->autohangup = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "silencesuppression"))
|
||||
o->silencesuppression = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "silencethreshold"))
|
||||
o->silencethreshold = atoi(v->value);
|
||||
else if (!strcasecmp(v->name, "device"))
|
||||
strncpy(o->device, v->value, sizeof(o->device)-1);
|
||||
else if (!strcasecmp(v->name, "frags"))
|
||||
o->frags = strtoul(v->value, NULL, 0);
|
||||
else if (!strcasecmp(v->name, "queuesize"))
|
||||
o->queuesize = strtoul(v->value, NULL, 0);
|
||||
else if (!strcasecmp(v->name, "context"))
|
||||
strncpy(o->ctx, v->value, sizeof(o->ctx)-1);
|
||||
else if (!strcasecmp(v->name, "language"))
|
||||
strncpy(o->language, v->value, sizeof(o->language)-1);
|
||||
else if (!strcasecmp(v->name, "extension"))
|
||||
strncpy(o->ext, v->value, sizeof(o->ext)-1);
|
||||
else if (!strcasecmp(v->name, "mixer"))
|
||||
store_mixer(o, v->value);
|
||||
M_START(v->name, v->value);
|
||||
|
||||
M_BOOL("autoanswer", o->autoanswer)
|
||||
M_BOOL("autohangup", o->autohangup)
|
||||
M_BOOL("playbackonly", o->playbackonly)
|
||||
M_BOOL("silencesuppression", o->silencesuppression)
|
||||
M_UINT("silencethreshold", o->silencethreshold )
|
||||
M_STR("device", o->device)
|
||||
M_UINT("frags", o->frags)
|
||||
M_UINT("debug", oss_debug)
|
||||
M_UINT("queuesize", o->queuesize)
|
||||
M_STR("context", o->ctx)
|
||||
M_STR("language", o->language)
|
||||
M_STR("extension", o->ext)
|
||||
M_F("mixer", store_mixer(o, v->value))
|
||||
M_END(;);
|
||||
v=v->next;
|
||||
}
|
||||
if (!strlen(o->device))
|
||||
@ -1263,12 +1262,19 @@ int load_module()
|
||||
}
|
||||
ast_destroy(cfg);
|
||||
}
|
||||
if (find_desc(oss_active) == NULL) {
|
||||
ast_log(LOG_NOTICE, "Device %s not found\n", oss_active);
|
||||
/* XXX we could default to 'dsp' perhaps ? */
|
||||
/* XXX should cleanup allocated memory etc. */
|
||||
return -1;
|
||||
}
|
||||
i = ast_channel_register(oss_default.type, tdesc,
|
||||
AST_FORMAT_SLINEAR, oss_request);
|
||||
if (i < 0) {
|
||||
ast_log(LOG_ERROR, "Unable to register channel class '%s'\n",
|
||||
oss_default.type);
|
||||
return NULL;
|
||||
/* XXX should cleanup allocated memory etc. */
|
||||
return -1;
|
||||
}
|
||||
for (i=0; i<sizeof(myclis)/sizeof(struct ast_cli_entry); i++)
|
||||
ast_cli_register(myclis + i);
|
||||
@ -1281,6 +1287,7 @@ int unload_module()
|
||||
int x;
|
||||
struct chan_oss_pvt *o;
|
||||
|
||||
/* XXX do we need a ast_channel_unregister oss_request ? */
|
||||
for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
|
||||
ast_cli_unregister(myclis + x);
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License
|
||||
*
|
||||
* FreeBSD changes and multiple device support by Luigi Rizzo, 2005.04.26
|
||||
* FreeBSD changes and multiple device support by Luigi Rizzo, 2005.05.02
|
||||
* note-this code best seen with ts=8 (8-spaces tabs) in the editor
|
||||
*/
|
||||
|
||||
@ -44,6 +44,28 @@
|
||||
#include "ring10.h"
|
||||
#include "answer.h"
|
||||
|
||||
/*
|
||||
* Helper macros to parse config arguments. They will go in a common
|
||||
* header file if their usage is globally accepted. In the meantime,
|
||||
* we define them here. Typical usage is as below, WITHOUT ; on each line.
|
||||
*
|
||||
* {
|
||||
* M_START(v->name, v->value)
|
||||
*
|
||||
* M_BOOL("dothis", x->flag1)
|
||||
* M_STR("name", x->somestring)
|
||||
* M_F("bar", some_c_code)
|
||||
* M_END(some_final_statement)
|
||||
*/
|
||||
#define M_START(var, val) \
|
||||
char *__s = var; char *__val = val;
|
||||
#define M_END(x) x;
|
||||
#define M_F(tag, f) if (!strcasecmp((__s), tag)) { f; } else
|
||||
#define M_BOOL(tag, dst) M_F(tag, (dst) = ast_true(__val) )
|
||||
#define M_UINT(tag, dst) M_F(tag, (dst) = strtoul(__val, NULL, 0) )
|
||||
#define M_STR(tag, dst) M_F(tag, strncpy(dst, __val, sizeof(dst) - 1) )
|
||||
|
||||
|
||||
/* Which device to use */
|
||||
#if defined( __OpenBSD__ ) || defined( __NetBSD__ )
|
||||
#define DEV_DSP "/dev/audio"
|
||||
@ -112,6 +134,7 @@ static char *desc = "OSS Console Channel Driver";
|
||||
static char *tdesc = "OSS Console Channel Driver";
|
||||
static char *config = "oss.conf"; /* default config file */
|
||||
|
||||
static int oss_debug;
|
||||
|
||||
/*
|
||||
* Each sound is made of 'datalen' samples of sound, repeated as needed to
|
||||
@ -181,7 +204,8 @@ struct chan_oss_pvt {
|
||||
|
||||
int silencesuppression;
|
||||
int silencethreshold;
|
||||
char device[64]; /* device to open */
|
||||
int playbackonly;
|
||||
char device[64]; /* device to open */
|
||||
|
||||
pthread_t sthread;
|
||||
|
||||
@ -271,7 +295,7 @@ static int soundcard_writeframe(struct chan_oss_pvt *o, short *data)
|
||||
*/
|
||||
res = used_blocks(o);
|
||||
if (res > o->queuesize) { /* no room to write a block */
|
||||
if (o->w_errors++ == 0 && 0)
|
||||
if (o->w_errors++ == 0 && (oss_debug & 0x4))
|
||||
ast_log(LOG_WARNING, "write: used %d blocks (%d)\n",
|
||||
res, o->w_errors);
|
||||
return 0;
|
||||
@ -345,9 +369,7 @@ static void *sound_thread(void *arg)
|
||||
struct chan_oss_pvt *o = (struct chan_oss_pvt *)arg;
|
||||
|
||||
/* kick the driver by trying to read from it. Ignore errors */
|
||||
if (read(o->sounddev, ign, sizeof(ign)) < 0)
|
||||
ast_log(LOG_WARNING, "Read error on sound device: %s\n",
|
||||
strerror(errno));
|
||||
read(o->sounddev, ign, sizeof(ign));
|
||||
for(;;) {
|
||||
fd_set rfds, wfds;
|
||||
int maxfd, res;
|
||||
@ -399,61 +421,6 @@ static void *sound_thread(void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int calc_loudness(short *frame)
|
||||
{
|
||||
int sum = 0;
|
||||
int x;
|
||||
for (x=0;x<FRAME_SIZE;x++) {
|
||||
if (frame[x] < 0)
|
||||
sum -= frame[x];
|
||||
else
|
||||
sum += frame[x];
|
||||
}
|
||||
sum = sum/FRAME_SIZE;
|
||||
return sum;
|
||||
}
|
||||
|
||||
static int silence_suppress(short *buf)
|
||||
{
|
||||
#define SILBUF 3
|
||||
int loudness;
|
||||
static int silentframes = 0;
|
||||
static char silbuf[FRAME_SIZE * 2 * SILBUF];
|
||||
static int silbufcnt=0;
|
||||
if (!oss.silencesuppression)
|
||||
return 0;
|
||||
loudness = calc_loudness((short *)(buf));
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "loudness is %d\n", loudness);
|
||||
if (loudness < silencethreshold) {
|
||||
silentframes++;
|
||||
silbufcnt++;
|
||||
/* Keep track of the last few bits of silence so we can play
|
||||
them as lead-in when the time is right */
|
||||
if (silbufcnt >= SILBUF) {
|
||||
/* Make way for more buffer */
|
||||
memmove(silbuf, silbuf + FRAME_SIZE * 2, FRAME_SIZE * 2 * (SILBUF - 1));
|
||||
silbufcnt--;
|
||||
}
|
||||
memcpy(silbuf + FRAME_SIZE * 2 * silbufcnt, buf, FRAME_SIZE * 2);
|
||||
if (silentframes > 10) {
|
||||
/* We've had plenty of silence, so compress it now */
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
silentframes=0;
|
||||
/* Write any buffered silence we have, it may have something
|
||||
important */
|
||||
if (silbufcnt) {
|
||||
write(oss.sounddev, silbuf, silbufcnt * FRAME_SIZE);
|
||||
silbufcnt = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* reset and close the device if opened,
|
||||
* then open and initialize it in the desired mode,
|
||||
@ -518,12 +485,14 @@ static int setformat(struct chan_oss_pvt *o, int mode)
|
||||
}
|
||||
if (fmt != desired) {
|
||||
if (!(o->warned & WARN_speed)) {
|
||||
ast_log(LOG_WARNING, "Requested %d Hz, got %d Hz -- sound may be choppy\n", desired, fmt);
|
||||
ast_log(LOG_WARNING,
|
||||
"Requested %d Hz, got %d Hz -- sound may be choppy\n",
|
||||
desired, fmt);
|
||||
o->warned |= WARN_speed;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* on freebsd, SETFRAGMENT does not work very well on some cards.
|
||||
* on Freebsd, SETFRAGMENT does not work very well on some cards.
|
||||
* Default to use 256 bytes, let the user override
|
||||
*/
|
||||
if (o->frags) {
|
||||
@ -531,7 +500,8 @@ static int setformat(struct chan_oss_pvt *o, int mode)
|
||||
res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
|
||||
if (res < 0) {
|
||||
if (!(o->warned & WARN_frag)) {
|
||||
ast_log(LOG_WARNING, "Unable to set fragment size -- sound may be choppy\n");
|
||||
ast_log(LOG_WARNING,
|
||||
"Unable to set fragment size -- sound may be choppy\n");
|
||||
o->warned |= WARN_frag;
|
||||
}
|
||||
}
|
||||
@ -573,21 +543,29 @@ static int soundcard_setinput(struct chan_oss_pvt *o, int force)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* some of the standard methods supported by channels.
|
||||
*/
|
||||
static int oss_digit(struct ast_channel *c, char digit)
|
||||
{
|
||||
/* no better use for received digits than print them */
|
||||
ast_verbose( " << Console Received digit %c >> \n", digit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int oss_text(struct ast_channel *c, char *text)
|
||||
{
|
||||
/* print received messages */
|
||||
ast_verbose( " << Console Received text %s >> \n", text);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* request to play a sound on the speaker XXX fix oss. */
|
||||
/* Play ringtone 'x' on device 'o' */
|
||||
#define RING(o, x) { int what = x; write((o)->sndcmd[1], &what, sizeof(what)); }
|
||||
|
||||
/*
|
||||
* handler for incoming calls. Either autoanswer, or start ringing
|
||||
*/
|
||||
static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
||||
{
|
||||
struct chan_oss_pvt *o = c->pvt->pvt;
|
||||
@ -600,7 +578,7 @@ static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
||||
f.subclass = AST_CONTROL_ANSWER;
|
||||
ast_queue_frame(c, &f);
|
||||
} else {
|
||||
ast_verbose( " << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
|
||||
ast_verbose(" << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
|
||||
f.frametype = AST_FRAME_CONTROL;
|
||||
f.subclass = AST_CONTROL_RINGING;
|
||||
ast_queue_frame(c, &f);
|
||||
@ -609,17 +587,18 @@ static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void answer_sound(struct chan_oss_pvt *o)
|
||||
{
|
||||
RING(o, AST_CONTROL_ANSWER);
|
||||
}
|
||||
|
||||
/*
|
||||
* remote side answered the phone
|
||||
*/
|
||||
static int oss_answer(struct ast_channel *c)
|
||||
{
|
||||
struct chan_oss_pvt *o = c->pvt->pvt;
|
||||
|
||||
ast_verbose( " << Console call has been answered >> \n");
|
||||
answer_sound(o); /* XXX do we really need it ? considering we shut down immediately... */
|
||||
#if 0
|
||||
/* play an answer tone (XXX do we really need it ?) */
|
||||
RING(o, AST_CONTROL_ANSWER);
|
||||
#endif
|
||||
ast_setstate(c, AST_STATE_UP);
|
||||
o->cursound = -1;
|
||||
o->nosound=0;
|
||||
@ -661,7 +640,7 @@ static int oss_write(struct ast_channel *c, struct ast_frame *f)
|
||||
return 0;
|
||||
/* Stop any currently playing sound */
|
||||
o->cursound = -1;
|
||||
if (o->duplex != M_FULL) {
|
||||
if (o->duplex != M_FULL && !o->playbackonly) {
|
||||
/* XXX check this, looks weird! */
|
||||
/* If we're half duplex, we have to switch to read mode
|
||||
to honor immediate needs if necessary */
|
||||
@ -710,9 +689,6 @@ static int oss_write(struct ast_channel *c, struct ast_frame *f)
|
||||
|
||||
static struct ast_frame *oss_read(struct ast_channel *c)
|
||||
{
|
||||
/* XXX if we want multiple devices, should move these static vars
|
||||
* into the device descriptor
|
||||
*/
|
||||
int res;
|
||||
struct chan_oss_pvt *o = c->pvt->pvt;
|
||||
struct ast_frame *f = &o->read_f;
|
||||
@ -812,12 +788,12 @@ static struct ast_channel *oss_new(struct chan_oss_pvt *o,
|
||||
pvt->indicate = oss_indicate;
|
||||
pvt->fixup = oss_fixup;
|
||||
|
||||
if (strlen(ctx))
|
||||
strncpy(c->context, ctx, sizeof(o->ctx)-1);
|
||||
if (strlen(ext))
|
||||
strncpy(c->exten, ext, sizeof(o->ext)-1);
|
||||
if (strlen(o->language))
|
||||
strncpy(c->language, o->language, sizeof(o->language)-1);
|
||||
#define S_OVERRIDE(dst, src) \
|
||||
{ if (src && src[0] != '\0') /* non-empty string */ \
|
||||
strncpy((dst), src, sizeof(dst)-1); }
|
||||
S_OVERRIDE(c->context, ctx);
|
||||
S_OVERRIDE(c->exten, ext);
|
||||
S_OVERRIDE(c->language, o->language);
|
||||
o->owner = c;
|
||||
ast_setstate(c, state);
|
||||
ast_mutex_lock(&usecnt_lock);
|
||||
@ -928,11 +904,14 @@ static char autoanswer_usage[] =
|
||||
" argument, displays the current on/off status of autoanswer.\n"
|
||||
" The default value of autoanswer is in 'oss.conf'.\n";
|
||||
|
||||
/*
|
||||
* answer command from the console
|
||||
*/
|
||||
static int console_answer(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
|
||||
struct chan_oss_pvt *o = find_desc(oss_active);
|
||||
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
|
||||
if (argc != 1)
|
||||
return RESULT_SHOWUSAGE;
|
||||
if (!o->owner) {
|
||||
@ -942,7 +921,7 @@ static int console_answer(int fd, int argc, char *argv[])
|
||||
o->hookstate = 1;
|
||||
o->cursound = -1;
|
||||
ast_queue_frame(o->owner, &f);
|
||||
answer_sound(o);
|
||||
RING(o, AST_CONTROL_ANSWER);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
@ -1007,6 +986,32 @@ static char hangup_usage[] =
|
||||
" Hangs up any call currently placed on the console.\n";
|
||||
|
||||
|
||||
static int console_flash(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_FLASH };
|
||||
struct chan_oss_pvt *o = find_desc(oss_active);
|
||||
|
||||
if (argc != 1)
|
||||
return RESULT_SHOWUSAGE;
|
||||
o->cursound = -1;
|
||||
if (!o->owner) { /* XXX maybe !o->hookstate too ? */
|
||||
ast_cli(fd, "No call to flash\n");
|
||||
return RESULT_FAILURE;
|
||||
}
|
||||
o->hookstate = 0;
|
||||
if (o->owner) { /* XXX must be true, right ? */
|
||||
ast_queue_frame(o->owner, &f);
|
||||
}
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static char flash_usage[] =
|
||||
"Usage: flash\n"
|
||||
" Flashes the call currently placed on the console.\n";
|
||||
|
||||
|
||||
|
||||
static int console_dial(int fd, int argc, char *argv[])
|
||||
{
|
||||
char *tmp = NULL, *mye = NULL, *myc = NULL;
|
||||
@ -1030,6 +1035,7 @@ static int console_dial(int fd, int argc, char *argv[])
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
/* if we have an argument split it into extension and context */
|
||||
|
||||
if (argc == 2) {
|
||||
tmp = myc = strdup(argv[1]); /* make a writable copy */
|
||||
mye = strsep(&myc, "@"); /* set exten, advance to context */
|
||||
@ -1055,19 +1061,17 @@ static char dial_usage[] =
|
||||
static int console_transfer(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct chan_oss_pvt *o = find_desc(oss_active);
|
||||
struct ast_channel *b;
|
||||
|
||||
struct ast_channel *b = NULL;
|
||||
char *ext, *ctx;
|
||||
|
||||
if (argc != 2)
|
||||
return RESULT_SHOWUSAGE;
|
||||
if (o == NULL)
|
||||
return RESULT_FAILURE;
|
||||
if (! (o->owner && o->owner->bridge)) {
|
||||
if (o->owner == NULL || (b = o->owner->bridge) == NULL) {
|
||||
ast_cli(fd, "There is no call to transfer\n");
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
b = o->owner->bridge;
|
||||
|
||||
ext = ctx = strdup(argv[1]); /* make a writable copy */
|
||||
strsep(&ctx, "@"); /* set exten, advance to context */
|
||||
@ -1116,6 +1120,7 @@ static int console_active(int fd, int argc, char *argv[])
|
||||
static struct ast_cli_entry myclis[] = {
|
||||
{ { "answer", NULL }, console_answer, "Answer an incoming console call", answer_usage },
|
||||
{ { "hangup", NULL }, console_hangup, "Hangup a call on the console", hangup_usage },
|
||||
{ { "flash", NULL }, console_flash, "Flash a call on the console", flash_usage },
|
||||
{ { "dial", NULL }, console_dial, "Dial an extension on the console", dial_usage },
|
||||
{ { "transfer", NULL }, console_transfer, "Transfer a call to a different extension", transfer_usage },
|
||||
{ { "send", "text", NULL }, console_sendtext, "Send text to the remote device", sendtext_usage },
|
||||
@ -1177,28 +1182,22 @@ static struct chan_oss_pvt * store_config(struct ast_config *cfg,
|
||||
/* fill other fields from configuration */
|
||||
v = ast_variable_browse(cfg, ctg);
|
||||
while(v) {
|
||||
if (!strcasecmp(v->name, "autoanswer"))
|
||||
o->autoanswer = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "autohangup"))
|
||||
o->autohangup = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "silencesuppression"))
|
||||
o->silencesuppression = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "silencethreshold"))
|
||||
o->silencethreshold = atoi(v->value);
|
||||
else if (!strcasecmp(v->name, "device"))
|
||||
strncpy(o->device, v->value, sizeof(o->device)-1);
|
||||
else if (!strcasecmp(v->name, "frags"))
|
||||
o->frags = strtoul(v->value, NULL, 0);
|
||||
else if (!strcasecmp(v->name, "queuesize"))
|
||||
o->queuesize = strtoul(v->value, NULL, 0);
|
||||
else if (!strcasecmp(v->name, "context"))
|
||||
strncpy(o->ctx, v->value, sizeof(o->ctx)-1);
|
||||
else if (!strcasecmp(v->name, "language"))
|
||||
strncpy(o->language, v->value, sizeof(o->language)-1);
|
||||
else if (!strcasecmp(v->name, "extension"))
|
||||
strncpy(o->ext, v->value, sizeof(o->ext)-1);
|
||||
else if (!strcasecmp(v->name, "mixer"))
|
||||
store_mixer(o, v->value);
|
||||
M_START(v->name, v->value);
|
||||
|
||||
M_BOOL("autoanswer", o->autoanswer)
|
||||
M_BOOL("autohangup", o->autohangup)
|
||||
M_BOOL("playbackonly", o->playbackonly)
|
||||
M_BOOL("silencesuppression", o->silencesuppression)
|
||||
M_UINT("silencethreshold", o->silencethreshold )
|
||||
M_STR("device", o->device)
|
||||
M_UINT("frags", o->frags)
|
||||
M_UINT("debug", oss_debug)
|
||||
M_UINT("queuesize", o->queuesize)
|
||||
M_STR("context", o->ctx)
|
||||
M_STR("language", o->language)
|
||||
M_STR("extension", o->ext)
|
||||
M_F("mixer", store_mixer(o, v->value))
|
||||
M_END(;);
|
||||
v=v->next;
|
||||
}
|
||||
if (!strlen(o->device))
|
||||
@ -1263,12 +1262,19 @@ int load_module()
|
||||
}
|
||||
ast_destroy(cfg);
|
||||
}
|
||||
if (find_desc(oss_active) == NULL) {
|
||||
ast_log(LOG_NOTICE, "Device %s not found\n", oss_active);
|
||||
/* XXX we could default to 'dsp' perhaps ? */
|
||||
/* XXX should cleanup allocated memory etc. */
|
||||
return -1;
|
||||
}
|
||||
i = ast_channel_register(oss_default.type, tdesc,
|
||||
AST_FORMAT_SLINEAR, oss_request);
|
||||
if (i < 0) {
|
||||
ast_log(LOG_ERROR, "Unable to register channel class '%s'\n",
|
||||
oss_default.type);
|
||||
return NULL;
|
||||
/* XXX should cleanup allocated memory etc. */
|
||||
return -1;
|
||||
}
|
||||
for (i=0; i<sizeof(myclis)/sizeof(struct ast_cli_entry); i++)
|
||||
ast_cli_register(myclis + i);
|
||||
@ -1281,6 +1287,7 @@ int unload_module()
|
||||
int x;
|
||||
struct chan_oss_pvt *o;
|
||||
|
||||
/* XXX do we need a ast_channel_unregister oss_request ? */
|
||||
for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
|
||||
ast_cli_unregister(myclis + x);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user