Compare commits

...

3 Commits

Author SHA1 Message Date
Kevin P. Fleming
bbe290b904 remove extraneous svn:executable properties
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/0.1.2@7221 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-11-29 18:24:39 +00:00
Kevin P. Fleming
d6a447055d automatic tag renames
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/0.1.2@7201 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-11-27 17:18:34 +00:00
Admin Commit
39e1748aea This commit was manufactured by cvs2svn to create tag 'v0-1-2'.
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/v0-1-2@200 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2000-01-07 11:02:42 +00:00
264 changed files with 4325 additions and 277 deletions

0
BUGS Executable file → Normal file
View File

15
CHANGES Executable file → Normal file
View File

@@ -1,3 +1,18 @@
* Asterisk 0.1.2
-- Updated README file with a "Getting Started" section
-- Added sample sounds and configuration files.
-- Added LPC10 very low bandwidth (low quality) compression
-- Enhanced translation selection mechanism.
-- Enhanced IAX jitter buffer, improved reliability
-- Support echo cancelation on PhoneJack
-- Updated PhoneJack driver to std. Telephony interface
-- Added app_echo for evaluating VoIP latency
-- Added app_system to execute arbitrary programs
-- Updated sample configuration files
-- Added OSS channel driver (full duplex only)
-- Added IAX implementation
-- Fixed some deadlocks.
-- A whole bunch of bug fixes
* Asterisk 0.1.1
-- Revised translator, fixed some general race conditions throughout *
-- Made dialer somewhat more aware of incompatible voice channels

0
CREDITS Executable file → Normal file
View File

0
LICENSE Executable file → Normal file
View File

64
Makefile Executable file → Normal file
View File

