Try to establish a more generic low level soundcard/ISDN/winmodem hardware

abstraction layer at the most fundamental level.
This commit is contained in:
Morten Rolland 2001-10-28 19:02:03 +00:00
parent cc0fcaee0a
commit b47cebd49f
5 changed files with 109 additions and 106 deletions

View File

@ -197,7 +197,7 @@ void main(int ac, char **av)
mh = modem_initialize();
linedriver = ifax_create_module(IFAX_LINEDRIVER);
ifax_command(linedriver,CMD_LINEDRIVER_ISDN,hh);
ifax_command(linedriver,CMD_LINEDRIVER_HARDWARE,hh);
/* ifax_command(linedriver,CMD_LINEDRIVER_AUDIO); */
/* ifax_command(linedriver,CMD_LINEDRIVER_RECORD,"modem.dat"); */

View File

@ -98,11 +98,11 @@ struct HardwareHandle {
/* Read a number of samples from the hardware driver.
*/
void (*read)(struct HardwareHandle *hh, ifax_uint8 *samples);
void (*read)(struct HardwareHandle *hh, ifax_uint8 *smpls, int cnt);
/* Write a number of (16-bit signed) samples to the hardware driver.
*/
void (*write)(struct HardwareHandle *hh, ifax_sint16 *samples);
void (*write)(struct HardwareHandle *hh, ifax_sint16 *smpls, int cnt);
/* Supply the hardware driver with configuration parameters.
*/

View File

@ -34,6 +34,8 @@
* and work with the hardware abstraction layer in 'hardware-driver.c'
*/
#define _GNU_SOURCE
#define FSM_DEBUG_STATES
#include <stdio.h>
@ -178,27 +180,33 @@ static void isdn_service_select(struct HardwareHandle *hh, fd_set *rfd,
}
/* Write a set of voice samples to the ISDN device. The samples are in the
/*
* Write a set of voice samples to the ISDN device. The samples are in the
* form of an array, containing 16-bit signed, linear values.
* The array is *modified* by this function to the linear values actually
* transmitted. This is to help an echo cancel function to work on the true
* values as sent over the ISDN line to the remote end.
*
* The number of samples that needs to be sent is dictated by the value
* in the hardware driver handle: hh->write_size. This function will assume
* there are exactly this many samples in the 'src' array.
*/
static void isdn_write_samples(struct HardwareHandle *hh, ifax_sint16 *src)
#define ISDN_MAX_WRITE 4096
static void isdn_write_samples(struct HardwareHandle *hh,
ifax_sint16 *src, int cnt)
{
struct IsdnHandle *ih = hh->private;
ifax_uint8 *dst, wala;
ifax_uint16 linear;
int t;
dst = &ih->tmp_write[0];
ifax_uint8 tmp[2 * ISDN_MAX_WRITE];
for ( t=0; t < hh->write_size; t++ ) {
if ( cnt > ISDN_MAX_WRITE ) {
ifax_dprintf(DEBUG_ERROR,"Dropping %d samples in isdn_write_samples",
cnt - ISDN_MAX_WRITE);
cnt = ISDN_MAX_WRITE;
}
dst = &tmp[0];
while ( cnt-- > 0 ) {
linear = (ifax_uint16) *src;
wala = sint2wala[linear>>4];
@ -209,8 +217,7 @@ static void isdn_write_samples(struct HardwareHandle *hh, ifax_sint16 *src)
*dst++ = wala;
}
iobuffer_fill(ih->outgoing_buffer,&ih->tmp_write[0],
dst - &ih->tmp_write[0]);
iobuffer_fill(ih->outgoing_buffer, &tmp[0], dst - &tmp[0]);
}

View File

@ -47,7 +47,7 @@
*
*/
#include <strings.h>
#include <string.h>
#include <ifax/types.h>
#include <ifax/debug.h>

View File

@ -26,19 +26,8 @@
******************************************************************************
*/
/* NOTE: This code deals with timing-critical device-driver
* buffering with synchronized read/write on same
* device and between devices (ISDN/Audio).
* The relationships between buffer-sizes, read/write
* strategy and possible timing glitches should be
* investigated more closely. UPDATE: Should work well
* as long as (low-level) transmit-buffer is
* pre-charged to avoid draining.
*
* BUGS: Error situations are not handeled well (no warnings etc.)
*/
/* Maintain buffers and send/receive samples to the underlying
/*
* Maintain buffers and send/receive samples to the underlying
* physical transmission medium, like ISDN or a soundcard, named
* pipes for faxing self (debugging) etc.
*
@ -83,7 +72,8 @@
#include <ifax/misc/isdnline.h>
#include <ifax/modules/linedriver.h>
/* These defines should probably be run-time configurable.
/*
* These defines should probably be run-time configurable.
* BUFFERSIZE is the size of the main output buffer which is
* filled by the handle function (incomming signal-chain).
* We need a buffer here since the signaling-chain may not generate
@ -97,7 +87,8 @@
#define MAXIOSIZE 256
/* An instance of this linedriver module holds the following
/*
* An instance of this linedriver module holds the following
* state-information and buffer storage.
*/
@ -122,7 +113,8 @@ typedef struct {
} linedriver_private;
/* Method of operation:
/*
* Method of operation:
*
* The 'handle' function is called, possibly as a result of a 'demand'
* request, with data to fill the output queue (TX). However, no data
@ -154,97 +146,101 @@ static int linedriver_handle(ifax_modp self, void *data, size_t length)
static int work(ifax_modp self)
{
int wanted, chunk, total, more, t;
ifax_sint32 sp;
ifax_uint32 up;
linedriver_private *priv = self->private;
int wanted, chunk, total, more, t;
ifax_sint32 sp;
ifax_uint32 up;
linedriver_private *priv = self->private;
struct HardwareHandle *hh;
/* When driving the ISDN-line, this is how it works:
* Read as much as we can from the line, and then
* transmit *exactly* as much. This will keep the
* flow of samples smooth. It may be a very good idea
* to pre-charge the output-buffers somewhat to be more
* resistant to buffer-drains during heavy computations.
*/
/* When driving the ISDN-line, this is how it works:
* Read as much as we can from the line, and then
* transmit *exactly* as much. This will keep the
* flow of samples smooth. It may be a very good idea
* to pre-charge the output-buffers somewhat to be more
* resistant to buffer-drains during heavy computations.
*/
total = more = 0;
total = more = 0;
do {
do {
chunk = MAXIOSIZE; /* Default buffer-size of IO-operations */
chunk = MAXIOSIZE; /* Default size of IO-operations */
if ( priv->ih != 0 ) {
/* ISDN is online, read first, then transmit */
chunk = IsdnReadSamples(priv->ih,&priv->rx_buffer[0],MAXIOSIZE);
if ( chunk < 0 )
return -1;
more = chunk == MAXIOSIZE;
} else
for ( t=0; t < chunk; t++)
priv->rx_buffer[t] = 0;
if ( priv->hh != 0 && priv->hh->state == ONLINE ) {
/* Hardware is online, read first, then transmit */
hh = priv->hh;
chunk = hh->read(hh,&priv->rx_buffer[0],MAXIOSIZE);
if ( chunk < 0 )
return -1;
more = chunk == MAXIOSIZE;
} else {
for ( t=0; t < chunk; t++)
priv->rx_buffer[t] = 0;
}
/* Fill output queue by demanding data (if needed) */
while ( priv->output.size < chunk ) {
wanted = chunk - priv->output.size + 5;
ifax_handle_demand (self->recvfrom, wanted);
}
/* Fill output queue by demanding data (if needed) */
while ( priv->output.size < chunk ) {
wanted = chunk - priv->output.size + 5;
ifax_handle_demand (self->recvfrom, wanted);
}
/* Prepare TX-buffer */
priv->output.size -= chunk;
for (t = 0; t < chunk; t++) {
priv->tx_buffer[t] = priv->output.buffer[priv->output.rp++];
if ( priv->output.rp >= BUFFERSIZE )
priv->output.rp = 0;
}
/* Prepare TX-buffer */
priv->output.size -= chunk;
for (t = 0; t < chunk; t++) {
priv->tx_buffer[t] = priv->output.buffer[priv->output.rp++];
if ( priv->output.rp >= BUFFERSIZE )
priv->output.rp = 0;
}
if ( priv->ih != 0 ) {
/* ISDN is online, send TX-buffer */
IsdnWriteSamples(priv->ih,&priv->tx_buffer[0],chunk);
}
if ( priv->ih != 0 ) {
/* ISDN is online, send TX-buffer */
IsdnWriteSamples(priv->ih,&priv->tx_buffer[0],chunk);
}
if ( priv->loopback ) {
/* Software loopback enabled, overwrite receive-buffer */
for ( t=0; t < chunk; t++ )
priv->rx_buffer[t] = priv->tx_buffer[t];
}
if ( priv->loopback ) {
/* Software loopback enabled, overwrite receive-buffer */
for ( t=0; t < chunk; t++ )
priv->rx_buffer[t] = priv->tx_buffer[t];
}
if ( priv->dsp_fd >= 0 ) {
/* Soundcard audio monitoring enabled */
for ( t=0; t < chunk; t++ ) {
sp = priv->tx_buffer[t] * priv->dsp_tx_volume;
up = sp;
up >>= 16;
priv->stereo_buffer[t+t+0] = up;
sp = priv->rx_buffer[t] * priv->dsp_rx_volume;
up = sp;
up >>= 16;
priv->stereo_buffer[t+t+1] = up;
}
if ( priv->dsp_fd >= 0 ) {
/* Soundcard audio monitoring enabled */
for ( t=0; t < chunk; t++ ) {
sp = priv->tx_buffer[t] * priv->dsp_tx_volume;
up = sp;
up >>= 16;
priv->stereo_buffer[t+t+0] = up;
write(priv->dsp_fd, priv->stereo_buffer, 4*chunk);
}
sp = priv->rx_buffer[t] * priv->dsp_rx_volume;
up = sp;
up >>= 16;
priv->stereo_buffer[t+t+1] = up;
}
if ( priv->rec_fd >= 0 ) {
/* Recording all audio to file */
for ( t=0; t < chunk; t++ ) {
priv->stereo_buffer[t+t+0] = priv->tx_buffer[t];
priv->stereo_buffer[t+t+1] = priv->rx_buffer[t];
}
write(priv->dsp_fd, priv->stereo_buffer, 4*chunk);
}
write(priv->rec_fd, priv->stereo_buffer, 4*chunk);
}
if ( priv->rec_fd >= 0 ) {
/* Recording all audio to file */
for ( t=0; t < chunk; t++ ) {
priv->stereo_buffer[t+t+0] = priv->tx_buffer[t];
priv->stereo_buffer[t+t+1] = priv->rx_buffer[t];
}
if ( self->sendto != 0 ) {
/* Feed the receiver signaling-chain */
ifax_handle_input(self->sendto, &priv->rx_buffer[0], chunk);
}
write(priv->rec_fd, priv->stereo_buffer, 4*chunk);
}
total += chunk;
if ( self->sendto != 0 ) {
/* Feed the receiver signaling-chain */
ifax_handle_input(self->sendto, &priv->rx_buffer[0], chunk);
}
} while ( more );
total += chunk;
return total;
} while ( more );
return total;
}
static void linedriver_destroy(ifax_modp self)