b6be6b2cd9
Submited by: luigi o add mpg123 into runtime dependencies list.
1167 lines
32 KiB
C
1167 lines
32 KiB
C
|
|
$FreeBSD$
|
|
|
|
--- channels/chan_oss.c
|
|
+++ channels/chan_oss.c
|
|
@@ -13,6 +13,8 @@
|
|
*
|
|
* This program is free software, distributed under the terms of
|
|
* the GNU General Public License
|
|
+ *
|
|
+ * FreeBSD changes by Luigi Rizzo, 2005.04.18
|
|
*/
|
|
|
|
#include <asterisk/lock.h>
|
|
@@ -54,21 +56,30 @@
|
|
#endif
|
|
|
|
/* Lets use 160 sample frames, just like GSM. */
|
|
-#define FRAME_SIZE 160
|
|
+/* this corresponds to 20ms of audio. */
|
|
+#define FRAME_SIZE 160 // was 160
|
|
|
|
-/* When you set the frame size, you have to come up with
|
|
- the right buffer format as well. */
|
|
+/*
|
|
+ * When you set the frame size, you have to come up with
|
|
+ * the right buffer format as well.
|
|
+ * OSS lets you define a 'block' size (which should be a power of 2,
|
|
+ * which power is specified in the lower 16 bits) and the number of
|
|
+ * blocks allowed in the buffer (to avoid that the queue grows too large).
|
|
+ * The latter is specified in the top 16 bits.
|
|
+ * We use a block of 64 bytes (0x6), 5 blocks make a frame each sample
|
|
+ * being 2 bytes, and we make room to store two buffers.
|
|
+ * XXX the '10' is magic
|
|
+ */
|
|
+
|
|
+#define N_BLOCKS (buffersize * 5 * 2)
|
|
/* 5 64-byte frames = one frame */
|
|
-#define BUFFER_FMT ((buffersize * 10) << 16) | (0x0006);
|
|
+#define BUFFER_FMT (N_BLOCKS << 16) | (0x0006);
|
|
|
|
/* Don't switch between read/write modes faster than every 300 ms */
|
|
-#define MIN_SWITCH_TIME 600
|
|
+#define MIN_SWITCH_TIME 300
|
|
|
|
-static struct timeval lasttime;
|
|
|
|
static int usecnt;
|
|
-static int silencesuppression = 0;
|
|
-static int silencethreshold = 1000;
|
|
|
|
|
|
AST_MUTEX_DEFINE_STATIC(usecnt_lock);
|
|
@@ -78,16 +89,15 @@
|
|
static char *tdesc = "OSS Console Channel Driver";
|
|
static char *config = "oss.conf";
|
|
|
|
-static char context[AST_MAX_EXTENSION] = "default";
|
|
+static char default_context[AST_MAX_EXTENSION] = "default";
|
|
static char language[MAX_LANGUAGE] = "";
|
|
-static char exten[AST_MAX_EXTENSION] = "s";
|
|
+static char oss_exten[AST_MAX_EXTENSION] = "s";
|
|
|
|
-static int hookstate=0;
|
|
|
|
-static short silence[FRAME_SIZE] = {0, };
|
|
|
|
struct sound {
|
|
int ind;
|
|
+ char *desc;
|
|
short *data;
|
|
int datalen;
|
|
int samplen;
|
|
@@ -96,136 +106,178 @@
|
|
};
|
|
|
|
static struct sound sounds[] = {
|
|
- { AST_CONTROL_RINGING, ringtone, sizeof(ringtone)/2, 16000, 32000, 1 },
|
|
- { AST_CONTROL_BUSY, busy, sizeof(busy)/2, 4000, 4000, 1 },
|
|
- { AST_CONTROL_CONGESTION, busy, sizeof(busy)/2, 2000, 2000, 1 },
|
|
- { AST_CONTROL_RING, ring10, sizeof(ring10)/2, 16000, 32000, 1 },
|
|
- { AST_CONTROL_ANSWER, answer, sizeof(answer)/2, 2200, 0, 0 },
|
|
+ { AST_CONTROL_RINGING, "RINGING", ringtone, sizeof(ringtone)/2, 16000, 32000, 1 },
|
|
+ { AST_CONTROL_BUSY, "BUSY", busy, sizeof(busy)/2, 4000, 4000, 1 },
|
|
+ { AST_CONTROL_CONGESTION, "CONGESTION", busy, sizeof(busy)/2, 2000, 2000, 1 },
|
|
+ { AST_CONTROL_RING, "RING10", ring10, sizeof(ring10)/2, 16000, 32000, 1 },
|
|
+ { AST_CONTROL_ANSWER, "ANSWER", answer, sizeof(answer)/2, 2200, 0, 0 },
|
|
+ { -1, NULL, 0, 0, 0, 0 }, /* end marker */
|
|
};
|
|
|
|
-/* Sound command pipe */
|
|
-static int sndcmd[2];
|
|
+
|
|
|
|
static struct chan_oss_pvt {
|
|
/* We only have one OSS structure -- near sighted perhaps, but it
|
|
keeps this driver as simple as possible -- as it should be. */
|
|
+ /*
|
|
+ * cursound indicates which in struct sound we play. -1 means nothing,
|
|
+ * any other value is a valid sound, in which case sampsent indicates
|
|
+ * the next sample to send in [0..samplen + silencelen]
|
|
+ * nosound is set to disable the audio data from the channel
|
|
+ * (so we can play the tones etc.).
|
|
+ */
|
|
+ int sndcmd[2]; /* Sound command pipe */
|
|
+ int cursound; /* index of sound to send */
|
|
+ int sampsent; /* # of sound samples sent */
|
|
+ int nosound;
|
|
+
|
|
+ int total_blocks; /* total blocks in the output device */
|
|
+ int sounddev;
|
|
+ enum { M_UNSET, M_FULL, M_READ, M_WRITE } duplex;
|
|
+ int autoanswer;
|
|
+ int autohangup;
|
|
+ int hookstate;
|
|
+ struct timeval lasttime; /* last setformat */
|
|
+
|
|
+ int silencesuppression;
|
|
+ int silencethreshold;
|
|
+ char device[64]; /* device to open */
|
|
+
|
|
+ pthread_t sthread;
|
|
+
|
|
struct ast_channel *owner;
|
|
char exten[AST_MAX_EXTENSION];
|
|
char context[AST_MAX_EXTENSION];
|
|
-} oss;
|
|
+} oss = {
|
|
+ .cursound = -1,
|
|
+ .sounddev = -1,
|
|
+ .duplex = M_UNSET, /* XXX check this */
|
|
+ .autoanswer = 1,
|
|
+ .autohangup = 1,
|
|
+ .silencethreshold = 1000,
|
|
+};
|
|
|
|
-static int time_has_passed(void)
|
|
+/*
|
|
+ * returns true if too early to switch
|
|
+ */
|
|
+static int too_early(struct chan_oss_pvt *o)
|
|
{
|
|
struct timeval tv;
|
|
int ms;
|
|
gettimeofday(&tv, NULL);
|
|
- ms = (tv.tv_sec - lasttime.tv_sec) * 1000 +
|
|
- (tv.tv_usec - lasttime.tv_usec) / 1000;
|
|
- if (ms > MIN_SWITCH_TIME)
|
|
+ ms = (tv.tv_sec - o->lasttime.tv_sec) * 1000 +
|
|
+ (tv.tv_usec - o->lasttime.tv_usec) / 1000;
|
|
+ if (ms < MIN_SWITCH_TIME)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
-/* Number of buffers... Each is FRAMESIZE/8 ms long. For example
|
|
- with 160 sample frames, and a buffer size of 3, we have a 60ms buffer,
|
|
- usually plenty. */
|
|
-
|
|
-static pthread_t sthread;
|
|
-
|
|
-#define MAX_BUFFER_SIZE 100
|
|
-static int buffersize = 3;
|
|
-
|
|
-static int full_duplex = 0;
|
|
-
|
|
-/* Are we reading or writing (simulated full duplex) */
|
|
-static int readmode = 1;
|
|
-
|
|
-/* File descriptor for sound device */
|
|
-static int sounddev = -1;
|
|
-
|
|
-static int autoanswer = 1;
|
|
-
|
|
-#if 0
|
|
-static int calc_loudness(short *frame)
|
|
+/*
|
|
+ * Returns the number of blocks used in the audio output channel
|
|
+ */
|
|
+static int
|
|
+used_blocks(struct chan_oss_pvt *o)
|
|
{
|
|
- int sum = 0;
|
|
- int x;
|
|
- for (x=0;x<FRAME_SIZE;x++) {
|
|
- if (frame[x] < 0)
|
|
- sum -= frame[x];
|
|
- else
|
|
- sum += frame[x];
|
|
+ struct audio_buf_info info;
|
|
+ static int warned=0;
|
|
+ if (ioctl(o->sounddev, SNDCTL_DSP_GETOSPACE, &info)) {
|
|
+ if (!warned) {
|
|
+ ast_log(LOG_WARNING, "Error reading output space\n");
|
|
+ warned++;
|
|
}
|
|
- sum = sum/FRAME_SIZE;
|
|
- return sum;
|
|
+ return 1;
|
|
+ }
|
|
+ if (o->total_blocks == 0) {
|
|
+ ast_log(LOG_WARNING, "fragtotal %d size %d avail %d\n",
|
|
+ info.fragstotal,
|
|
+ info.fragsize,
|
|
+ info.fragments);
|
|
+ o->total_blocks = info.fragments;
|
|
+ }
|
|
+ return o->total_blocks - info.fragments;
|
|
}
|
|
-#endif
|
|
|
|
-static int cursound = -1;
|
|
-static int sampsent = 0;
|
|
-static int silencelen=0;
|
|
-static int offset=0;
|
|
-static int nosound=0;
|
|
+static int soundcard_writeframe(struct chan_oss_pvt *o, short *data)
|
|
+{
|
|
+ /* Write an exactly FRAME_SIZE sized of frame */
|
|
+ int res;
|
|
+ static int errors = 0;
|
|
|
|
-static int send_sound(void)
|
|
+ /*
|
|
+ * nothing spectacular.
|
|
+ * If the buffer is full just drop the extra, otherwise write
|
|
+ */
|
|
+ res = used_blocks(o);
|
|
+ if (res > 10) { /* no room to write a block */
|
|
+ errors ++;
|
|
+ if (errors == 0)
|
|
+ ast_log(LOG_WARNING, "write: used %d blocks (%d)\n", res, errors);
|
|
+ return 0;
|
|
+ }
|
|
+ errors = 0;
|
|
+ res = write(o->sounddev, ((void *)data), FRAME_SIZE * 2);
|
|
+ return res;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * handler for 'sound writable' events from the sound thread.
|
|
+ * Builds a frame from the high level description of the sounds,
|
|
+ * (tone+silence) and passes it to the audio device.
|
|
+ */
|
|
+static int send_sound(struct chan_oss_pvt *o)
|
|
{
|
|
short myframe[FRAME_SIZE];
|
|
- int total = FRAME_SIZE;
|
|
- short *frame = NULL;
|
|
- int amt=0;
|
|
- int res;
|
|
- int myoff;
|
|
- audio_buf_info abi;
|
|
- if (cursound > -1) {
|
|
- res = ioctl(sounddev, SNDCTL_DSP_GETOSPACE ,&abi);
|
|
- if (res) {
|
|
- ast_log(LOG_WARNING, "Unable to read output space\n");
|
|
- return -1;
|
|
- }
|
|
- /* Calculate how many samples we can send, max */
|
|
- if (total > (abi.fragments * abi.fragsize / 2))
|
|
- total = abi.fragments * abi.fragsize / 2;
|
|
- res = total;
|
|
- if (sampsent < sounds[cursound].samplen) {
|
|
- myoff=0;
|
|
- while(total) {
|
|
- amt = total;
|
|
- if (amt > (sounds[cursound].datalen - offset))
|
|
- amt = sounds[cursound].datalen - offset;
|
|
- memcpy(myframe + myoff, sounds[cursound].data + offset, amt * 2);
|
|
- total -= amt;
|
|
- offset += amt;
|
|
- sampsent += amt;
|
|
- myoff += amt;
|
|
- if (offset >= sounds[cursound].datalen)
|
|
- offset = 0;
|
|
- }
|
|
- /* Set it up for silence */
|
|
- if (sampsent >= sounds[cursound].samplen)
|
|
- silencelen = sounds[cursound].silencelen;
|
|
- frame = myframe;
|
|
- } else {
|
|
- if (silencelen > 0) {
|
|
- frame = silence;
|
|
- silencelen -= res;
|
|
- } else {
|
|
- if (sounds[cursound].repeat) {
|
|
- /* Start over */
|
|
- sampsent = 0;
|
|
- offset = 0;
|
|
- } else {
|
|
- cursound = -1;
|
|
- nosound = 0;
|
|
- }
|
|
- }
|
|
+ int ofs = 0;
|
|
+ int l_sampsent = o->sampsent;
|
|
+ int l;
|
|
+ struct sound *s;
|
|
+
|
|
+ if (o->cursound < 0) /* no sound to send */
|
|
+ return 0;
|
|
+ s = &sounds[o->cursound];
|
|
+ /*
|
|
+ * prepare a frame
|
|
+ */
|
|
+
|
|
+ for (ofs = 0; ofs < FRAME_SIZE; ofs += l) {
|
|
+ /* take chunks of sound and data until the buffer is full */
|
|
+ l = s->samplen - l_sampsent; /* sound available */
|
|
+ if (l > 0) {
|
|
+ if (l > FRAME_SIZE - ofs)
|
|
+ l = FRAME_SIZE - ofs;
|
|
+ if (0)
|
|
+ ast_log(LOG_WARNING, "send_sound sound %d/%d of %d into %d\n",
|
|
+ l_sampsent, l, s->samplen, ofs);
|
|
+ bcopy(s->data + l_sampsent, myframe + ofs, l*2);
|
|
+ l_sampsent += l;
|
|
+ } else { /* no sound, maybe some silence */
|
|
+ static short silence[FRAME_SIZE] = {0, };
|
|
+
|
|
+ l += s->silencelen;
|
|
+ if (l > 0) {
|
|
+ if (l > FRAME_SIZE - ofs)
|
|
+ l = FRAME_SIZE - ofs;
|
|
+ if (0)
|
|
+ ast_log(LOG_WARNING, "send_sound silence %d/%d of %d into %d\n",
|
|
+ l_sampsent - s->samplen, l, s->silencelen, ofs);
|
|
+ bcopy(silence, myframe + ofs, l*2);
|
|
+ l_sampsent += l;
|
|
+ } else { /* silence is over, restart sound if loop */
|
|
+ if (s->repeat == 0) { /* last block */
|
|
+ ast_log(LOG_WARNING, "send_sound last block\n");
|
|
+ o->cursound = -1;
|
|
+ o->nosound = 0; /* allow audio data */
|
|
+ if (ofs < FRAME_SIZE) /* pad with silence */
|
|
+ bcopy(silence, myframe + ofs, (FRAME_SIZE - ofs)*2);
|
|
+ }
|
|
+ l_sampsent = 0;
|
|
}
|
|
- if (frame)
|
|
- res = write(sounddev, frame, res * 2);
|
|
- if (res > 0)
|
|
- return 0;
|
|
- return res;
|
|
+ }
|
|
}
|
|
- return 0;
|
|
+ l = soundcard_writeframe(o, myframe);
|
|
+ if (l > 0)
|
|
+ o->sampsent = l_sampsent; /* update status */
|
|
+ return 0; /* fake success */
|
|
}
|
|
|
|
static void *sound_thread(void *unused)
|
|
@@ -235,41 +287,53 @@
|
|
int max;
|
|
int res;
|
|
char ign[4096];
|
|
- if (read(sounddev, ign, sizeof(sounddev)) < 0)
|
|
+ if (read(oss.sounddev, ign, sizeof(ign)) < 0)
|
|
ast_log(LOG_WARNING, "Read error on sound device: %s\n", strerror(errno));
|
|
for(;;) {
|
|
FD_ZERO(&rfds);
|
|
FD_ZERO(&wfds);
|
|
- max = sndcmd[0];
|
|
- FD_SET(sndcmd[0], &rfds);
|
|
+ max = oss.sndcmd[0];
|
|
+ FD_SET(oss.sndcmd[0], &rfds);
|
|
if (!oss.owner) {
|
|
- FD_SET(sounddev, &rfds);
|
|
- if (sounddev > max)
|
|
- max = sounddev;
|
|
+ FD_SET(oss.sounddev, &rfds);
|
|
+ if (oss.sounddev > max)
|
|
+ max = oss.sounddev;
|
|
}
|
|
- if (cursound > -1) {
|
|
- FD_SET(sounddev, &wfds);
|
|
- if (sounddev > max)
|
|
- max = sounddev;
|
|
+ if (oss.cursound > -1) {
|
|
+ FD_SET(oss.sounddev, &wfds);
|
|
+ if (oss.sounddev > max)
|
|
+ max = oss.sounddev;
|
|
}
|
|
res = ast_select(max + 1, &rfds, &wfds, NULL, NULL);
|
|
if (res < 1) {
|
|
ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno));
|
|
continue;
|
|
}
|
|
- if (FD_ISSET(sndcmd[0], &rfds)) {
|
|
- read(sndcmd[0], &cursound, sizeof(cursound));
|
|
- silencelen = 0;
|
|
- offset = 0;
|
|
- sampsent = 0;
|
|
+ if (FD_ISSET(oss.sndcmd[0], &rfds)) { /* read which sound to play from the pipe */
|
|
+ int i, what;
|
|
+
|
|
+ read(oss.sndcmd[0], &what, sizeof(what));
|
|
+ for (i = 0; sounds[i].ind != -1; i++)
|
|
+ if (sounds[i].ind == what) {
|
|
+ oss.cursound = i;
|
|
+ oss.sampsent = 0;
|
|
+ oss.nosound = 1; /* block other audio */
|
|
+ ast_log(LOG_WARNING, "play %s\n", sounds[i].desc);
|
|
+ break;
|
|
+ }
|
|
+ if (sounds[i].ind == -1)
|
|
+ oss.cursound = -1;
|
|
+ ast_log(LOG_WARNING, "cursound %d samplen %d silencelen %d\n",
|
|
+ oss.cursound, oss.cursound >=0 ? sounds[oss.cursound].samplen : -1,
|
|
+ oss.cursound >=0 ? sounds[oss.cursound].silencelen : -1);
|
|
}
|
|
- if (FD_ISSET(sounddev, &rfds)) {
|
|
+ if (FD_ISSET(oss.sounddev, &rfds)) {
|
|
/* Ignore read */
|
|
- if (read(sounddev, ign, sizeof(ign)) < 0)
|
|
+ if (read(oss.sounddev, ign, sizeof(ign)) < 0)
|
|
ast_log(LOG_WARNING, "Read error on sound device: %s\n", strerror(errno));
|
|
}
|
|
- if (FD_ISSET(sounddev, &wfds))
|
|
- if (send_sound())
|
|
+ if (FD_ISSET(oss.sounddev, &wfds))
|
|
+ if (send_sound(&oss) < 0)
|
|
ast_log(LOG_WARNING, "Failed to write sound\n");
|
|
}
|
|
/* Never reached */
|
|
@@ -277,6 +341,20 @@
|
|
}
|
|
|
|
#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
|
|
@@ -284,7 +362,7 @@
|
|
static int silentframes = 0;
|
|
static char silbuf[FRAME_SIZE * 2 * SILBUF];
|
|
static int silbufcnt=0;
|
|
- if (!silencesuppression)
|
|
+ if (!oss.silencesuppression)
|
|
return 0;
|
|
loudness = calc_loudness((short *)(buf));
|
|
if (option_debug)
|
|
@@ -309,7 +387,7 @@
|
|
/* Write any buffered silence we have, it may have something
|
|
important */
|
|
if (silbufcnt) {
|
|
- write(sounddev, silbuf, silbufcnt * FRAME_SIZE);
|
|
+ write(oss.sounddev, silbuf, silbufcnt * FRAME_SIZE);
|
|
silbufcnt = 0;
|
|
}
|
|
}
|
|
@@ -317,27 +395,55 @@
|
|
}
|
|
#endif
|
|
|
|
-static int setformat(void)
|
|
+/*
|
|
+ * reset and close the device if opened,
|
|
+ * then open and initialize it in the desired mode,
|
|
+ * trigger reads and writes so we can start using it.
|
|
+ */
|
|
+static int setformat(struct chan_oss_pvt *o, int mode)
|
|
{
|
|
- int fmt, desired, res, fd = sounddev;
|
|
+ int fmt, desired, res, fd;
|
|
static int warnedalready = 0;
|
|
static int warnedalready2 = 0;
|
|
+
|
|
+ if (o->sounddev >= 0) {
|
|
+ ioctl(o->sounddev, SNDCTL_DSP_RESET, 0);
|
|
+ close(o->sounddev);
|
|
+ o->duplex = M_UNSET;
|
|
+ }
|
|
+ fd = o->sounddev = open(o->device, mode |O_NONBLOCK);
|
|
+ if (o->sounddev < 0) {
|
|
+ ast_log(LOG_WARNING, "Unable to re-open DSP device: %s\n",
|
|
+ strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ gettimeofday(&o->lasttime, NULL);
|
|
fmt = AFMT_S16_LE;
|
|
res = ioctl(fd, SNDCTL_DSP_SETFMT, &fmt);
|
|
if (res < 0) {
|
|
ast_log(LOG_WARNING, "Unable to set format to 16-bit signed\n");
|
|
return -1;
|
|
}
|
|
- res = ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
|
|
-
|
|
- /* Check to see if duplex set (FreeBSD Bug)*/
|
|
- res = ioctl(fd, SNDCTL_DSP_GETCAPS, &fmt);
|
|
-
|
|
- if ((fmt & DSP_CAP_DUPLEX) && !res) {
|
|
- if (option_verbose > 1)
|
|
+ switch (mode) {
|
|
+ case O_RDWR:
|
|
+ res = ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
|
|
+ /* Check to see if duplex set (FreeBSD Bug)*/
|
|
+ res = ioctl(fd, SNDCTL_DSP_GETCAPS, &fmt);
|
|
+ if (res == 0 && (fmt & DSP_CAP_DUPLEX)) {
|
|
+ if (option_verbose > 1)
|
|
ast_verbose(VERBOSE_PREFIX_2 "Console is full duplex\n");
|
|
- full_duplex = -1;
|
|
+ o->duplex = M_FULL;
|
|
+ };
|
|
+ break;
|
|
+ case O_WRONLY:
|
|
+ o->duplex = M_WRITE;
|
|
+ break;
|
|
+ case O_RDONLY:
|
|
+ o->duplex = M_READ;
|
|
+ break;
|
|
}
|
|
+
|
|
fmt = 0;
|
|
res = ioctl(fd, SNDCTL_DSP_STEREO, &fmt);
|
|
if (res < 0) {
|
|
@@ -348,6 +454,7 @@
|
|
desired = 8000;
|
|
fmt = desired;
|
|
res = ioctl(fd, SNDCTL_DSP_SPEED, &fmt);
|
|
+
|
|
if (res < 0) {
|
|
ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
|
|
return -1;
|
|
@@ -357,89 +464,54 @@
|
|
ast_log(LOG_WARNING, "Requested %d Hz, got %d Hz -- sound may be choppy\n", desired, fmt);
|
|
}
|
|
#if 1
|
|
- fmt = BUFFER_FMT;
|
|
+ /*
|
|
+ * on freebsd, SETFRAGMENT does not work very well on some cards.
|
|
+ * Better leave it out
|
|
+ */
|
|
+
|
|
+ // fmt = BUFFER_FMT;
|
|
+ fmt = 0x8; // 256-bytes fragment
|
|
res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
|
|
if (res < 0) {
|
|
if (!warnedalready2++)
|
|
ast_log(LOG_WARNING, "Unable to set fragment size -- sound may be choppy\n");
|
|
}
|
|
#endif
|
|
+ /* XXX on some cards, we need SNDCTL_DSP_SETTRIGGER to start outputting */
|
|
+ res = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;
|
|
+ res = ioctl(fd, SNDCTL_DSP_SETTRIGGER, &res);
|
|
+ /* it may fail if we are in half duplex, never mind */
|
|
return 0;
|
|
}
|
|
|
|
+/*
|
|
+ * make sure output mode is available. Returns 0 if done,
|
|
+ * 1 if too early to switch, -1 if error
|
|
+ */
|
|
static int soundcard_setoutput(int force)
|
|
{
|
|
- /* Make sure the soundcard is in output mode. */
|
|
- int fd = sounddev;
|
|
- if (full_duplex || (!readmode && !force))
|
|
- return 0;
|
|
- readmode = 0;
|
|
- if (force || time_has_passed()) {
|
|
- ioctl(sounddev, SNDCTL_DSP_RESET, 0);
|
|
- /* Keep the same fd reserved by closing the sound device and copying stdin at the same
|
|
- time. */
|
|
- /* dup2(0, sound); */
|
|
- close(sounddev);
|
|
- fd = open(DEV_DSP, O_WRONLY |O_NONBLOCK);
|
|
- if (fd < 0) {
|
|
- ast_log(LOG_WARNING, "Unable to re-open DSP device: %s\n", strerror(errno));
|
|
- return -1;
|
|
- }
|
|
- /* dup2 will close the original and make fd be sound */
|
|
- if (dup2(fd, sounddev) < 0) {
|
|
- ast_log(LOG_WARNING, "dup2() failed: %s\n", strerror(errno));
|
|
- return -1;
|
|
- }
|
|
- if (setformat()) {
|
|
- return -1;
|
|
- }
|
|
+ if (oss.duplex == M_FULL || (oss.duplex == M_WRITE && !force))
|
|
return 0;
|
|
- }
|
|
- return 1;
|
|
+ if (!force && too_early(&oss))
|
|
+ return 1;
|
|
+ if (setformat(&oss, O_WRONLY))
|
|
+ return -1;
|
|
+ return 0;
|
|
}
|
|
|
|
+/*
|
|
+ * make sure input mode is available. Returns 0 if done
|
|
+ * 1 if too early to switch, -1 if error
|
|
+ */
|
|
static int soundcard_setinput(int force)
|
|
{
|
|
- int fd = sounddev;
|
|
- if (full_duplex || (readmode && !force))
|
|
- return 0;
|
|
- readmode = -1;
|
|
- if (force || time_has_passed()) {
|
|
- ioctl(sounddev, SNDCTL_DSP_RESET, 0);
|
|
- close(sounddev);
|
|
- /* dup2(0, sound); */
|
|
- fd = open(DEV_DSP, O_RDONLY | O_NONBLOCK);
|
|
- if (fd < 0) {
|
|
- ast_log(LOG_WARNING, "Unable to re-open DSP device: %s\n", strerror(errno));
|
|
- return -1;
|
|
- }
|
|
- /* dup2 will close the original and make fd be sound */
|
|
- if (dup2(fd, sounddev) < 0) {
|
|
- ast_log(LOG_WARNING, "dup2() failed: %s\n", strerror(errno));
|
|
- return -1;
|
|
- }
|
|
- if (setformat()) {
|
|
- return -1;
|
|
- }
|
|
+ if (oss.duplex == M_FULL || (oss.duplex == M_READ && !force))
|
|
return 0;
|
|
- }
|
|
- return 1;
|
|
-}
|
|
-
|
|
-static int soundcard_init(void)
|
|
-{
|
|
- /* Assume it's full duplex for starters */
|
|
- int fd = open(DEV_DSP, O_RDWR | O_NONBLOCK);
|
|
- if (fd < 0) {
|
|
- ast_log(LOG_WARNING, "Unable to open %s: %s\n", DEV_DSP, strerror(errno));
|
|
- return fd;
|
|
- }
|
|
- gettimeofday(&lasttime, NULL);
|
|
- sounddev = fd;
|
|
- setformat();
|
|
- if (!full_duplex)
|
|
- soundcard_setinput(1);
|
|
- return sounddev;
|
|
+ if (!force && too_early(&oss))
|
|
+ return 1;
|
|
+ if (setformat(&oss, O_RDONLY))
|
|
+ return -1;
|
|
+ return 0;
|
|
}
|
|
|
|
static int oss_digit(struct ast_channel *c, char digit)
|
|
@@ -454,120 +526,81 @@
|
|
return 0;
|
|
}
|
|
|
|
+/* request to play a sound on the speaker */
|
|
+#define RING(x) { int what = x; write(oss.sndcmd[1], &what, sizeof(what)); }
|
|
+
|
|
static int oss_call(struct ast_channel *c, char *dest, int timeout)
|
|
{
|
|
- int res = 3;
|
|
struct ast_frame f = { 0, };
|
|
ast_verbose( " << Call placed to '%s' on console >> \n", dest);
|
|
- if (autoanswer) {
|
|
+ if (oss.autoanswer) {
|
|
ast_verbose( " << Auto-answered >> \n" );
|
|
f.frametype = AST_FRAME_CONTROL;
|
|
f.subclass = AST_CONTROL_ANSWER;
|
|
ast_queue_frame(c, &f);
|
|
} else {
|
|
- nosound = 1;
|
|
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);
|
|
- write(sndcmd[1], &res, sizeof(res));
|
|
+ RING(AST_CONTROL_RING);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void answer_sound(void)
|
|
{
|
|
- int res;
|
|
- nosound = 1;
|
|
- res = 4;
|
|
- write(sndcmd[1], &res, sizeof(res));
|
|
-
|
|
+ RING(AST_CONTROL_ANSWER);
|
|
}
|
|
|
|
static int oss_answer(struct ast_channel *c)
|
|
{
|
|
ast_verbose( " << Console call has been answered >> \n");
|
|
- answer_sound();
|
|
+ answer_sound(); /* XXX do we really need it ? considering we shut down immediately... */
|
|
ast_setstate(c, AST_STATE_UP);
|
|
- cursound = -1;
|
|
- nosound=0;
|
|
+ oss.cursound = -1;
|
|
+ oss.nosound=0;
|
|
return 0;
|
|
}
|
|
|
|
static int oss_hangup(struct ast_channel *c)
|
|
{
|
|
- int res = 0;
|
|
- cursound = -1;
|
|
+ oss.cursound = -1;
|
|
c->pvt->pvt = NULL;
|
|
oss.owner = NULL;
|
|
ast_verbose( " << Hangup on console >> \n");
|
|
ast_mutex_lock(&usecnt_lock);
|
|
usecnt--;
|
|
ast_mutex_unlock(&usecnt_lock);
|
|
- if (hookstate) {
|
|
- if (autoanswer) {
|
|
+ if (oss.hookstate) {
|
|
+ if (oss.autoanswer || oss.autohangup) {
|
|
/* Assume auto-hangup too */
|
|
- hookstate = 0;
|
|
+ oss.hookstate = 0;
|
|
} else {
|
|
/* Make congestion noise */
|
|
- res = 2;
|
|
- write(sndcmd[1], &res, sizeof(res));
|
|
+ RING(AST_CONTROL_CONGESTION);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
-static int soundcard_writeframe(short *data)
|
|
-{
|
|
- /* Write an exactly FRAME_SIZE sized of frame */
|
|
- static int bufcnt = 0;
|
|
- static short buffer[FRAME_SIZE * MAX_BUFFER_SIZE * 5];
|
|
- struct audio_buf_info info;
|
|
- int res;
|
|
- int fd = sounddev;
|
|
- static int warned=0;
|
|
- if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info)) {
|
|
- if (!warned)
|
|
- ast_log(LOG_WARNING, "Error reading output space\n");
|
|
- bufcnt = buffersize;
|
|
- warned++;
|
|
- }
|
|
- if ((info.fragments >= buffersize * 5) && (bufcnt == buffersize)) {
|
|
- /* We've run out of stuff, buffer again */
|
|
- bufcnt = 0;
|
|
- }
|
|
- if (bufcnt == buffersize) {
|
|
- /* Write sample immediately */
|
|
- res = write(fd, ((void *)data), FRAME_SIZE * 2);
|
|
- } else {
|
|
- /* Copy the data into our buffer */
|
|
- res = FRAME_SIZE * 2;
|
|
- memcpy(buffer + (bufcnt * FRAME_SIZE), data, FRAME_SIZE * 2);
|
|
- bufcnt++;
|
|
- if (bufcnt == buffersize) {
|
|
- res = write(fd, ((void *)buffer), FRAME_SIZE * 2 * buffersize);
|
|
- }
|
|
- }
|
|
- return res;
|
|
-}
|
|
-
|
|
-
|
|
+/* used for data coming from the network */
|
|
static int oss_write(struct ast_channel *chan, struct ast_frame *f)
|
|
{
|
|
int res;
|
|
- static char sizbuf[8000];
|
|
- static int sizpos = 0;
|
|
- int len = sizpos;
|
|
- int pos;
|
|
+ int src;
|
|
+
|
|
+ // ast_log(LOG_WARNING, "oss_write size %d\n", f->datalen);
|
|
/* Immediately return if no sound is enabled */
|
|
- if (nosound)
|
|
+ if (oss.nosound)
|
|
return 0;
|
|
/* Stop any currently playing sound */
|
|
- cursound = -1;
|
|
- if (!full_duplex) {
|
|
+ oss.cursound = -1;
|
|
+ if (oss.duplex != M_FULL) {
|
|
+ /* XXX check this, looks weird! */
|
|
/* If we're half duplex, we have to switch to read mode
|
|
to honor immediate needs if necessary */
|
|
- res = soundcard_setinput(1);
|
|
+ res = soundcard_setinput(1); /* force set if not full_duplex */
|
|
if (res < 0) {
|
|
ast_log(LOG_WARNING, "Unable to set device to input mode\n");
|
|
return -1;
|
|
@@ -583,21 +616,30 @@
|
|
so just pretend we wrote it */
|
|
return 0;
|
|
}
|
|
- /* We have to digest the frame in 160-byte portions */
|
|
- if (f->datalen > sizeof(sizbuf) - sizpos) {
|
|
- ast_log(LOG_WARNING, "Frame too large\n");
|
|
- return -1;
|
|
- }
|
|
- memcpy(sizbuf + sizpos, f->data, f->datalen);
|
|
- len += f->datalen;
|
|
- pos = 0;
|
|
- while(len - pos > FRAME_SIZE * 2) {
|
|
- soundcard_writeframe((short *)(sizbuf + pos));
|
|
- pos += FRAME_SIZE * 2;
|
|
+ /*
|
|
+ * we could receive a sample which is not a multiple of our FRAME_SIZE,
|
|
+ * so we buffer it locally and write to the device in FRAME_SIZE
|
|
+ * chunks, keeping the residue stored for future use.
|
|
+ */
|
|
+
|
|
+ src = 0; /* read position into f->data */
|
|
+ while ( src < f->datalen ) {
|
|
+ static char buf[FRAME_SIZE*2];
|
|
+ static int dst = 0;
|
|
+ int l = sizeof(buf) - dst; /* how much room in the buffer */
|
|
+
|
|
+ if (f->datalen - src >= l) { /* enough to fill a frame */
|
|
+ memcpy(buf + dst, f->data + src, l);
|
|
+ soundcard_writeframe(&oss, (short *)buf);
|
|
+ src += l;
|
|
+ dst = 0;
|
|
+ } else { /* copy residue */
|
|
+ l = f->datalen - src;
|
|
+ memcpy(buf + dst, f->data + src, l);
|
|
+ src += l; /* but really, we are done */
|
|
+ dst += l;
|
|
+ }
|
|
}
|
|
- if (len - pos)
|
|
- memmove(sizbuf, sizbuf + pos, len - pos);
|
|
- sizpos = len - pos;
|
|
return 0;
|
|
}
|
|
|
|
@@ -628,18 +670,15 @@
|
|
ast_log(LOG_WARNING, "Unable to set input mode\n");
|
|
return NULL;
|
|
}
|
|
- if (res > 0) {
|
|
+ if (res > 0) { /* too early to switch ? */
|
|
/* Theoretically shouldn't happen, but anyway, return a NULL frame */
|
|
return &f;
|
|
}
|
|
- res = read(sounddev, buf + AST_FRIENDLY_OFFSET + readpos, FRAME_SIZE * 2 - readpos);
|
|
- if (res < 0) {
|
|
- ast_log(LOG_WARNING, "Error reading from sound device (If you're running 'artsd' then kill it): %s\n", strerror(errno));
|
|
-#if 0
|
|
- CRASH;
|
|
-#endif
|
|
- return NULL;
|
|
- }
|
|
+
|
|
+ res = read(oss.sounddev, buf + AST_FRIENDLY_OFFSET + readpos, FRAME_SIZE * 2 - readpos);
|
|
+ // ast_log(LOG_WARNING, "oss_read() fd %d got %d\n", oss.sounddev, res);
|
|
+ if (res < 0) /* audio data not ready, return a NULL frame */
|
|
+ return &f;
|
|
readpos += res;
|
|
|
|
if (readpos >= FRAME_SIZE * 2) {
|
|
@@ -682,64 +721,66 @@
|
|
int res;
|
|
switch(cond) {
|
|
case AST_CONTROL_BUSY:
|
|
- res = 1;
|
|
- break;
|
|
case AST_CONTROL_CONGESTION:
|
|
- res = 2;
|
|
- break;
|
|
case AST_CONTROL_RINGING:
|
|
- res = 0;
|
|
+ res = cond;
|
|
break;
|
|
case -1:
|
|
- cursound = -1;
|
|
+ oss.cursound = -1;
|
|
return 0;
|
|
default:
|
|
ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, chan->name);
|
|
return -1;
|
|
}
|
|
if (res > -1) {
|
|
- write(sndcmd[1], &res, sizeof(res));
|
|
+ RING(res);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
-static struct ast_channel *oss_new(struct chan_oss_pvt *p, int state)
|
|
+static struct ast_channel *oss_new(struct chan_oss_pvt *oss, int state)
|
|
{
|
|
struct ast_channel *tmp;
|
|
+ struct ast_channel_pvt *pvt;
|
|
+
|
|
tmp = ast_channel_alloc(1);
|
|
- if (tmp) {
|
|
- snprintf(tmp->name, sizeof(tmp->name), "OSS/%s", DEV_DSP + 5);
|
|
- tmp->type = type;
|
|
- tmp->fds[0] = sounddev;
|
|
- tmp->nativeformats = AST_FORMAT_SLINEAR;
|
|
- tmp->pvt->pvt = p;
|
|
- tmp->pvt->send_digit = oss_digit;
|
|
- tmp->pvt->send_text = oss_text;
|
|
- tmp->pvt->hangup = oss_hangup;
|
|
- tmp->pvt->answer = oss_answer;
|
|
- tmp->pvt->read = oss_read;
|
|
- tmp->pvt->call = oss_call;
|
|
- tmp->pvt->write = oss_write;
|
|
- tmp->pvt->indicate = oss_indicate;
|
|
- tmp->pvt->fixup = oss_fixup;
|
|
- if (strlen(p->context))
|
|
- strncpy(tmp->context, p->context, sizeof(tmp->context)-1);
|
|
- if (strlen(p->exten))
|
|
- strncpy(tmp->exten, p->exten, sizeof(tmp->exten)-1);
|
|
- if (strlen(language))
|
|
- strncpy(tmp->language, language, sizeof(tmp->language)-1);
|
|
- p->owner = tmp;
|
|
- ast_setstate(tmp, state);
|
|
- ast_mutex_lock(&usecnt_lock);
|
|
- usecnt++;
|
|
- ast_mutex_unlock(&usecnt_lock);
|
|
- ast_update_use_count();
|
|
- if (state != AST_STATE_DOWN) {
|
|
- if (ast_pbx_start(tmp)) {
|
|
- ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
|
|
- ast_hangup(tmp);
|
|
- tmp = NULL;
|
|
- }
|
|
+ if (tmp == NULL)
|
|
+ return NULL;
|
|
+ snprintf(tmp->name, sizeof(tmp->name), "OSS/%s", oss->device + 5);
|
|
+ tmp->type = type;
|
|
+ tmp->fds[0] = oss->sounddev;
|
|
+ tmp->nativeformats = AST_FORMAT_SLINEAR;
|
|
+ pvt = tmp->pvt;
|
|
+ pvt->pvt = oss;
|
|
+#if 1
|
|
+ pvt->send_digit = oss_digit;
|
|
+ pvt->send_text = oss_text;
|
|
+ pvt->hangup = oss_hangup;
|
|
+ pvt->answer = oss_answer;
|
|
+ pvt->read = oss_read;
|
|
+ pvt->call = oss_call;
|
|
+ pvt->write = oss_write;
|
|
+ pvt->indicate = oss_indicate;
|
|
+ pvt->fixup = oss_fixup;
|
|
+#endif
|
|
+ if (strlen(oss->context))
|
|
+ strncpy(tmp->context, oss->context, sizeof(tmp->context)-1);
|
|
+ if (strlen(oss->exten))
|
|
+ strncpy(tmp->exten, oss->exten, sizeof(tmp->exten)-1);
|
|
+ if (strlen(language))
|
|
+ strncpy(tmp->language, language, sizeof(tmp->language)-1);
|
|
+ oss->owner = tmp;
|
|
+ ast_setstate(tmp, state);
|
|
+ ast_mutex_lock(&usecnt_lock);
|
|
+ usecnt++;
|
|
+ ast_mutex_unlock(&usecnt_lock);
|
|
+ ast_update_use_count();
|
|
+ if (state != AST_STATE_DOWN) {
|
|
+ if (ast_pbx_start(tmp)) {
|
|
+ ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
|
|
+ ast_hangup(tmp);
|
|
+ tmp = NULL;
|
|
+ /* XXX what about oss->owner and the channel itself ? */
|
|
}
|
|
}
|
|
return tmp;
|
|
@@ -770,13 +811,13 @@
|
|
if ((argc != 1) && (argc != 2))
|
|
return RESULT_SHOWUSAGE;
|
|
if (argc == 1) {
|
|
- ast_cli(fd, "Auto answer is %s.\n", autoanswer ? "on" : "off");
|
|
+ ast_cli(fd, "Auto answer is %s.\n", oss.autoanswer ? "on" : "off");
|
|
return RESULT_SUCCESS;
|
|
} else {
|
|
if (!strcasecmp(argv[1], "on"))
|
|
- autoanswer = -1;
|
|
+ oss.autoanswer = -1;
|
|
else if (!strcasecmp(argv[1], "off"))
|
|
- autoanswer = 0;
|
|
+ oss.autoanswer = 0;
|
|
else
|
|
return RESULT_SHOWUSAGE;
|
|
}
|
|
@@ -788,12 +829,14 @@
|
|
#ifndef MIN
|
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
|
#endif
|
|
+ int l = strlen(word);
|
|
+
|
|
switch(state) {
|
|
case 0:
|
|
- if (strlen(word) && !strncasecmp(word, "on", MIN(strlen(word), 2)))
|
|
+ if (l && !strncasecmp(word, "on", MIN(l, 2)))
|
|
return strdup("on");
|
|
case 1:
|
|
- if (strlen(word) && !strncasecmp(word, "off", MIN(strlen(word), 3)))
|
|
+ if (l && !strncasecmp(word, "off", MIN(l, 3)))
|
|
return strdup("off");
|
|
default:
|
|
return NULL;
|
|
@@ -816,8 +859,8 @@
|
|
ast_cli(fd, "No one is calling us\n");
|
|
return RESULT_FAILURE;
|
|
}
|
|
- hookstate = 1;
|
|
- cursound = -1;
|
|
+ oss.hookstate = 1;
|
|
+ oss.cursound = -1;
|
|
ast_queue_frame(oss.owner, &f);
|
|
answer_sound();
|
|
return RESULT_SUCCESS;
|
|
@@ -863,12 +906,12 @@
|
|
{
|
|
if (argc != 1)
|
|
return RESULT_SHOWUSAGE;
|
|
- cursound = -1;
|
|
- if (!oss.owner && !hookstate) {
|
|
+ oss.cursound = -1;
|
|
+ if (!oss.owner && !oss.hookstate) {
|
|
ast_cli(fd, "No call to hangup up\n");
|
|
return RESULT_FAILURE;
|
|
}
|
|
- hookstate = 0;
|
|
+ oss.hookstate = 0;
|
|
if (oss.owner) {
|
|
ast_queue_hangup(oss.owner);
|
|
}
|
|
@@ -900,8 +943,8 @@
|
|
}
|
|
return RESULT_SUCCESS;
|
|
}
|
|
- mye = exten;
|
|
- myc = context;
|
|
+ mye = oss_exten;
|
|
+ myc = default_context;
|
|
if (argc == 2) {
|
|
char *stringp=NULL;
|
|
strncpy(tmp, argv[1], sizeof(tmp)-1);
|
|
@@ -916,7 +959,7 @@
|
|
if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
|
|
strncpy(oss.exten, mye, sizeof(oss.exten)-1);
|
|
strncpy(oss.context, myc, sizeof(oss.context)-1);
|
|
- hookstate = 1;
|
|
+ oss.hookstate = 1;
|
|
oss_new(&oss, AST_STATE_RINGING);
|
|
} else
|
|
ast_cli(fd, "No such extension '%s' in context '%s'\n", mye, myc);
|
|
@@ -974,21 +1017,47 @@
|
|
int res;
|
|
int x;
|
|
struct ast_config *cfg;
|
|
- struct ast_variable *v;
|
|
- res = pipe(sndcmd);
|
|
+
|
|
+ res = pipe(oss.sndcmd);
|
|
if (res) {
|
|
ast_log(LOG_ERROR, "Unable to create pipe\n");
|
|
return -1;
|
|
}
|
|
- res = soundcard_init();
|
|
- if (res < 0) {
|
|
+ /* load config file */
|
|
+ if ((cfg = ast_load(config))) {
|
|
+ struct ast_variable *v = ast_variable_browse(cfg, "general");
|
|
+ while(v) {
|
|
+ if (!strcasecmp(v->name, "autoanswer"))
|
|
+ oss.autoanswer = ast_true(v->value);
|
|
+ else if (!strcasecmp(v->name, "autohangup"))
|
|
+ oss.autohangup = ast_true(v->value);
|
|
+ else if (!strcasecmp(v->name, "oss.silencesuppression"))
|
|
+ oss.silencesuppression = ast_true(v->value);
|
|
+ else if (!strcasecmp(v->name, "silencethreshold"))
|
|
+ oss.silencethreshold = atoi(v->value);
|
|
+ else if (!strcasecmp(v->name, "device"))
|
|
+ strncpy(oss.device, v->value, sizeof(oss.device)-1);
|
|
+ else if (!strcasecmp(v->name, "context"))
|
|
+ strncpy(default_context, v->value, sizeof(default_context)-1);
|
|
+ else if (!strcasecmp(v->name, "language"))
|
|
+ strncpy(language, v->value, sizeof(language)-1);
|
|
+ else if (!strcasecmp(v->name, "extension"))
|
|
+ strncpy(oss_exten, v->value, sizeof(oss_exten)-1);
|
|
+ v=v->next;
|
|
+ }
|
|
+ ast_destroy(cfg);
|
|
+ }
|
|
+ if (!strlen(oss.device))
|
|
+ strncpy(oss.device, DEV_DSP, sizeof(oss.device)-1);
|
|
+ if (setformat(&oss, O_RDWR) < 0) { /* open device */
|
|
if (option_verbose > 1) {
|
|
ast_verbose(VERBOSE_PREFIX_2 "No sound card detected -- console channel will be unavailable\n");
|
|
ast_verbose(VERBOSE_PREFIX_2 "Turn off OSS support by adding 'noload=chan_oss.so' in /etc/asterisk/modules.conf\n");
|
|
}
|
|
return 0;
|
|
}
|
|
- if (!full_duplex)
|
|
+ soundcard_setinput(1); /* force set if not full_duplex */
|
|
+ if (oss.duplex != M_FULL)
|
|
ast_log(LOG_WARNING, "XXX I don't work right with non-full duplex sound cards XXX\n");
|
|
res = ast_channel_register(type, tdesc, AST_FORMAT_SLINEAR, oss_request);
|
|
if (res < 0) {
|
|
@@ -997,26 +1066,7 @@
|
|
}
|
|
for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
|
|
ast_cli_register(myclis + x);
|
|
- if ((cfg = ast_load(config))) {
|
|
- v = ast_variable_browse(cfg, "general");
|
|
- while(v) {
|
|
- if (!strcasecmp(v->name, "autoanswer"))
|
|
- autoanswer = ast_true(v->value);
|
|
- else if (!strcasecmp(v->name, "silencesuppression"))
|
|
- silencesuppression = ast_true(v->value);
|
|
- else if (!strcasecmp(v->name, "silencethreshold"))
|
|
- silencethreshold = atoi(v->value);
|
|
- else if (!strcasecmp(v->name, "context"))
|
|
- strncpy(context, v->value, sizeof(context)-1);
|
|
- else if (!strcasecmp(v->name, "language"))
|
|
- strncpy(language, v->value, sizeof(language)-1);
|
|
- else if (!strcasecmp(v->name, "extension"))
|
|
- strncpy(exten, v->value, sizeof(exten)-1);
|
|
- v=v->next;
|
|
- }
|
|
- ast_destroy(cfg);
|
|
- }
|
|
- ast_pthread_create(&sthread, NULL, sound_thread, NULL);
|
|
+ ast_pthread_create(&oss.sthread, NULL, sound_thread, NULL);
|
|
return 0;
|
|
}
|
|
|
|
@@ -1027,15 +1077,16 @@
|
|
int x;
|
|
for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
|
|
ast_cli_unregister(myclis + x);
|
|
- close(sounddev);
|
|
- if (sndcmd[0] > 0) {
|
|
- close(sndcmd[0]);
|
|
- close(sndcmd[1]);
|
|
+ close(oss.sounddev);
|
|
+ if (oss.sndcmd[0] > 0) {
|
|
+ close(oss.sndcmd[0]);
|
|
+ close(oss.sndcmd[1]);
|
|
}
|
|
if (oss.owner)
|
|
ast_softhangup(oss.owner, AST_SOFTHANGUP_APPUNLOAD);
|
|
if (oss.owner)
|
|
return -1;
|
|
+ /* XXX what about the thread ? */
|
|
return 0;
|
|
}
|
|
|