@@ -16,16 +16,31 @@
MODULES_DIR=/usr/lib/asterisk/modules
# Pentium Pro Optimize
#PROC=i686
# Pentium Optimize
PROC=i586
DEBUG=-g #-pg
INCLUDE=-Iinclude -I../include
CFLAGS=-pipe -Wall -Werror -Wmissing-prototypes -Wmissing-declarations -O6 $(DEBUG) $(INCLUDE) -D_REENTRANT
CFLAGS+=$(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi)
CFLAGS+=$(shell if $(CC) -march=$(PROC) -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=$(PROC)"; fi)
SUBDIRS=channels pbx apps codecs formats
LIBS=-ldl -lpthread -lreadline # -lefence
OBJS=io.o sched.o logger.o frame.o loader.o config.o channel.o translate.o file.o say.o pbx.o cli.o asterisk.o
LIBS=-ldl -lpthread -lreadline #-lefence
OBJS=io.o sched.o logger.o frame.o loader.o config.o channel.o translate.o file.o say.o pbx.o cli.o md5.o asterisk.o
CC=gcc
INSTALL=install
_all: all
@echo " +--------- Asterisk Build Complete ---------+"
@echo " + Asterisk has successfully been built, but +"
@echo " + cannot be run before being installed by +"
@echo " + running: +"
@echo " + +"
@echo " + make install +"
@echo " + +"
@echo " +-------------------------------------------+"
all: asterisk subdirs
asterisk: $(OBJS)
@@ -38,8 +53,51 @@ clean:
for x in $(SUBDIRS); do $(MAKE) -C $$x clean || exit 1 ; done
rm -f *.o *.so asterisk
datafiles: all
mkdir -p /var/lib/asterisk/sounds/digits
for x in sounds/digits/*; do \
install $$x /var/lib/asterisk/sounds/digits ; \
done
for x in sounds/vm-* sounds/transfer* ; do \
install $$x /var/lib/asterisk/sounds ; \
done
install: all
mkdir -p $(MODULES_DIR)
for x in $(SUBDIRS); do $(MAKE) -C $$x install || exit 1 ; done
install -d /usr/include/asterisk
install include/asterisk/*.h /usr/include/asterisk
rm -f /var/lib/asterisk/sounds/vm
mkdir -p /var/spool/asterisk/vm
rm -f /usr/lib/asterisk/modules/chan_ixj.so
( cd /var/lib/asterisk/sounds ; ln -s ../../../spool/asterisk/vm . )
@echo " +---- Asterisk Installation Complete -------+"
@echo " + Asterisk has successfully been installed. +"
@echo " + If you would like to install the sample +"
@echo " + configuration files (overwriting any +"
@echo " + existing config files), run: +"
@echo " + +"
@echo " + make samples +"
@echo " + +"
@echo " +-------------------------------------------+"
samples: all datafiles
mkdir -p /etc/asterisk
for x in configs/*.sample; do \
if [ -f /etc/asterisk/`basename $$x .sample` ]; then \
mv -f /etc/asterisk/`basename $$x .sample` /etc/asterisk/`basename $$x .sample`.old ; \
fi ; \
install $$x /etc/asterisk/`basename $$x .sample` ;\
done
for x in sounds/demo-*; do \
install $$x /var/lib/asterisk/sounds; \
done
mkdir -p /var/lib/asterisk/sounds/vm/1234
:> /var/lib/asterisk/sounds/vm/1234/unavail.gsm
for x in vm-theperson digits/1 digits/2 digits/3 digits/4 vm-isunavail; do \
cat /var/lib/asterisk/sounds/$$x.gsm >> /var/lib/asterisk/sounds/vm/1234/unavail.gsm ; \
done
:> /var/lib/asterisk/sounds/vm/1234/busy.gsm
for x in vm-theperson digits/1 digits/2 digits/3 digits/4 vm-isonphone; do \
cat /var/lib/asterisk/sounds/$$x.gsm >> /var/lib/asterisk/sounds/vm/1234/busy.gsm ; \
done

56
README Executable file → Normal file
View File

@@ -22,6 +22,60 @@ as well.
If you want to use format_wav module, then you need a very recent
version of libaudiofile (at least version 0.2.0, or you can apply the
following patch to version 0.1.9):
included patch. RPMS for the patched libaudiofile are available at:
ftp://ftp.asteriskpbx.com/pub/asterisk/support
* GETTING STARTED
First, be sure you've installed the required libaudiofile upgrade if
you want to use the non-GSM WAV format. Next, be sure you've got
supported hardware. To use Asterisk right now, you will need one of
the following:
* Adtran Atlas 800 Plus
* QuickNet Internet PhoneJack
* Full Duplex Sound Card supported by Linux
Assuming you have one of these (most likely the third) you're ready to
proceed:
1) Run "make"
2) Run "make install"
If this is your first time working with Asterisk, you may wish to install
the sample PBX, with demonstration extensions, etc. If so, run:
"make samples"
Doing so will overwrite any existing config files you have.
Finally, you can launch Asterisk with:
./asterisk -vvvc
If you get an error about unresolved symbols, install the updated
libaudiofile (available at ftp://ftp.asteriskpbx.com/pub/asterisk/support
You'll see a bunch of verbose messages fly by your screen as Asterisk
initializes (that's the "very very verbose" mode). When it's ready, if
you specified the "c" then you'll get a command line console, that looks
like this:
*CLI>
You can type "help" at any time to get help with the system. For help
with a specific command, type "help <command>". To start the PBX using
your sound card, you can type "dial" to dial the PBX. Then you can use
"answer", "hangup", and "dial" to simulate the actions of a telephone.
Remember that if you don't have a full duplex sound card (And asterisk
will tell you somewhere in its verbose messages if you do/don't) than it
won't work right (not yet).
Feel free to look over the configuration files in /etc/asterisk, where
you'll find a lot of information about what you can do with Asterisk.
Finally, you may wish to visit the web site and join the mailing list if
you're interested in getting more information.
Mark

0
apps/Makefile Executable file → Normal file
View File

0
apps/app_dial.c Executable file → Normal file
View File

0
apps/app_directory.c Executable file → Normal file
View File

0
apps/app_echo.c Executable file → Normal file
View File

0
apps/app_intercom.c Executable file → Normal file
View File

0
apps/app_mp3.c Executable file → Normal file
View File

0
apps/app_playback.c Executable file → Normal file
View File

0
apps/app_skel.c Executable file → Normal file
View File

0
apps/app_system.c Executable file → Normal file
View File

0
apps/app_voicemail.c Executable file → Normal file
View File

0
asterisk.c Executable file → Normal file
View File

0
asterisk.h Executable file → Normal file
View File

0
audiofile.patch Executable file → Normal file
View File

0
channel.c Executable file → Normal file
View File

0
channels/DialTone.h Executable file → Normal file
View File

0
channels/Makefile Executable file → Normal file
View File

0
channels/adtranvofr.h Executable file → Normal file
View File

2238
channels/chan_iax.c Normal file

File diff suppressed because it is too large Load Diff

16
channels/chan_modem.c Executable file → Normal file
View File

@@ -419,7 +419,6 @@ struct ast_channel *ast_modem_new(struct ast_modem_pvt *i, int state)
snprintf(tmp->name, sizeof(tmp->name), "Modem[%s]/%s", i->mc->name, i->dev + 5);
tmp->type = type;
tmp->fd = i->fd;
/* XXX Switching formats silently causes kernel panics XXX */
tmp->format = i->mc->formats;
tmp->state = state;
if (state == AST_STATE_RING)
@@ -433,7 +432,7 @@ struct ast_channel *ast_modem_new(struct ast_modem_pvt *i, int state)
tmp->pvt->write = modem_write;
strncpy(tmp->context, i->context, sizeof(tmp->context));
if (strlen(i->cid))
strncpy(tmp->callerid, i->cid, sizeof(tmp->callerid));
tmp->callerid = strdup(i->cid);
i->owner = tmp;
pthread_mutex_lock(&usecnt_lock);
usecnt++;
@@ -443,6 +442,7 @@ struct ast_channel *ast_modem_new(struct ast_modem_pvt *i, int state)
if (ast_pbx_start(tmp)) {
ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
ast_hangup(tmp);
tmp = NULL;
}
}
} else
@@ -454,6 +454,12 @@ static void modem_mini_packet(struct ast_modem_pvt *i)
{
struct ast_frame *fr;
fr = i->mc->read(i);
if (fr->frametype == AST_FRAME_CONTROL) {
if (fr->subclass == AST_CONTROL_RING) {
ast_modem_new(i, AST_STATE_RING);
restart_monitor();
}
}
}
static void *do_monitor(void *data)
@@ -701,10 +707,10 @@ int load_module()
ast_verbose(VERBOSE_PREFIX_2 "Loading modem driver %s", driver);
if (ast_load_resource(driver)) {
ast_log(LOG_ERROR, "Failed to laod driver %s\n", driver);
ast_log(LOG_ERROR, "Failed to load driver %s\n", driver);
ast_destroy(cfg);
unload_module();
pthread_mutex_unlock(&iflock);
unload_module();
return -1;
}
} else if (!strcasecmp(v->name, "mode")) {
@@ -742,8 +748,6 @@ int load_module()
return 0;
}
int unload_module()
{
struct ast_modem_pvt *p, *pl;

13
channels/chan_modem_aopen.c Executable file → Normal file
View File

@@ -194,9 +194,13 @@ static struct ast_frame *aopen_handle_escape(struct ast_modem_pvt *p, char esc)
ast_log(LOG_DEBUG, "Escaped character '%c'\n", esc);
switch(esc) {
case 'R': /* Pseudo ring */
p->fr.frametype = AST_FRAME_CONTROL;
p->fr.subclass = AST_CONTROL_RING;
return &p->fr;
case 'X': /* Pseudo connect */
p->fr.frametype = AST_FRAME_CONTROL;
p->fr.subclass = AST_CONTROL_ANSWER;
p->fr.subclass = AST_CONTROL_RING;
if (p->owner)
p->owner->state = AST_STATE_UP;
if (aopen_startrec(p))
@@ -255,11 +259,14 @@ static struct ast_frame *aopen_read(struct ast_modem_pvt *p)
/* If we're in immediate mode, reply now */
if (p->mode == MODEM_MODE_IMMEDIATE)
return aopen_handle_escape(p, 'X');
}
} else
if (!strcasecmp(result, "BUSY")) {
/* Same as a busy signal */
return aopen_handle_escape(p, 'b');
}
} else
if (!strcasecmp(result, "RING")) {
return aopen_handle_escape(p, 'R');
} else
if (!strcasecmp(result, "NO DIALTONE")) {
/* There's no dialtone, so the line isn't working */
ast_log(LOG_WARNING, "Device '%s' lacking dialtone\n", p->dev);

791
channels/chan_oss.c Normal file
View File

@@ -0,0 +1,791 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Use /dev/dsp as a channel, and the console to command it :).
*
* The full-duplex "simulation" is pretty weak. This is generally a
* VERY BADLY WRITTEN DRIVER so please don't use it as a model for
* writing a driver.
*
* Copyright (C) 1999, Mark Spencer
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#include <asterisk/frame.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/module.h>
#include <asterisk/channel_pvt.h>
#include <asterisk/options.h>
#include <asterisk/pbx.h>
#include <asterisk/config.h>
#include <asterisk/cli.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <linux/soundcard.h>
/* Which device to use */
#define DEV_DSP "/dev/dsp"
/* Lets use 160 sample frames, just like GSM. */
#define FRAME_SIZE 160
/* When you set the frame size, you have to come up with
the right buffer format as well. */
/* 5 64-byte frames = one frame */
#define BUFFER_FMT ((buffersize * 5) << 16) | (0x0006);
/* Don't switch between read/write modes faster than every 300 ms */
#define MIN_SWITCH_TIME 600
static struct timeval lasttime;
static int usecnt;
static int needanswer = 0;
static int needhangup = 0;
static int silencesuppression = 0;
static int silencethreshold = 1000;
static char digits[80] = "";
static pthread_mutex_t usecnt_lock = PTHREAD_MUTEX_INITIALIZER;
static char *type = "Console";
static char *desc = "OSS Console Channel Driver";
static char *tdesc = "OSS Console Channel Driver";
static char *config = "oss.conf";
static char context[AST_MAX_EXTENSION] = "default";
static char exten[AST_MAX_EXTENSION] = "s";
/* Some pipes to prevent overflow */
static int funnel[2];
static pthread_mutex_t sound_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_t silly;
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. */
struct ast_channel *owner;
char exten[AST_MAX_EXTENSION];
char context[AST_MAX_EXTENSION];
} oss;
static int time_has_passed()
{
struct timeval tv;
int ms;
gettimeofday(&tv, NULL);
ms = (tv.tv_sec - lasttime.tv_sec) * 1000 +
(tv.tv_usec - lasttime.tv_usec) / 1000;
if (ms > MIN_SWITCH_TIME)
return -1;
return 0;
}
/* 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. */
#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;
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 (!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(funnel[1], silbuf, silbufcnt * FRAME_SIZE);
silbufcnt = 0;
}
}
return 0;
}
static void *silly_thread(void *ignore)
{
char buf[FRAME_SIZE * 2];
int pos=0;
int res=0;
/* Read from the sound device, and write to the pipe. */
for (;;) {
/* Give the writer a better shot at the lock */
#if 0
usleep(1000);
#endif
pthread_testcancel();
pthread_mutex_lock(&sound_lock);
res = read(sounddev, buf + pos, FRAME_SIZE * 2 - pos);
pthread_mutex_unlock(&sound_lock);
if (res > 0) {
pos += res;
if (pos == FRAME_SIZE * 2) {
if (needhangup || needanswer || strlen(digits) ||
!silence_suppress((short *)buf)) {
res = write(funnel[1], buf, sizeof(buf));
}
pos = 0;
}
} else {
close(funnel[1]);
break;
}
pthread_testcancel();
}
return NULL;
}
static int setformat(void)
{
int fmt, desired, res, fd = sounddev;
static int warnedalready = 0;
static int warnedalready2 = 0;
pthread_mutex_lock(&sound_lock);
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");
pthread_mutex_unlock(&sound_lock);
return -1;
}
res = ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
if (res >= 0) {
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "Console is full duplex\n");
full_duplex = -1;
}
fmt = 0;
res = ioctl(fd, SNDCTL_DSP_STEREO, &fmt);
if (res < 0) {
ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
pthread_mutex_unlock(&sound_lock);
return -1;
}
/* 8000 Hz desired */
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");
pthread_mutex_unlock(&sound_lock);
return -1;
}
if (fmt != desired) {
if (!warnedalready++)
ast_log(LOG_WARNING, "Requested %d Hz, got %d Hz -- sound may be choppy\n", desired, fmt);
}
#if 1
fmt = BUFFER_FMT;
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
pthread_mutex_unlock(&sound_lock);
return 0;
}
static int soundcard_setoutput(int force)
{
/* Make sure the soundcard is in output mode. */
int fd = sounddev;
if (full_duplex || (!readmode && !force))
return 0;
pthread_mutex_lock(&sound_lock);
readmode = 0;
if (force || time_has_passed()) {
ioctl(sounddev, SNDCTL_DSP_RESET);
/* 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);
if (fd < 0) {
ast_log(LOG_WARNING, "Unable to re-open DSP device: %s\n", strerror(errno));
pthread_mutex_unlock(&sound_lock);
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));
pthread_mutex_unlock(&sound_lock);
return -1;
}
if (setformat()) {
pthread_mutex_unlock(&sound_lock);
return -1;
}
pthread_mutex_unlock(&sound_lock);
return 0;
}
pthread_mutex_unlock(&sound_lock);
return 1;
}
static int soundcard_setinput(int force)
{
int fd = sounddev;
if (full_duplex || (readmode && !force))
return 0;
pthread_mutex_lock(&sound_lock);
readmode = -1;
if (force || time_has_passed()) {
ioctl(sounddev, SNDCTL_DSP_RESET);
close(sounddev);
/* dup2(0, sound); */
fd = open(DEV_DSP, O_RDONLY);
if (fd < 0) {
ast_log(LOG_WARNING, "Unable to re-open DSP device: %s\n", strerror(errno));
pthread_mutex_unlock(&sound_lock);
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));
pthread_mutex_unlock(&sound_lock);
return -1;
}
if (setformat()) {
pthread_mutex_unlock(&sound_lock);
return -1;
}
pthread_mutex_unlock(&sound_lock);
return 0;
}
pthread_mutex_unlock(&sound_lock);
return 1;
}
static int soundcard_init()
{
/* Assume it's full duplex for starters */
int fd = open(DEV_DSP, O_RDWR);
if (fd < 0) {
ast_log(LOG_ERROR, "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;
}
static int oss_digit(struct ast_channel *c, char digit)
{
ast_verbose( " << Console Received digit %c >> \n", digit);
return 0;
}
static int oss_call(struct ast_channel *c, char *dest, int timeout)
{
ast_verbose( " << Call placed to '%s' on console >> \n", dest);
if (autoanswer) {
ast_verbose( " << Auto-answered >> \n" );
needanswer = 1;
} else {
ast_verbose( " << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
}
return 0;
}
static int oss_answer(struct ast_channel *c)
{
ast_verbose( " << Console call has been answered >> \n");
c->state = AST_STATE_UP;
return 0;
}
static int oss_hangup(struct ast_channel *c)
{
c->pvt->pvt = NULL;
oss.owner = NULL;
ast_verbose( " << Hangup on console >> \n");
pthread_mutex_lock(&usecnt_lock);
usecnt--;
pthread_mutex_unlock(&usecnt_lock);
needhangup = 0;
needanswer = 0;
return 0;
}
static int soundcard_writeframe(short *data)
{
/* Write an exactly FRAME_SIZE sized of frame */
static int bufcnt = 0;
static char buffer[FRAME_SIZE * 2 * MAX_BUFFER_SIZE * 5];
struct audio_buf_info info;
int res;
int fd = sounddev;
static int warned=0;
pthread_mutex_lock(&sound_lock);
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 * 2), data, FRAME_SIZE * 2);
bufcnt++;
if (bufcnt == buffersize) {
res = write(fd, ((void *)buffer), FRAME_SIZE * 2 * buffersize);
}
}
pthread_mutex_unlock(&sound_lock);
return res;
}
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;
if (!full_duplex && (strlen(digits) || needhangup || needanswer)) {
/* If we're half duplex, we have to switch to read mode
to honor immediate needs if necessary */
res = soundcard_setinput(1);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set device to input mode\n");
return -1;
}
return 0;
}
res = soundcard_setoutput(0);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set output device\n");
return -1;
} else if (res > 0) {
/* The device is still in read mode, and it's too soon to change it,
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;
}
if (len - pos)
memmove(sizbuf, sizbuf + pos, len - pos);
sizpos = len - pos;
return 0;
}
static struct ast_frame *oss_read(struct ast_channel *chan)
{
static struct ast_frame f;
static char buf[FRAME_SIZE * 2 + AST_FRIENDLY_OFFSET];
static int readpos = 0;
int res;
#if 0
ast_log(LOG_DEBUG, "oss_read()\n");
#endif
f.frametype = AST_FRAME_NULL;
f.subclass = 0;
f.timelen = 0;
f.datalen = 0;
f.data = NULL;
f.offset = 0;
f.src = type;
f.mallocd = 0;
if (needhangup) {
return NULL;
}
if (strlen(digits)) {
f.frametype = AST_FRAME_DTMF;
f.subclass = digits[0];
for (res=0;res<strlen(digits);res++)
digits[res] = digits[res + 1];
return &f;
}
if (needanswer) {
needanswer = 0;
f.frametype = AST_FRAME_CONTROL;
f.subclass = AST_CONTROL_ANSWER;
chan->state = AST_STATE_UP;
return &f;
}
res = soundcard_setinput(0);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set input mode\n");
return NULL;
}
if (res > 0) {
/* Theoretically shouldn't happen, but anyway, return a NULL frame */
return &f;
}
res = read(funnel[0], buf + AST_FRIENDLY_OFFSET + readpos, FRAME_SIZE * 2 - readpos);
if (res < 0) {
ast_log(LOG_WARNING, "Error reading from sound device: %s\n", strerror(errno));
return NULL;
}
readpos += res;
if (readpos == FRAME_SIZE * 2) {
/* A real frame */
readpos = 0;
f.frametype = AST_FRAME_VOICE;
f.subclass = AST_FORMAT_SLINEAR;
f.timelen = FRAME_SIZE / 8;
f.datalen = FRAME_SIZE * 2;
f.data = buf + AST_FRIENDLY_OFFSET;
f.offset = AST_FRIENDLY_OFFSET;
f.src = type;
f.mallocd = 0;
}
return &f;
}
static struct ast_channel *oss_new(struct chan_oss_pvt *p, int state)
{
struct ast_channel *tmp;
tmp = ast_channel_alloc();
if (tmp) {
snprintf(tmp->name, sizeof(tmp->name), "OSS/%s", DEV_DSP + 5);
tmp->type = type;
tmp->fd = funnel[0];
tmp->format = AST_FORMAT_SLINEAR;
tmp->pvt->pvt = p;
tmp->pvt->send_digit = oss_digit;
tmp->pvt->hangup = oss_hangup;
tmp->pvt->answer = oss_answer;
tmp->pvt->read = oss_read;
tmp->pvt->write = oss_write;
if (strlen(p->context))
strncpy(tmp->context, p->context, sizeof(tmp->context));
if (strlen(p->exten))
strncpy(tmp->exten, p->exten, sizeof(tmp->exten));
p->owner = tmp;
tmp->state = state;
pthread_mutex_lock(&usecnt_lock);
usecnt++;
pthread_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;
}
}
}
return tmp;
}
static struct ast_channel *oss_request(char *type, int format, void *data)
{
int oldformat = format;
format &= AST_FORMAT_SLINEAR;
if (!format) {
ast_log(LOG_NOTICE, "Asked to get a channel of format '%d'\n", oldformat);
return NULL;
}
if (oss.owner) {
ast_log(LOG_NOTICE, "Already have a call on the OSS channel\n");
return NULL;
}
return oss_new(&oss, AST_STATE_DOWN);
}
static int console_autoanswer(int fd, int argc, char *argv[])
{
if ((argc != 1) && (argc != 2))
return RESULT_SHOWUSAGE;
if (argc == 1) {
ast_cli(fd, "Auto answer is %s.\n", autoanswer ? "on" : "off");
return RESULT_SUCCESS;
} else {
if (!strcasecmp(argv[1], "on"))
autoanswer = -1;
else if (!strcasecmp(argv[1], "off"))
autoanswer = 0;
else
return RESULT_SHOWUSAGE;
}
return RESULT_SUCCESS;
}
static char *autoanswer_complete(char *line, char *word, int pos, int state)
{
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
switch(state) {
case 0:
if (strlen(word) && !strncasecmp(word, "on", MIN(strlen(word), 2)))
return strdup("on");
case 1:
if (strlen(word) && !strncasecmp(word, "off", MIN(strlen(word), 3)))
return strdup("off");
default:
return NULL;
}
return NULL;
}
static char autoanswer_usage[] =
"Usage: autoanswer [on|off]\n"
" Enables or disables autoanswer feature. If used without\n"
" argument, displays the current on/off status of autoanswer.\n"
" The default value of autoanswer is in 'oss.conf'.\n";
static int console_answer(int fd, int argc, char *argv[])
{
if (argc != 1)
return RESULT_SHOWUSAGE;
if (!oss.owner) {
ast_cli(fd, "No one is calling us\n");
return RESULT_FAILURE;
}
needanswer++;
return RESULT_SUCCESS;
}
static char answer_usage[] =
"Usage: answer\n"
" Answers an incoming call on the console (OSS) channel.\n";
static int console_hangup(int fd, int argc, char *argv[])
{
if (argc != 1)
return RESULT_SHOWUSAGE;
if (!oss.owner) {
ast_cli(fd, "No call to hangup up\n");
return RESULT_FAILURE;
}
needhangup++;
return RESULT_SUCCESS;
}
static char hangup_usage[] =
"Usage: hangup\n"
" Hangs up any call currently placed on the console.\n";
static int console_dial(int fd, int argc, char *argv[])
{
char tmp[256], *tmp2;
char *mye, *myc;
if ((argc != 1) && (argc != 2))
return RESULT_SHOWUSAGE;
if (oss.owner) {
if (argc == 2)
strncat(digits, argv[1], sizeof(digits) - strlen(digits));
else {
ast_cli(fd, "You're already in a call. You can use this only to dial digits until you hangup\n");
return RESULT_FAILURE;
}
return RESULT_SUCCESS;
}
mye = exten;
myc = context;
if (argc == 2) {
strncpy(tmp, argv[1], sizeof(tmp));
strtok(tmp, "@");
tmp2 = strtok(NULL, "@");
if (strlen(tmp))
mye = tmp;
if (tmp2 && strlen(tmp2))
myc = tmp2;
}
if (ast_exists_extension(NULL, myc, mye, 1)) {
strncpy(oss.exten, mye, sizeof(oss.exten));
strncpy(oss.context, myc, sizeof(oss.context));
oss_new(&oss, AST_STATE_UP);
} else
ast_cli(fd, "No such extension '%s' in context '%s'\n", mye, myc);
return RESULT_SUCCESS;
}
static char dial_usage[] =
"Usage: dial [extension[@context]]\n"
" Dials a given extensison (";
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 },
{ { "dial", NULL }, console_dial, "Dial an extension on the console", dial_usage },
{ { "autoanswer", NULL }, console_autoanswer, "Sets/displays autoanswer", autoanswer_usage, autoanswer_complete }
};
int load_module()
{
int res;
int x;
int flags;
struct ast_config *cfg = ast_load(config);
struct ast_variable *v;
res = pipe(funnel);
if (res) {
ast_log(LOG_ERROR, "Unable to create pipe\n");
return -1;
}
/* We make the funnel so that writes to the funnel don't block...
Our "silly" thread can read to its heart content, preventing
recording overruns */
flags = fcntl(funnel[1], F_GETFL);
#if 0
fcntl(funnel[0], F_SETFL, flags | O_NONBLOCK);
#endif
fcntl(funnel[1], F_SETFL, flags | O_NONBLOCK);
res = soundcard_init();
if (res < 0) {
close(funnel[1]);
close(funnel[0]);
return -1;
}
if (!full_duplex)
ast_log(LOG_WARNING, "XXX I don't work right with non-full duplex sound cards XXX\n");
pthread_create(&silly, NULL, silly_thread, NULL);
res = ast_channel_register(type, tdesc, AST_FORMAT_SLINEAR, oss_request);
if (res < 0) {
ast_log(LOG_ERROR, "Unable to register channel class '%s'\n", type);
return -1;
}
for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
ast_cli_register(myclis + x);
if (cfg) {
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));
else if (!strcasecmp(v->name, "extension"))
strncpy(exten, v->value, sizeof(exten));
v=v->next;
}
ast_destroy(cfg);
}
return 0;
}
int unload_module()
{
int x;
for (x=0;x<sizeof(myclis)/sizeof(struct ast_cli_entry); x++)
ast_cli_unregister(myclis + x);
close(sounddev);
if (funnel[0] > 0) {
close(funnel[0]);
close(funnel[1]);
}
if (silly) {
pthread_cancel(silly);
pthread_join(silly, NULL);
}
if (oss.owner)
ast_softhangup(oss.owner);
if (oss.owner)
return -1;
return 0;
}
char *description()
{
return desc;
}
int usecount()
{
int res;
pthread_mutex_lock(&usecnt_lock);
res = usecnt;
pthread_mutex_unlock(&usecnt_lock);
return res;
}

378
channels/chan_ixj.c → channels/chan_phone.c Executable file → Normal file
View File

@@ -1,7 +1,7 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* QuickNet Internet Phone Jack Channel
* Generic Linux Telephony Interface driver
*
* Copyright (C) 1999, Mark Spencer
*
@@ -29,27 +29,32 @@
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include "ixjuser.h"
#include <linux/telephony.h>
/* Still use some IXJ specific stuff */
#include <linux/ixjuser.h>
#include "DialTone.h"
#define IXJ_MAX_BUF 480
#define phone_MAX_BUF 480
static char *desc = "QuickNet Internet Phone Jack";
static char *type = "PhoneJack";
static char *tdesc = "QuickNet Internet Phone Jack";
static char *config = "ixj.conf";
static char *desc = "Linux Telephony API Support";
static char *type = "Phone";
static char *tdesc = "Standard Linux Telephony API Driver";
static char *config = "phone.conf";
/* Default context for dialtone mode */
static char context[AST_MAX_EXTENSION] = "default";
char *ignore_rcs_id_for_chan_ixj = ixjuser_h_rcsid;
static int usecnt =0;
static int echocancel = AEC_OFF;
static int silencesupression = 0;
static int prefformat = AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR;
static pthread_mutex_t usecnt_lock = PTHREAD_MUTEX_INITIALIZER;
/* Protect the interface list (of ixj_pvt's) */
/* Protect the interface list (of phone_pvt's) */
static pthread_mutex_t iflock = PTHREAD_MUTEX_INITIALIZER;
/* Protect the monitoring thread, so only one process can kill or start it, and not
@@ -68,7 +73,7 @@ static int restart_monitor(void);
#define MODE_DIALTONE 1
#define MODE_IMMEDIATE 2
static struct ixj_pvt {
static struct phone_pvt {
int fd; /* Raw file descriptor for this device */
struct ast_channel *owner; /* Channel we belong to, possibly NULL */
int mode; /* Is this in the */
@@ -76,20 +81,21 @@ static struct ixj_pvt {
int lastinput; /* Last input format */
int ministate; /* Miniature state, for dialtone mode */
char dev[256]; /* Device name */
struct ixj_pvt *next; /* Next channel in list */
struct phone_pvt *next; /* Next channel in list */
struct ast_frame fr; /* Frame */
char offset[AST_FRIENDLY_OFFSET];
char buf[IXJ_MAX_BUF]; /* Static buffer for reading frames */
char buf[phone_MAX_BUF]; /* Static buffer for reading frames */
int obuflen;
int dialtone;
int silencesupression;
char context[AST_MAX_EXTENSION];
char obuf[IXJ_MAX_BUF * 2];
char obuf[phone_MAX_BUF * 2];
char ext[AST_MAX_EXTENSION];
} *iflist = NULL;
static int ixj_digit(struct ast_channel *ast, char digit)
static int phone_digit(struct ast_channel *ast, char digit)
{
struct ixj_pvt *p;
struct phone_pvt *p;
int outdigit;
p = ast->pvt->pvt;
switch(digit) {
@@ -115,57 +121,60 @@ static int ixj_digit(struct ast_channel *ast, char digit)
ast_log(LOG_WARNING, "Unknown digit '%c'\n", digit);
return -1;
}
ioctl(p->fd, IXJCTL_PLAY_TONE, digit);
ioctl(p->fd, PHONE_PLAY_TONE, digit);
return 0;
}
static int ixj_call(struct ast_channel *ast, char *dest, int timeout)
static int phone_call(struct ast_channel *ast, char *dest, int timeout)
{
struct ixj_pvt *p;
struct phone_pvt *p;
p = ast->pvt->pvt;
if ((ast->state != AST_STATE_DOWN) && (ast->state != AST_STATE_RESERVED)) {
ast_log(LOG_WARNING, "ixj_call called on %s, neither down nor reserved\n", ast->name);
ast_log(LOG_WARNING, "phone_call called on %s, neither down nor reserved\n", ast->name);
return -1;
}
/* When we call, it just works, really, there's no destination... Just
ring the phone and wait for someone to answer */
if (option_debug)
ast_log(LOG_DEBUG, "Ringing %s on %s (%d)\n", dest, ast->name, ast->fd);
ioctl(p->fd, IXJCTL_RING_START);
ioctl(p->fd, PHONE_RING_START);
ast->state = AST_STATE_RINGING;
return 0;
}
static int ixj_hangup(struct ast_channel *ast)
static int phone_hangup(struct ast_channel *ast)
{
struct ixj_pvt *p;
struct phone_pvt *p;
p = ast->pvt->pvt;
if (option_debug)
ast_log(LOG_DEBUG, "ixj_hangup(%s)\n", ast->name);
ast_log(LOG_DEBUG, "phone_hangup(%s)\n", ast->name);
if (!ast->pvt->pvt) {
ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
return 0;
}
/* XXX Is there anything we can do to really hang up except stop recording? */
ast->state = AST_STATE_DOWN;
if (ioctl(p->fd, IXJCTL_REC_STOP))
if (ioctl(p->fd, PHONE_REC_STOP))
ast_log(LOG_WARNING, "Failed to stop recording\n");
if (ioctl(p->fd, IXJCTL_PLAY_STOP))
if (ioctl(p->fd, PHONE_PLAY_STOP))
ast_log(LOG_WARNING, "Failed to stop playing\n");
if (ioctl(p->fd, IXJCTL_RING_STOP))
if (ioctl(p->fd, PHONE_RING_STOP))
ast_log(LOG_WARNING, "Failed to stop ringing\n");
if (ioctl(p->fd, IXJCTL_CPT_STOP))
if (ioctl(p->fd, PHONE_CPT_STOP))
ast_log(LOG_WARNING, "Failed to stop sounds\n");
/* If they're off hook, give a busy signal */
if (ioctl(p->fd, IXJCTL_HOOKSTATE))
ioctl(p->fd, IXJCTL_BUSY);
if (ioctl(p->fd, PHONE_HOOKSTATE)) {
if (option_debug)
ast_log(LOG_DEBUG, "Got hunghup, giving busy signal\n");
ioctl(p->fd, PHONE_BUSY);
}
p->lastformat = -1;
p->lastinput = -1;
p->ministate = 0;
p->obuflen = 0;
p->dialtone = 0;
memset(p->ext, 0, sizeof(p->ext));
((struct ixj_pvt *)(ast->pvt->pvt))->owner = NULL;
((struct phone_pvt *)(ast->pvt->pvt))->owner = NULL;
pthread_mutex_lock(&usecnt_lock);
usecnt--;
if (usecnt < 0)
@@ -180,27 +189,27 @@ static int ixj_hangup(struct ast_channel *ast)
return 0;
}
static int ixj_setup(struct ast_channel *ast)
static int phone_setup(struct ast_channel *ast)
{
struct ixj_pvt *p;
struct phone_pvt *p;
p = ast->pvt->pvt;
ioctl(p->fd, IXJCTL_CPT_STOP);
ioctl(p->fd, PHONE_CPT_STOP);
/* Nothing to answering really, just start recording */
if (ast->format & AST_FORMAT_G723_1) {
/* Prefer g723 */
ioctl(p->fd, IXJCTL_REC_STOP);
ioctl(p->fd, PHONE_REC_STOP);
if (p->lastinput != AST_FORMAT_G723_1) {
p->lastinput = AST_FORMAT_G723_1;
if (ioctl(p->fd, IXJCTL_REC_CODEC, G723_63)) {
if (ioctl(p->fd, PHONE_REC_CODEC, G723_63)) {
ast_log(LOG_WARNING, "Failed to set codec to g723.1\n");
return -1;
}
}
} else if (ast->format & AST_FORMAT_SLINEAR) {
ioctl(p->fd, IXJCTL_REC_STOP);
ioctl(p->fd, PHONE_REC_STOP);
if (p->lastinput != AST_FORMAT_SLINEAR) {
p->lastinput = AST_FORMAT_SLINEAR;
if (ioctl(p->fd, IXJCTL_REC_CODEC, LINEAR16)) {
if (ioctl(p->fd, PHONE_REC_CODEC, LINEAR16)) {
ast_log(LOG_WARNING, "Failed to set codec to signed linear 16\n");
return -1;
}
@@ -209,24 +218,24 @@ static int ixj_setup(struct ast_channel *ast)
ast_log(LOG_WARNING, "Can't do format %d\n", ast->format);
return -1;
}
if (ioctl(p->fd, IXJCTL_REC_START)) {
if (ioctl(p->fd, PHONE_REC_START)) {
ast_log(LOG_WARNING, "Failed to start recording\n");
return -1;
}
return 0;
}
static int ixj_answer(struct ast_channel *ast)
static int phone_answer(struct ast_channel *ast)
{
ixj_setup(ast);
phone_setup(ast);
if (option_debug)
ast_log(LOG_DEBUG, "ixj_answer(%s)\n", ast->name);
ast_log(LOG_DEBUG, "phone_answer(%s)\n", ast->name);
ast->rings = 0;
ast->state = AST_STATE_UP;
return 0;
}
static char ixj_2digit(char c)
static char phone_2digit(char c)
{
if (c == 12)
return '#';
@@ -238,11 +247,11 @@ static char ixj_2digit(char c)
return '?';
}
static struct ast_frame *ixj_read(struct ast_channel *ast)
static struct ast_frame *phone_read(struct ast_channel *ast)
{
int res;
IXJ_EXCEPTION ixje;
struct ixj_pvt *p = ast->pvt->pvt;
union telephony_exception phonee;
struct phone_pvt *p = ast->pvt->pvt;
char digit;
/* Some nice norms */
@@ -253,16 +262,16 @@ static struct ast_frame *ixj_read(struct ast_channel *ast)
p->fr.offset = 0;
p->fr.mallocd=0;
ixje.bytes = ioctl(p->fd, IXJCTL_EXCEPTION);
if (ixje.bits.dtmf_ready) {
phonee.bytes = ioctl(p->fd, PHONE_EXCEPTION);
if (phonee.bits.dtmf_ready) {
/* We've got a digit -- Just handle this nicely and easily */
digit = ioctl(p->fd, IXJCTL_GET_DTMF_ASCII);
digit = ioctl(p->fd, PHONE_GET_DTMF_ASCII);
p->fr.subclass = digit;
p->fr.frametype = AST_FRAME_DTMF;
return &p->fr;
}
if (ixje.bits.hookstate) {
res = ioctl(p->fd, IXJCTL_HOOKSTATE);
if (phonee.bits.hookstate) {
res = ioctl(p->fd, PHONE_HOOKSTATE);
/* See if we've gone on hook, if so, notify by returning NULL */
if (!res)
return NULL;
@@ -271,23 +280,23 @@ static struct ast_frame *ixj_read(struct ast_channel *ast)
/* They've picked up the phone */
p->fr.frametype = AST_FRAME_CONTROL;
p->fr.subclass = AST_CONTROL_ANSWER;
ixj_setup(ast);
phone_setup(ast);
ast->state = AST_STATE_UP;
return &p->fr;
} else
ast_log(LOG_WARNING, "Got off hook in weird state\n");
ast_log(LOG_WARNING, "Got off hook in weird state %d\n", ast->state);
}
}
#if 0
if (ixje.bits.pstn_ring)
if (phonee.bits.pstn_ring)
ast_verbose("Unit is ringing\n");
if (ixje.bits.caller_id) {
if (phonee.bits.caller_id) {
ast_verbose("We have caller ID: %s\n");
}
#endif
/* Try to read some data... */
CHECK_BLOCKING(ast);
res = read(p->fd, p->buf, IXJ_MAX_BUF);
res = read(p->fd, p->buf, phone_MAX_BUF);
ast->blocking = 0;
if (res < 0) {
#if 0
@@ -302,6 +311,17 @@ static struct ast_frame *ixj_read(struct ast_channel *ast)
return NULL;
}
p->fr.data = p->buf;
switch(p->buf[0] & 0x3) {
case '0':
case '1':
/* Normal */
break;
case '2':
case '3':
/* VAD/CNG, only send two words */
res = 4;
break;
}
p->fr.datalen = res;
p->fr.frametype = AST_FRAME_VOICE;
p->fr.subclass = p->lastinput;
@@ -309,7 +329,7 @@ static struct ast_frame *ixj_read(struct ast_channel *ast)
return &p->fr;
}
static int ixj_write_buf(struct ixj_pvt *p, char *buf, int len, int frlen)
static int phone_write_buf(struct phone_pvt *p, char *buf, int len, int frlen)
{
int res;
/* Store as much of the buffer as we can, then write fixed frames */
@@ -342,14 +362,15 @@ static int ixj_write_buf(struct ixj_pvt *p, char *buf, int len, int frlen)
return len;
}
static int ixj_write(struct ast_channel *ast, struct ast_frame *frame)
static int phone_write(struct ast_channel *ast, struct ast_frame *frame)
{
struct ixj_pvt *p = ast->pvt->pvt;
struct phone_pvt *p = ast->pvt->pvt;
int res;
int maxfr=0;
char *pos;
int sofar;
int expected;
char tmpbuf[4];
/* Write a frame of (presumably voice) data */
if (frame->frametype != AST_FRAME_VOICE) {
ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype);
@@ -361,14 +382,25 @@ static int ixj_write(struct ast_channel *ast, struct ast_frame *frame)
ast_frfree(frame);
return -1;
}
/* If we're not in up mode, go into up mode now */
if (ast->state != AST_STATE_UP) {
ast->state = AST_STATE_UP;
phone_setup(ast);
}
if (frame->subclass == AST_FORMAT_G723_1) {
if (p->lastformat != AST_FORMAT_G723_1) {
ioctl(p->fd, IXJCTL_PLAY_STOP);
if (ioctl(p->fd, IXJCTL_PLAY_CODEC, G723_63)) {
ioctl(p->fd, PHONE_PLAY_STOP);
ioctl(p->fd, PHONE_REC_STOP);
if (ioctl(p->fd, PHONE_PLAY_CODEC, G723_63)) {
ast_log(LOG_WARNING, "Unable to set G723.1 mode\n");
return -1;
}
if (ioctl(p->fd, PHONE_REC_CODEC, G723_63)) {
ast_log(LOG_WARNING, "Unable to set G723.1 mode\n");
return -1;
}
p->lastformat = AST_FORMAT_G723_1;
p->lastinput = AST_FORMAT_G723_1;
/* Reset output buffer */
p->obuflen = 0;
}
@@ -379,18 +411,28 @@ static int ixj_write(struct ast_channel *ast, struct ast_frame *frame)
maxfr = 24;
} else if (frame->subclass == AST_FORMAT_SLINEAR) {
if (p->lastformat != AST_FORMAT_SLINEAR) {
ioctl(p->fd, IXJCTL_PLAY_STOP);
if (ioctl(p->fd, IXJCTL_PLAY_CODEC, LINEAR16)) {
ioctl(p->fd, PHONE_PLAY_STOP);
ioctl(p->fd, PHONE_REC_STOP);
if (ioctl(p->fd, PHONE_PLAY_CODEC, LINEAR16)) {
ast_log(LOG_WARNING, "Unable to set 16-bit linear mode\n");
return -1;
}
if (ioctl(p->fd, PHONE_REC_CODEC, LINEAR16)) {
ast_log(LOG_WARNING, "Unable to set 16-bit linear mode\n");
return -1;
}
p->lastformat = AST_FORMAT_SLINEAR;
p->lastinput = AST_FORMAT_SLINEAR;
/* Reset output buffer */
p->obuflen = 0;
}
maxfr = 480;
}
if (ioctl(p->fd, IXJCTL_PLAY_START)) {
if (ioctl(p->fd, PHONE_PLAY_START)) {
ast_log(LOG_WARNING, "Failed to start playback\n");
return -1;
}
if (ioctl(p->fd, PHONE_REC_START)) {
ast_log(LOG_WARNING, "Failed to start recording\n");
return -1;
}
@@ -402,45 +444,54 @@ static int ixj_write(struct ast_channel *ast, struct ast_frame *frame)
expected = frame->datalen - sofar;
if (maxfr < expected)
expected = maxfr;
/* XXX Internet Phone Jack does not handle the 4-byte VAD frame properly! XXX */
if (frame->datalen != 4) {
res = ixj_write_buf(p, pos, expected, maxfr);
if (res != expected) {
if (res < 0)
ast_log(LOG_WARNING, "Write returned error (%s)\n", strerror(errno));
else
ast_log(LOG_WARNING, "Only wrote %d of %d bytes\n", res, frame->datalen);
return -1;
/* XXX Internet Phone Jack does not handle the 4-byte VAD frame properly! XXX
we have to pad it to 24 bytes still. */
if (frame->datalen == 4) {
if (p->silencesupression) {
memset(tmpbuf + 4, 0, sizeof(tmpbuf) - 4);
memcpy(tmpbuf, frame->data, 4);
expected = 24;
res = phone_write_buf(p, tmpbuf, expected, maxfr);
}
sofar += res;
pos += res;
} else
sofar += 4;
res = 4;
expected=4;
} else {
res = phone_write_buf(p, pos, expected, maxfr);
}
if (res != expected) {
if (res < 0)
ast_log(LOG_WARNING, "Write returned error (%s)\n", strerror(errno));
else
ast_log(LOG_WARNING, "Only wrote %d of %d bytes\n", res, frame->datalen);
return -1;
}
sofar += res;
pos += res;
}
return 0;
}
static struct ast_channel *ixj_new(struct ixj_pvt *i, int state)
static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *context)
{
struct ast_channel *tmp;
tmp = ast_channel_alloc();
if (tmp) {
snprintf(tmp->name, sizeof(tmp->name), "PhoneJack/%s", i->dev + 5);
snprintf(tmp->name, sizeof(tmp->name), "Phone/%s", i->dev + 5);
tmp->type = type;
tmp->fd = i->fd;
/* XXX Switching formats silently causes kernel panics XXX */
tmp->format = AST_FORMAT_G723_1 /* | AST_FORMAT_SLINEAR */;
tmp->format = prefformat;
tmp->state = state;
if (state == AST_STATE_RING)
tmp->rings = 1;
tmp->pvt->pvt = i;
tmp->pvt->send_digit = ixj_digit;
tmp->pvt->call = ixj_call;
tmp->pvt->hangup = ixj_hangup;
tmp->pvt->answer = ixj_answer;
tmp->pvt->read = ixj_read;
tmp->pvt->write = ixj_write;
strncpy(tmp->context, i->context, sizeof(tmp->context));
tmp->pvt->send_digit = phone_digit;
tmp->pvt->call = phone_call;
tmp->pvt->hangup = phone_hangup;
tmp->pvt->answer = phone_answer;
tmp->pvt->read = phone_read;
tmp->pvt->write = phone_write;
strncpy(tmp->context, context, sizeof(tmp->context));
if (strlen(i->ext))
strncpy(tmp->exten, i->ext, sizeof(tmp->exten));
i->owner = tmp;
@@ -449,8 +500,9 @@ static struct ast_channel *ixj_new(struct ixj_pvt *i, int state)
pthread_mutex_unlock(&usecnt_lock);
ast_update_use_count();
if (state != AST_STATE_DOWN) {
if (state == AST_STATE_RING)
ioctl(tmp->fd, IXJCTL_RINGBACK);
if (state == AST_STATE_RING) {
ioctl(tmp->fd, PHONE_RINGBACK);
}
if (ast_pbx_start(tmp)) {
ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
ast_hangup(tmp);
@@ -461,7 +513,7 @@ static struct ast_channel *ixj_new(struct ixj_pvt *i, int state)
return tmp;
}
static void ixj_mini_packet(struct ixj_pvt *i)
static void phone_mini_packet(struct phone_pvt *i)
{
int res;
char buf[1024];
@@ -473,75 +525,77 @@ static void ixj_mini_packet(struct ixj_pvt *i)
}
}
static void ixj_check_exception(struct ixj_pvt *i)
static void phone_check_exception(struct phone_pvt *i)
{
int offhook=0;
char digit[2] = {0 , 0};
IXJ_EXCEPTION ixje;
union telephony_exception phonee;
/* XXX Do something XXX */
#if 0
ast_log(LOG_DEBUG, "Exception!\n");
#endif
ixje.bytes = ioctl(i->fd, IXJCTL_EXCEPTION);
if (ixje.bits.dtmf_ready) {
digit[0] = ioctl(i->fd, IXJCTL_GET_DTMF_ASCII);
phonee.bytes = ioctl(i->fd, PHONE_EXCEPTION);
if (phonee.bits.dtmf_ready) {
digit[0] = ioctl(i->fd, PHONE_GET_DTMF_ASCII);
if (i->mode == MODE_DIALTONE) {
ioctl(i->fd, IXJCTL_PLAY_STOP);
ioctl(i->fd, IXJCTL_REC_STOP);
ioctl(i->fd, IXJCTL_CPT_STOP);
ioctl(i->fd, PHONE_PLAY_STOP);
ioctl(i->fd, PHONE_REC_STOP);
ioctl(i->fd, PHONE_CPT_STOP);
i->dialtone = 0;
if (strlen(i->ext) < AST_MAX_EXTENSION - 1)
strcat(i->ext, digit);
if (ast_exists_extension(NULL, i->context, i->ext, 1)) {
/* It's a valid extension in its context, get moving! */
ixj_new(i, AST_STATE_UP);
phone_new(i, AST_STATE_RING, i->context);
/* No need to restart monitor, we are the monitor */
if (i->owner) {
pthread_mutex_lock(&usecnt_lock);
usecnt--;
pthread_mutex_unlock(&usecnt_lock);
ast_update_use_count();
ixj_setup(i->owner);
}
} else if (ast_exists_extension(NULL, "default", i->ext, 1)) {
/* Check the default, too... */
/* XXX This should probably be justified better XXX */
strncpy(i->context, "default", sizeof(i->context));
ixj_new(i, AST_STATE_UP);
if (i->owner) {
pthread_mutex_lock(&usecnt_lock);
usecnt--;
pthread_mutex_unlock(&usecnt_lock);
ast_update_use_count();
ixj_setup(i->owner);
} else if (!ast_canmatch_extension(NULL, i->context, i->ext, 1)) {
/* There is nothing in the specified extension that can match anymore.
Try the default */
if (ast_exists_extension(NULL, "default", i->ext, 1)) {
/* Check the default, too... */
phone_new(i, AST_STATE_RING, "default");
if (i->owner) {
pthread_mutex_lock(&usecnt_lock);
usecnt--;
pthread_mutex_unlock(&usecnt_lock);
ast_update_use_count();
}
/* XXX This should probably be justified better XXX */
} else if (!ast_canmatch_extension(NULL, "default", i->ext, 1)) {
/* It's not a valid extension, give a busy signal */
if (option_debug)
ast_log(LOG_DEBUG, "%s can't match anything in %s or default\n", i->ext, i->context);
ioctl(i->fd, PHONE_BUSY);
}
} else if ((strlen(i->ext) >= ast_pbx_longest_extension(i->context)) &&
(strlen(i->ext) >= ast_pbx_longest_extension("default"))) {
if (option_debug)
ast_log(LOG_DEBUG, "%s is too long\n", i->ext);
/* It's not a valid extension, give a busy signal */
ioctl(i->fd, IXJCTL_BUSY);
}
#if 0
ast_verbose("Extension is %s\n", i->ext);
#endif
}
}
if (ixje.bits.hookstate) {
offhook = ioctl(i->fd, IXJCTL_HOOKSTATE);
if (phonee.bits.hookstate) {
offhook = ioctl(i->fd, PHONE_HOOKSTATE);
if (offhook) {
if (i->mode == MODE_IMMEDIATE) {
ixj_new(i, AST_STATE_RING);
phone_new(i, AST_STATE_RING, i->context);
} else if (i->mode == MODE_DIALTONE) {
pthread_mutex_lock(&usecnt_lock);
usecnt++;
pthread_mutex_unlock(&usecnt_lock);
ast_update_use_count();
/* Reset the extension */
i->ext[0] = '\0';
/* Play the dialtone */
i->dialtone++;
ioctl(i->fd, IXJCTL_PLAY_STOP);
ioctl(i->fd, IXJCTL_PLAY_CODEC, ULAW);
ioctl(i->fd, IXJCTL_PLAY_START);
ioctl(i->fd, PHONE_PLAY_STOP);
ioctl(i->fd, PHONE_PLAY_CODEC, ULAW);
ioctl(i->fd, PHONE_PLAY_START);
}
} else {
if (i->dialtone) {
@@ -551,15 +605,15 @@ static void ixj_check_exception(struct ixj_pvt *i)
ast_update_use_count();
}
memset(i->ext, 0, sizeof(i->ext));
ioctl(i->fd, IXJCTL_CPT_STOP);
ioctl(i->fd, IXJCTL_PLAY_STOP);
ioctl(i->fd, IXJCTL_REC_STOP);
ioctl(i->fd, PHONE_CPT_STOP);
ioctl(i->fd, PHONE_PLAY_STOP);
ioctl(i->fd, PHONE_REC_STOP);
i->dialtone = 0;
}
}
if (ixje.bits.pstn_ring)
if (phonee.bits.pstn_ring)
ast_verbose("Unit is ringing\n");
if (ixje.bits.caller_id)
if (phonee.bits.caller_id)
ast_verbose("We have caller ID\n");
@@ -569,7 +623,7 @@ static void *do_monitor(void *data)
{
fd_set rfds, efds;
int n, res;
struct ixj_pvt *i;
struct phone_pvt *i;
int tonepos = 0;
/* The tone we're playing this round */
struct timeval tv = {0,0};
@@ -595,7 +649,7 @@ static void *do_monitor(void *data)
return NULL;
}
/* Build the stuff we're going to select on, that is the socket of every
ixj_pvt that does not have an associated owner channel */
phone_pvt that does not have an associated owner channel */
n = -1;
FD_ZERO(&rfds);
FD_ZERO(&efds);
@@ -668,14 +722,14 @@ static void *do_monitor(void *data)
ast_log(LOG_WARNING, "Whoa.... I'm owned but found (%d, %s)...\n", i->fd, i->dev);
continue;
}
ixj_mini_packet(i);
phone_mini_packet(i);
}
if (FD_ISSET(i->fd, &efds)) {
if (i->owner) {
ast_log(LOG_WARNING, "Whoa.... I'm owned but found (%d, %s)...\n", i->fd, i->dev);
continue;
}
ixj_check_exception(i);
phone_check_exception(i);
}
i=i->next;
}
@@ -716,15 +770,15 @@ static int restart_monitor()
return 0;
}
static struct ixj_pvt *mkif(char *iface, int mode)
static struct phone_pvt *mkif(char *iface, int mode)
{
/* Make a ixj_pvt structure for this interface */
struct ixj_pvt *tmp;
/* Make a phone_pvt structure for this interface */
struct phone_pvt *tmp;
#if 0
int flags;
#endif
tmp = malloc(sizeof(struct ixj_pvt));
tmp = malloc(sizeof(struct phone_pvt));
if (tmp) {
tmp->fd = open(iface, O_RDWR);
if (tmp->fd < 0) {
@@ -732,10 +786,16 @@ static struct ixj_pvt *mkif(char *iface, int mode)
free(tmp);
return NULL;
}
ioctl(tmp->fd, IXJCTL_PLAY_STOP);
ioctl(tmp->fd, IXJCTL_REC_STOP);
ioctl(tmp->fd, IXJCTL_RING_STOP);
ioctl(tmp->fd, IXJCTL_CPT_STOP);
ioctl(tmp->fd, PHONE_PLAY_STOP);
ioctl(tmp->fd, PHONE_REC_STOP);
ioctl(tmp->fd, PHONE_RING_STOP);
ioctl(tmp->fd, PHONE_CPT_STOP);
ioctl(tmp->fd, PHONE_REC_DEPTH, 4);
if (echocancel != AEC_OFF)
ioctl(tmp->fd, IXJCTL_AEC_START, echocancel);
if (silencesupression)
tmp->silencesupression = 1;
ioctl(tmp->fd, PHONE_VAD, tmp->silencesupression);
tmp->mode = mode;
#if 0
flags = fcntl(tmp->fd, F_GETFL);
@@ -755,10 +815,10 @@ static struct ixj_pvt *mkif(char *iface, int mode)
return tmp;
}
static struct ast_channel *ixj_request(char *type, int format, void *data)
static struct ast_channel *phone_request(char *type, int format, void *data)
{
int oldformat;
struct ixj_pvt *p;
struct phone_pvt *p;
struct ast_channel *tmp = NULL;
char *name = data;
@@ -777,7 +837,7 @@ static struct ast_channel *ixj_request(char *type, int format, void *data)
while(p) {
if (!strcmp(name, p->dev + 5)) {
if (!p->owner) {
tmp = ixj_new(p, AST_STATE_DOWN);
tmp = phone_new(p, AST_STATE_DOWN, p->context);
break;
}
}
@@ -792,7 +852,7 @@ int load_module()
{
struct ast_config *cfg;
struct ast_variable *v;
struct ixj_pvt *tmp;
struct phone_pvt *tmp;
int mode = MODE_IMMEDIATE;
cfg = ast_load(config);
@@ -822,6 +882,8 @@ int load_module()
unload_module();
return -1;
}
} else if (!strcasecmp(v->name, "silencesupression")) {
silencesupression = ast_true(v->value);
} else if (!strcasecmp(v->name, "mode")) {
if (!strncasecmp(v->value, "di", 2))
mode = MODE_DIALTONE;
@@ -831,12 +893,30 @@ int load_module()
ast_log(LOG_WARNING, "Unknown mode: %s\n", v->value);
} else if (!strcasecmp(v->name, "context")) {
strncpy(context, v->value, sizeof(context));
} else if (!strcasecmp(v->name, "format")) {
if (!strcasecmp(v->value, "g723.1")) {
prefformat = AST_FORMAT_G723_1;
} else if (!strcasecmp(v->value, "slinear")) {
prefformat = AST_FORMAT_SLINEAR;
} else
ast_log(LOG_WARNING, "Unknown format '%s'\n", v->value);
} else if (!strcasecmp(v->name, "echocancel")) {
if (!strcasecmp(v->value, "off")) {
echocancel = AEC_OFF;
} else if (!strcasecmp(v->value, "low")) {
echocancel = AEC_LOW;
} else if (!strcasecmp(v->value, "medium")) {
echocancel = AEC_MED;
} else if (!strcasecmp(v->value, "high")) {
echocancel = AEC_HIGH;
} else
ast_log(LOG_WARNING, "Unknown echo cancellation '%s'\n", v->value);
}
v = v->next;
}
pthread_mutex_unlock(&iflock);
/* Make sure we can register our Adtranixj channel type */
if (ast_channel_register(type, tdesc, AST_FORMAT_G723_1, ixj_request)) {
/* Make sure we can register our Adtranphone channel type */
if (ast_channel_register(type, tdesc, AST_FORMAT_G723_1, phone_request)) {
ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
ast_destroy(cfg);
unload_module();
@@ -852,7 +932,7 @@ int load_module()
int unload_module()
{
struct ixj_pvt *p, *pl;
struct phone_pvt *p, *pl;
/* First, take us out of the channel loop */
ast_channel_unregister(type);
if (!pthread_mutex_lock(&iflock)) {

0
channels/chan_vofr.c Executable file → Normal file
View File

0
channels/iax.h Executable file → Normal file
View File

4
channels/ixjuser.h Executable file → Normal file
View File

@@ -1,8 +1,8 @@
/******************************************************************************
$Id$
$Log$
Revision 1.15 1999/12/01 05:25:58 markster
Version 0.3.0 from FTP
Revision 1.3 1999/12/01 05:25:58 markster
Version 0.1.2 from FTP
Revision 1.1 1999/12/01 05:25:58 markster
Start on the Internet Phone Jack channel

0
cli.c Executable file → Normal file
View File

12
codecs/Makefile Executable file → Normal file
View File

@@ -26,8 +26,9 @@ LIBG723=g723.1/libg723.a
LIBG723B=g723.1b/libg723b.a
LIBGSM=gsm/lib/libgsm.a
LIBMP3=mp3/libmp3.a
LIBLPC10=lpc10/liblpc10.a
CODECS+=$(MODG723) codec_gsm.so codec_mp3_d.so
CODECS+=$(MODG723) codec_gsm.so codec_mp3_d.so codec_lpc10.so
all: $(CODECS)
@@ -37,6 +38,7 @@ clean:
! [ -d g723.1b ] || make -C g723.1b clean
make -C gsm clean
make -C mp3 clean
make -C lpc10 clean
$(LIBG723):
make -C g723.1 all
@@ -50,11 +52,14 @@ $(LIBG723B):
$(LIBMP3):
make -C mp3 all
$(LIBLPC10):
make -C lpc10 all
codec_g723_1.so : codec_g723_1.o $(LIBG723)
$(CC) -shared -Xlinker -x -o $@ $< $(LIBG723)
codec_g723_1b.o : codec_g723_1.c
$(CC) -c -o $@ $(CFLAGS) -DANNEX_B $<
$(CC) -c -o $@ $(CFLAGS) -DANNEX_B -Dsingle $<
codec_g723_1b.so : codec_g723_1b.o $(LIBG723B)
$(CC) -shared -Xlinker -x -o $@ $< $(LIBG723B) -lm
@@ -62,6 +67,9 @@ codec_g723_1b.so : codec_g723_1b.o $(LIBG723B)
codec_gsm.so: codec_gsm.o $(LIBGSM)
$(CC) -shared -Xlinker -x -o $@ $< $(LIBGSM)
codec_lpc10.so: codec_lpc10.o $(LIBLPC10)
$(CC) -shared -Xlinker -x -o $@ $< $(LIBLPC10) -lm
codec_mp3_d.so: codec_mp3_d.o $(LIBMP3)
$(CC) -shared -Xlinker -x -o $@ $< $(LIBMP3)

0
codecs/codec_g723_1.c Executable file → Normal file
View File

0
codecs/codec_gsm.c Executable file → Normal file
View File

348
codecs/codec_lpc10.c Normal file
View File

@@ -0,0 +1,348 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Translate between signed linear and LPC10 (Linear Predictor Code)
*
* The lpc10 code is from a library used by nautilus, modified to be a bit
* nicer to the compiler.
*
* See http://www.arl.wustl.edu/~jaf/
*
* Copyright (C) 1999, Mark Spencer
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#include <asterisk/translate.h>
#include <asterisk/module.h>
#include <asterisk/logger.h>
#include <pthread.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
#include "lpc10/lpc10.h"
/* Sample frame data */
#include "slin_lpc10_ex.h"
#include "lpc10_slin_ex.h"
/* We use a very strange format here... I have no idea why... The frames are 180
samples long, which isn't even an even number of milliseconds... Not only that
but we hvae to waste two bits of each frame to keep them ending on a byte boundary
because the frames are 54 bits long */
#define LPC10_BYTES_IN_COMPRESSED_FRAME (LPC10_BITS_IN_COMPRESSED_FRAME + 7)/8
static pthread_mutex_t localuser_lock = PTHREAD_MUTEX_INITIALIZER;
static int localusecnt=0;
static char *tdesc = "LPC10 2.4kbps (signed linear) Voice Coder";
struct ast_translator_pvt {
union {
struct lpc10_encoder_state *enc;
struct lpc10_decoder_state *dec;
} lpc10;
struct ast_frame f;
/* Space to build offset */
char offset[AST_FRIENDLY_OFFSET];
/* Buffer for our outgoing frame */
short outbuf[LPC10_SAMPLES_PER_FRAME];
/* Enough to store a full second */
short buf[8000];
int tail;
int longer;
};
#define lpc10_coder_pvt ast_translator_pvt
static struct ast_translator_pvt *lpc10_enc_new()
{
struct lpc10_coder_pvt *tmp;
tmp = malloc(sizeof(struct lpc10_coder_pvt));
if (tmp) {
if (!(tmp->lpc10.enc = create_lpc10_encoder_state())) {
free(tmp);
tmp = NULL;
}
tmp->tail = 0;
tmp->longer = 0;
localusecnt++;
}
return tmp;
}
static struct ast_translator_pvt *lpc10_dec_new()
{
struct lpc10_coder_pvt *tmp;
tmp = malloc(sizeof(struct lpc10_coder_pvt));
if (tmp) {
if (!(tmp->lpc10.dec = create_lpc10_decoder_state())) {
free(tmp);
tmp = NULL;
}
tmp->tail = 0;
tmp->longer = 0;
localusecnt++;
}
return tmp;
}
static struct ast_frame *lintolpc10_sample()
{
static struct ast_frame f;
static int longer = 0;
f.frametype = AST_FRAME_VOICE;
f.subclass = AST_FORMAT_SLINEAR;
f.datalen = sizeof(slin_lpc10_ex);
/* Assume 8000 Hz */
f.timelen = LPC10_SAMPLES_PER_FRAME/8;
f.timelen += longer;
longer = 1- longer;
f.mallocd = 0;
f.offset = 0;
f.src = __PRETTY_FUNCTION__;
f.data = slin_lpc10_ex;
return &f;
}
static struct ast_frame *lpc10tolin_sample()
{
static struct ast_frame f;
f.frametype = AST_FRAME_VOICE;
f.subclass = AST_FORMAT_LPC10;
f.datalen = sizeof(lpc10_slin_ex);
/* All frames are 22 ms long (maybe a little more -- why did he choose
LPC10_SAMPLES_PER_FRAME sample frames anyway?? */
f.timelen = LPC10_SAMPLES_PER_FRAME/8;
f.mallocd = 0;
f.offset = 0;
f.src = __PRETTY_FUNCTION__;
f.data = lpc10_slin_ex;
return &f;
}
static struct ast_frame *lpc10tolin_frameout(struct ast_translator_pvt *tmp)
{
if (!tmp->tail)
return NULL;
/* Signed linear is no particular frame size, so just send whatever
we have in the buffer in one lump sum */
tmp->f.frametype = AST_FRAME_VOICE;
tmp->f.subclass = AST_FORMAT_SLINEAR;
tmp->f.datalen = tmp->tail * 2;
/* Assume 8000 Hz */
tmp->f.timelen = tmp->tail / 8;
tmp->f.mallocd = 0;
tmp->f.offset = AST_FRIENDLY_OFFSET;
tmp->f.src = __PRETTY_FUNCTION__;
tmp->f.data = tmp->buf;
/* Reset tail pointer */
tmp->tail = 0;
#if 0
/* Save a sample frame */
{ static int samplefr = 0;
if (samplefr == 80) {
int fd;
fd = open("lpc10.example", O_WRONLY | O_CREAT, 0644);
write(fd, tmp->f.data, tmp->f.datalen);
close(fd);
}
samplefr++;
}
#endif
return &tmp->f;
}
static void extract_bits(INT32 *bits, unsigned char *c)
{
int x;
for (x=0;x<LPC10_BITS_IN_COMPRESSED_FRAME;x++) {
if (*c & (0x80 >> (x & 7)))
bits[x] = 1;
else
bits[x] = 0;
if ((x & 7) == 7)
c++;
}
}
static void build_bits(unsigned char *c, INT32 *bits)
{
unsigned char mask=0x80;
int x;
*c = 0;
for (x=0;x<LPC10_BITS_IN_COMPRESSED_FRAME;x++) {
if (bits[x])
*c |= mask;
mask = mask >> 1;
if ((x % 8)==7) {
c++;
*c = 0;
mask = 0x80;
}
}
}
static int lpc10tolin_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
{
/* Assuming there's space left, decode into the current buffer at
the tail location */
int x;
float tmpbuf[LPC10_SAMPLES_PER_FRAME];
short *sd;
INT32 bits[LPC10_BITS_IN_COMPRESSED_FRAME];
if (tmp->tail + LPC10_SAMPLES_PER_FRAME < sizeof(tmp->buf)/2) {
sd = tmp->buf + tmp->tail;
extract_bits(bits, f->data);
if (lpc10_decode(bits, tmpbuf, tmp->lpc10.dec)) {
ast_log(LOG_WARNING, "Invalid lpc10 data\n");
return -1;
}
for (x=0;x<LPC10_SAMPLES_PER_FRAME;x++) {
/* Convert to a real between -1.0 and 1.0 */
sd[x] = 32768.0 * tmpbuf[x];
}
tmp->tail+=LPC10_SAMPLES_PER_FRAME;
} else {
ast_log(LOG_WARNING, "Out of buffer space\n");
return -1;
}
return 0;
}
static int lintolpc10_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
{
/* Just add the frames to our stream */
/* XXX We should look at how old the rest of our stream is, and if it
is too old, then we should overwrite it entirely, otherwise we can
get artifacts of earlier talk that do not belong */
if (tmp->tail + f->datalen < sizeof(tmp->buf) / 2) {
memcpy((tmp->buf + tmp->tail), f->data, f->datalen);
tmp->tail += f->datalen/2;
} else {
ast_log(LOG_WARNING, "Out of buffer space\n");
return -1;
}
return 0;
}
static struct ast_frame *lintolpc10_frameout(struct ast_translator_pvt *tmp)
{
int x;
float tmpbuf[LPC10_SAMPLES_PER_FRAME];
INT32 bits[LPC10_BITS_IN_COMPRESSED_FRAME];
/* We can't work on anything less than a frame in size */
if (tmp->tail < LPC10_SAMPLES_PER_FRAME)
return NULL;
/* Encode a frame of data */
for (x=0;x<LPC10_SAMPLES_PER_FRAME;x++) {
tmpbuf[x] = (float)tmp->buf[x] / 32768.0;
}
lpc10_encode(tmpbuf, bits, tmp->lpc10.enc);
build_bits((unsigned char *)tmp->outbuf, bits);
tmp->f.frametype = AST_FRAME_VOICE;
tmp->f.subclass = AST_FORMAT_LPC10;
tmp->f.datalen = LPC10_BYTES_IN_COMPRESSED_FRAME;
tmp->f.timelen = 22;
/* We alternate between 22 and 23 ms to simulate 22.5 ms */
tmp->f.timelen += tmp->longer;
/* Use one of the two left over bits to record if this is a 22 or 23 ms frame...
important for IAX use */
tmp->longer = 1 - tmp->longer;
tmp->f.mallocd = 0;
tmp->f.offset = AST_FRIENDLY_OFFSET;
tmp->f.src = __PRETTY_FUNCTION__;
tmp->f.data = tmp->outbuf;
((char *)(tmp->f.data))[LPC10_BYTES_IN_COMPRESSED_FRAME - 1] |= tmp->longer;
tmp->tail -= LPC10_SAMPLES_PER_FRAME;
/* Move the data at the end of the buffer to the front */
if (tmp->tail)
memmove(tmp->buf, tmp->buf + LPC10_SAMPLES_PER_FRAME, tmp->tail * 2);
#if 0
/* Save a sample frame */
{ static int samplefr = 0;
if (samplefr == 0) {
int fd;
fd = open("lpc10.example", O_WRONLY | O_CREAT, 0644);
write(fd, tmp->f.data, tmp->f.datalen);
close(fd);
}
samplefr++;
}
#endif
return &tmp->f;
}
static void lpc10_destroy(struct ast_translator_pvt *pvt)
{
/* Enc and DEC are both just allocated, so they can be freed */
free(pvt->lpc10.enc);
free(pvt);
localusecnt--;
}
static struct ast_translator lpc10tolin =
{ "lpc10tolin",
AST_FORMAT_LPC10, AST_FORMAT_SLINEAR,
lpc10_dec_new,
lpc10tolin_framein,
lpc10tolin_frameout,
lpc10_destroy,
lpc10tolin_sample
};
static struct ast_translator lintolpc10 =
{ "lintolpc10",
AST_FORMAT_SLINEAR, AST_FORMAT_LPC10,
lpc10_enc_new,
lintolpc10_framein,
lintolpc10_frameout,
lpc10_destroy,
lintolpc10_sample
};
int unload_module(void)
{
int res;
pthread_mutex_lock(&localuser_lock);
res = ast_unregister_translator(&lintolpc10);
if (!res)
res = ast_unregister_translator(&lpc10tolin);
if (localusecnt)
res = -1;
pthread_mutex_unlock(&localuser_lock);
return res;
}
int load_module(void)
{
int res;
res=ast_register_translator(&lpc10tolin);
if (!res)
res=ast_register_translator(&lintolpc10);
else
ast_unregister_translator(&lpc10tolin);
return res;
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}

0
codecs/codec_mp3_d.c Executable file → Normal file
View File

0
codecs/g723_slin_ex.h Executable file → Normal file
View File

0
codecs/gsm/COPYRIGHT Executable file → Normal file
View File

0
codecs/gsm/Makefile Executable file → Normal file
View File

0
codecs/gsm/README Executable file → Normal file
View File

0
codecs/gsm/inc/config.h Executable file → Normal file
View File

0
codecs/gsm/inc/gsm.h Executable file → Normal file
View File

0
codecs/gsm/inc/private.h Executable file → Normal file
View File

0
codecs/gsm/inc/proto.h Executable file → Normal file
View File

0
codecs/gsm/inc/unproto.h Executable file → Normal file
View File

0
codecs/gsm/src/add.c Executable file → Normal file
View File

0
codecs/gsm/src/code.c Executable file → Normal file
View File

0
codecs/gsm/src/debug.c Executable file → Normal file
View File

0
codecs/gsm/src/decode.c Executable file → Normal file
View File

0
codecs/gsm/src/gsm_create.c Executable file → Normal file
View File

0
codecs/gsm/src/gsm_decode.c Executable file → Normal file
View File

0
codecs/gsm/src/gsm_destroy.c Executable file → Normal file
View File

0
codecs/gsm/src/gsm_encode.c Executable file → Normal file
View File

0
codecs/gsm/src/gsm_explode.c Executable file → Normal file
View File

0
codecs/gsm/src/gsm_implode.c Executable file → Normal file
View File

0
codecs/gsm/src/gsm_option.c Executable file → Normal file
View File

0
codecs/gsm/src/gsm_print.c Executable file → Normal file
View File

0
codecs/gsm/src/long_term.c Executable file → Normal file
View File

0
codecs/gsm/src/lpc.c Executable file → Normal file
View File

0
codecs/gsm/src/preprocess.c Executable file → Normal file
View File

0
codecs/gsm/src/rpe.c Executable file → Normal file
View File

0
codecs/gsm/src/short_term.c Executable file → Normal file
View File

0
codecs/gsm/src/table.c Executable file → Normal file
View File

0
codecs/gsm_slin_ex.h Executable file → Normal file
View File

0
codecs/lpc10/Makefile Executable file → Normal file
View File

0
codecs/lpc10/README Executable file → Normal file
View File

0
codecs/lpc10/analys.c Executable file → Normal file
View File

0
codecs/lpc10/bsynz.c Executable file → Normal file
View File

0
codecs/lpc10/chanwr.c Executable file → Normal file
View File

0
codecs/lpc10/dcbias.c Executable file → Normal file
View File

0
codecs/lpc10/decode.c Executable file → Normal file
View File

0
codecs/lpc10/deemp.c Executable file → Normal file
View File

0
codecs/lpc10/difmag.c Executable file → Normal file
View File

0
codecs/lpc10/dyptrk.c Executable file → Normal file
View File

0
codecs/lpc10/encode.c Executable file → Normal file
View File

0
codecs/lpc10/energy.c Executable file → Normal file
View File

0
codecs/lpc10/f2c.h Executable file → Normal file
View File

0
codecs/lpc10/f2clib.c Executable file → Normal file
View File

0
codecs/lpc10/ham84.c Executable file → Normal file
View File

0
codecs/lpc10/hp100.c Executable file → Normal file
View File

0
codecs/lpc10/invert.c Executable file → Normal file
View File

0
codecs/lpc10/irc2pc.c Executable file → Normal file
View File

0
codecs/lpc10/ivfilt.c Executable file → Normal file
View File

4
codecs/lpc10/lpc10.h Executable file → Normal file
View File

@@ -1,8 +1,8 @@
/*
$Log$
Revision 1.13 2000/01/05 00:20:06 markster
Version 0.3.0 from FTP
Revision 1.1 2000/01/05 00:20:06 markster
Version 0.1.2 from FTP
Revision 1.1 2000/01/05 00:20:06 markster
Add broken lpc10 code... It's not too far from working I don't think...

0
codecs/lpc10/lpcdec.c Executable file → Normal file
View File

0
codecs/lpc10/lpcenc.c Executable file → Normal file
View File

0
codecs/lpc10/lpcini.c Executable file → Normal file
View File

0
codecs/lpc10/lpfilt.c Executable file → Normal file
View File

0
codecs/lpc10/median.c Executable file → Normal file
View File

0
codecs/lpc10/mload.c Executable file → Normal file
View File

0
codecs/lpc10/onset.c Executable file → Normal file
View File

0
codecs/lpc10/pitsyn.c Executable file → Normal file
View File

0
codecs/lpc10/placea.c Executable file → Normal file
View File

0
codecs/lpc10/placev.c Executable file → Normal file
View File

0
codecs/lpc10/preemp.c Executable file → Normal file
View File

0
codecs/lpc10/prepro.c Executable file → Normal file
View File

0
codecs/lpc10/random.c Executable file → Normal file
View File

0
codecs/lpc10/rcchk.c Executable file → Normal file
View File

0
codecs/lpc10/synths.c Executable file → Normal file
View File

Some files were not shown because too many files have changed in this diff Show More