Hi,
I managed to get SpeakFreely working between a normal Linux and an iPAQ,
a SGI and iPAQ and iPAQ/iPAQ (yes, we have two of them).
I know it's just a supoptimal solution for 16kHz in stereo are a bit
oversized for just speech communication but at least it works really
fine. Another flaw is that You can't use any SF but have to take the
modified one.
What I did was simply change the sample rate (speed) to 16000 and the
mode to stereo (remember to set Audio_info for both play and record,
channels=2). I compiled this version on both iPAQ and a X86-Linux and it
worked fine. This worked also for SGI, You just have to change
audio_sgi.c
Tilman
/*
Silicon Graphics audio drivers adapted from the stand-alone
Speak Freely for SGI designed and implemented by:
Paul Schurman
Espoo, Finland
16 July 1995
*/
#include "speakfree.h"
#ifdef sgi
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <dmedia/audio.h>
#include "ulaw2linear.h"
/* Local variables */
static ALport audioport; /* Audio I/O port */
static long origParams[] = {
AL_INPUT_RATE, 0,
AL_OUTPUT_RATE, 0,
AL_LEFT_SPEAKER_GAIN, 0,
AL_RIGHT_SPEAKER_GAIN, 0,
AL_LEFT_INPUT_ATTEN, 0,
AL_RIGHT_INPUT_ATTEN, 0
};
static long origMute[] = {
AL_SPEAKER_MUTE_CTL, 0
};
/* SOUNDINIT -- Open the sound peripheral and initialise for
access. Return TRUE if successful, FALSE
otherwise. */
int soundinit(iomode)
int iomode;
{
ALconfig audioconfig;
int err;
static long params[] = {
/* TS
AL_INPUT_RATE, 8000,
AL_OUTPUT_RATE, 8000
*/
AL_INPUT_RATE, 16000,
AL_OUTPUT_RATE, 16000
};
ALseterrorhandler(0);
/* Get a new audioconfig and set parameters. */
audioconfig = ALnewconfig();
ALsetsampfmt(audioconfig, AL_SAMPFMT_TWOSCOMP);
ALsetwidth(audioconfig, AL_SAMPLE_16);
/* TS
ALsetqueuesize(audioconfig, 8000L);
ALsetchannels(audioconfig, AL_MONO);
*/
ALsetqueuesize(audioconfig, 16000L);
ALsetchannels(audioconfig, AL_STEREO);
/* Save original of all global modes we change. */
ALgetparams(AL_DEFAULT_DEVICE, origMute, 2);
ALgetparams(AL_DEFAULT_DEVICE, origParams, 12);
/* Set input and output data rates to 8000 samples/second. */
ALsetparams(AL_DEFAULT_DEVICE, params, 4);
/* Open the audioport. */
audioport = ALopenport((iomode & O_WRONLY) ? "Speaker" : "Mike",
(iomode & O_WRONLY) ? "w" : "r", audioconfig);
if (audioport == (ALport) 0) {
err = oserror();
if (err == AL_BAD_NO_PORTS) {
fprintf(stderr, " System is out of audio ports\n");
} else if (err == AL_BAD_DEVICE_ACCESS) {
fprintf(stderr, " Couldn't access audio device\n");
} else if (err == AL_BAD_OUT_OF_MEM) {
fprintf(stderr, " Out of memory\n");
}
return FALSE;
}
if (ALfreeconfig(audioconfig) != 0) {
err = oserror();
if (err == AL_BAD_CONFIG) {
fprintf(stderr, " Config not valid");
return FALSE;
}
}
/* Initialized the audioport okay. */
return TRUE;
}
/* SOUNDTERM -- Close the sound device. */
void soundterm()
{
ALsetparams(AL_DEFAULT_DEVICE, origParams, 12);
ALsetparams(AL_DEFAULT_DEVICE, origMute, 2);
ALcloseport(audioport);
}
/* SOUNDPLAY -- Begin playing a sound. */
void soundplay(len, buf)
int len;
unsigned char *buf;
{
int i;
short abuf[BUFL];
for (i = 0; i < len; i++) {
abuf[i] = audio_u2s(buf[i]);
}
ALwritesamps(audioport, abuf, len);
}
/* SOUNDPLAYVOL -- Set playback volume from 0 (silence) to 100 (full on). */
void soundplayvol(value)
int value;
{
long par[] = {
AL_LEFT_SPEAKER_GAIN, 0,
AL_RIGHT_SPEAKER_GAIN, 0
};
par[1] = par[3] = (value * 255L) / 100;
ALsetparams(AL_DEFAULT_DEVICE, par, 4);
}
/* SOUNDRECGAIN -- Set recording gain from 0 (minimum) to 100 (maximum). */
void soundrecgain(value)
int value;
{
long par[] = {
AL_LEFT_INPUT_ATTEN, 0,
AL_RIGHT_INPUT_ATTEN, 0
};
par[1] = par[3] = ((100 - value) * 255L) / 100;
ALsetparams(AL_DEFAULT_DEVICE, par, 4);
}
/* SOUNDDEST -- Set destination for generated sound. If "where"
is 0, sound goes to the built-in speaker; if
1, to the audio output jack. */
void sounddest(where)
int where;
{
/* Since we can't mute independently, and this is used only
for ring, always unmute the speaker and headphones. */
static long par[] = {
AL_SPEAKER_MUTE_CTL, AL_SPEAKER_MUTE_OFF
};
ALsetparams(AL_DEFAULT_DEVICE, par, 2);
}
/* SOUNDGRAB -- Return audio information in the record queue. */
int soundgrab(buf, len)
char *buf;
int len;
{
int i;
short sb[BUFL];
/* long filled = ALgetfilled(audioport);
if (len > filled) {
len = filled;
}
len=488;
*/
/*len=1600;*/
if (len > 0) {
ALreadsamps(audioport, sb, len);
for (i = 0; i < len; i++) {
buf[i] = audio_s2u(sb[i]);
}
}
return len;
}
/* SOUNDFLUSH -- Flush any queued sound. */
void soundflush()
{
short sb[BUFL];
while (TRUE) {
long l = ALgetfilled(audioport);
if (l < 400) {
break;
} else {
if (l > BUFL) {
l = BUFL;
}
ALreadsamps(audioport, sb, l);
}
}
}
#endif /* sgi */
/*
Sound interface for Speak Freely for Unix
Designed and implemented in July of 1990 by John Walker
*/
#include "speakfree.h"
#ifdef AUDIO_DEVICE_FILE
#ifdef Solaris
#include <sys/filio.h>
#else
#include <sys/dir.h>
#include <sys/file.h>
#endif
#include <errno.h>
#include <sys/ioctl.h>
#ifdef sun
#include <sys/stropts.h>
#ifdef Solaris
#include <sys/audioio.h>
#else
#include <sun/audioio.h>
#endif
#else /* FreeBSD / Linux */
#ifdef LINUX
#include <linux/soundcard.h>
#else
#include <machine/soundcard.h>
#endif
#define AUDIO_MIN_GAIN 0
#define AUDIO_MAX_GAIN 255
static int abuf_size;
#endif
static int abuf_size;
#ifdef IN_AUDIO_DEV
#define SoundFileIn IN_AUDIO_DEV
#else
#define SoundFileIn "/dev/audio"
#endif
#ifdef OUT_AUDIO_DEV
#define SoundFileOut OUT_AUDIO_DEV
#else
#define SoundFileOut "/dev/audio"
#endif
#ifdef sun
#define AUDIO_CTLDEV "/dev/audioctl"
#else
#define AUDIO_CTLDEV "/dev/mixer"
#endif
signed char *devAudioInput = SoundFileIn, /* Audio device files to open. */ //TS
*devAudioOutput = SoundFileOut, /* These can overridden by the -y */
*devAudioControl = AUDIO_CTLDEV; /* option on sfmike and sfspeaker. */
#define MAX_GAIN 100
//TS
#define TS_SPEED 16000
#define TS_STEREO 1
#define TS_FORMAT AFMT_S16_LE
//end TS
struct sound_buf {
struct sound_buf *snext; /* Next sound buffer */
int sblen; /* Length of this sound buffer */
unsigned char sbtext[2]; /* Actual sampled sound */
};
/* Local variables */
static int audiof = -1; /* Audio device file descriptor */
static int Audio_fd; /* Audio control port */
#ifdef sun
static audio_info_t Audio_info; /* Current configuration info */
#endif
struct sound_buf *sbchain = NULL, /* Sound buffer chain links */
*sbtail = NULL;
static int sbtotal = 0; /* Total sample bytes in memory */
static int playing = FALSE; /* Replay in progress ? */
/* static int playqsize; */ /* Output queue size */
static int playlen = 0; /* Length left to play */
static unsigned char *playbuf= NULL; /* Current play pointer */
static int squelch = 0; /* Squelch value */
static int neverRelease = FALSE; /* Never release audio device. This
is set if we inherited our open
audio device file descriptor from
a parent process. If we release
it, there's no way we can get it
back, so we glom onto it until
we exit. */
/* Convert local gain into device parameters */
static unsigned scale_gain(g)
unsigned g;
{
return (AUDIO_MIN_GAIN + (unsigned)
((int) ((((double) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN)) *
((double) g / (double) MAX_GAIN)) + 0.5)));
}
#ifdef Solaris
/* SETAUBUFSIZE -- Preset size of internal /dev/audio buffer segments
Must be called before soundinit() */
static int aubufsize = 2048; /* Default */
void setaubufsize(size)
int size;
{
aubufsize = size;
}
#endif
/* SOUNDINIT -- Open the sound peripheral and initialise for
access. Return TRUE if successful, FALSE
otherwise. */
int soundinit(iomode)
int iomode;
{
int attempts = 3;
int format;
//TS
//int speed = 8000;
int speed = TS_SPEED;
//int stereo = 0; /* 0=mono, 1=stereo */
int stereo = TS_STEREO;
//end TS
#ifdef LINUX_DSP_SMALL_BUFFER
int arg = 0x7FFF000B, frag_size;
#ifdef FRAGMENT_BUFSIZE
#ifdef FRAGMENT_BUFPOWER
/* http://www.opensound.com/pguide/audio2.html
section "improving real-audio performance":
"Selecting buffering parameter"
buffer is FRAGMENT_BUFSIZE * 2 ^ FRAGMENT_BUFPOWER
eg.: 128 buffers (0x0080) of 64 (0x0006=2^6) bytes
arg = 0x00800006 -> 128 * 64 = 8192 bytes.
See README.Linux_OSS_bufsize for additional details.
Code contributed by Walter Haidinger
(http://members.kstp.at/wh/index.html). */
arg = ((((FRAGMENT_BUFSIZE < 2 ? 2 : FRAGMENT_BUFSIZE) & 0xFFFF) << 16) |
((FRAGMENT_BUFPOWER < 4 ? 4 : FRAGMENT_BUFPOWER) & 0xF));
#endif
#endif
#endif
/* If we've been handed open file descriptors for the
audio files on a silver platter, we never release
them and hence don't need to re-open them, even if
sfspeaker is trying to be nice about releasing
audio output when it's been idle for a while. */
if (neverRelease) {
return TRUE;
}
assert(audiof == -1);
/* When opening the audio device file and control file, we
check for a specification which begins with a sharp sign
and, if present, use the integer which follows as the number
of an already-open file descriptor. This allows a launcher
program to open the audio device and then fork two processes
which invoke sfmike and sfspeaker. Why go to all this
trouble? Because some audio drivers, particularly on
Linux, don't permit two separate programs to open /dev/audio
simultaneously, even though function just fine in full
duplex. This kludge allows getting aroung around that
restriction. */
while (attempts-- > 0) {
signed char *adf = (iomode == O_RDONLY) ? devAudioInput : devAudioOutput; //TS
if (adf[0] == '#') {
audiof = atoi(adf + 1);
neverRelease = TRUE;
} else {
audiof = open(adf, iomode);
}
if (audiof >= 0) {
if (devAudioControl[0] == '#') {
Audio_fd = atoi(devAudioControl + 1);
} else {
Audio_fd = open(devAudioControl, O_RDWR);
}
if (Audio_fd < 0) {
perror(devAudioControl);
close(audiof);
audiof = -1;
return FALSE;
}
/*fcntl(audiof, F_SETFL, O_NDELAY);*/
#ifdef NEEDED_LINEAR
#ifdef M_LITTLE_ENDIAN
//TS
format = TS_FORMAT;
//format = AFMT_U16_LE;
//end TS
#else
format = AFMT_S16_BE;
#endif
{
int linearSet = FALSE;
if (ioctl(audiof, SNDCTL_DSP_SETFMT, &format) == -1) {
perror("SNDCTL_DSP_SETFMT");
} else if (ioctl(audiof, SNDCTL_DSP_STEREO, &stereo) == -1) {
perror("SNDCTL_DSP_STEREO");
} else if (ioctl(audiof, SNDCTL_DSP_SPEED, &speed) == -1) {
perror("SNDCTL_DSP_SPEED");
} else {
linearSet = TRUE;
}
if (!linearSet) {
soundterm();
return FALSE;
}
}
#endif
#ifdef LINUX_DSP_SMALL_BUFFER
/* Some Linux sound drivers use a large audio input buffer
which results in a long delay between the time audio is
recorded and when it is delivered to a program. The
following attempts to set the input buffer size to
reduce the delay. You can explicitly set the buffer size
by defining FRAGMENT_BUFSIZE and FRAGMENT_BUFPOWER or
leave these values undefined, in which case a buffer size
of 2048 bytes will be used. */
if (ioctl(audiof, SNDCTL_DSP_SETFRAGMENT, &arg) == -1) {
/* Ignore EINVAL if we were handed an open file descriptor
because that just means that sound is already being
transferred, which, in turn, means that another process
has already configured the device.
*/
if ((errno != EINVAL) || !neverRelease) {
perror("SNDCTL_DSP_SETFRAGMENT (LINUX_DSP_SMALL_BUFFER defined)");
}
/* This isn't fatal, so keep on going. */
}
if (ioctl(audiof, SNDCTL_DSP_GETBLKSIZE, &frag_size) == -1) {
perror("SNDCTL_DSP_GETBLKSIZE (LINUX_DSP_SMALL_BUFFER defined)");
soundterm();
return FALSE;
}
#endif
#ifndef sun
#ifndef AUDIO_BLOCKING
if (ioctl(audiof, SNDCTL_DSP_NONBLOCK, NULL) < 0) {
perror("SNDCTL_DSP_NONBLOCK");
soundterm();
return FALSE;
}
if (ioctl(audiof, SNDCTL_DSP_GETBLKSIZE, &abuf_size) < 0) {
perror("SNDCTL_DSP_GETBLKSIZE");
soundterm();
return FALSE;
}
#endif
#else
AUDIO_INITINFO(&Audio_info);
/* We always fill in the information for
record and play regardless of the open mode since
we may be called from sflaunch to open in O_RDWR. */
//Audio_info.play.sample_rate = 8000;
Audio_info.play.sample_rate = TS_SPEED; //TS
//Audio_info.play.channels = 1;
Audio_info.play.channels = 2; //TS
Audio_info.play.precision = 8;
Audio_info.play.encoding = AUDIO_ENCODING_ULAW;
Audio_info.record.sample_rate = TS_SPEED; //TS
//Audio_info.record.sample_rate = 8000;
//Audio_info.record.channels = 1;
Audio_info.record.channels = 2; //TS
Audio_info.record.precision = 8;
Audio_info.record.encoding = AUDIO_ENCODING_ULAW;
#ifdef Solaris
Audio_info.record.buffer_size = aubufsize;
#endif
ioctl(Audio_fd, AUDIO_SETINFO, &Audio_info);
#endif
return TRUE;
}
if (errno != EINTR) {
break;
}
fprintf(stderr, "Audio open: retrying EINTR attempt %d\n", attempts);
}
return FALSE;
}
/* SOUNDTERM -- Close the sound device. */
void soundterm()
{
if ((!neverRelease) && (audiof >= 0)) {
if (close(audiof) < 0) {
perror("closing audio device");
}
if (close(Audio_fd) < 0) {
perror("closing audio control device");
}
audiof = -1;
}
}
/* SOUND_OPEN_FILE_DESCRIPTORS -- Obtain file descriptors of open
audio and audio control device files. */
void sound_open_file_descriptors(audio_io, audio_ctl)
int *audio_io, *audio_ctl;
{
*audio_io = audiof;
*audio_ctl = Audio_fd;
}
/* SOUNDPLAY -- Begin playing a sound. */
void soundplay(len, buf)
int len;
unsigned char *buf;
{
int ios;
#ifdef NEEDED_LINEAR
int i, p;
short c;
unsigned char abuf[BUFL];
#endif
assert(audiof != -1);
while (TRUE) {
#ifdef NEEDED_LINEAR
p = 0;
for ( i=0 ; i< len ; i++)
{
c = (short)ulaw2linear(buf[i]);
abuf[p++] = (unsigned char)(c & 0xff);
abuf[p++] = (unsigned char)((c >> 8) & 0xff);
}
ios = write(audiof, abuf, len*2);
#else
ios = write(audiof, buf, len);
#endif
if (ios == -1) {
sf_usleep(100000);
} else {
if (ios < len) {
buf += ios;
len -= ios;
} else {
break;
}
}
}
}
/* SOUNDPLAYVOL -- Set playback volume from 0 (silence) to 100 (full on). */
void soundplayvol(value)
int value;
{
#ifdef sun
AUDIO_INITINFO(&Audio_info);
Audio_info.play.gain = scale_gain(value);
if (ioctl(Audio_fd, AUDIO_SETINFO, &Audio_info) < 0) {
perror("Set play volume");
}
#else
int arg;
arg = (value << 8) | value;
if (ioctl(Audio_fd, MIXER_WRITE(SOUND_MIXER_PCM), &arg) < 0)
perror("SOUND_MIXER_PCM");
#endif
}
/* SOUNDRECGAIN -- Set recording gain from 0 (minimum) to 100 (maximum). */
void soundrecgain(value)
int value;
{
#ifdef sun
AUDIO_INITINFO(&Audio_info);
Audio_info.record.gain = scale_gain(value);
if (ioctl(Audio_fd, AUDIO_SETINFO, &Audio_info) < 0) {
perror("Set record gain");
}
#else
int arg;
arg = (value << 8) | value;
if (ioctl(Audio_fd, SOUND_MIXER_WRITE_RECLEV, &arg) < 0)
perror("SOUND_MIXER_WRITE_RECLEV");
#endif
}
/* SOUNDDEST -- Set destination for generated sound. If "where"
is 0, sound goes to the built-in speaker; if
1, to the audio output jack. */
void sounddest(where)
int where;
{
#ifdef sun
AUDIO_INITINFO(&Audio_info);
Audio_info.play.port = (where == 0 ? AUDIO_SPEAKER : AUDIO_HEADPHONE);
if (ioctl(Audio_fd, AUDIO_SETINFO, &Audio_info) < 0) {
perror("Set output port");
}
#endif
}
/* SOUNDGRAB -- Return audio information in the record queue. */
int soundgrab(buf, len)
signed char *buf; //TS
int len;
{
long read_size;
int c;
#ifdef NEEDED_LINEAR
int i, result;
static short buf2[BUFL];
read_size = len*2;
#else
read_size = len;
#endif
#ifndef sun
#ifndef AUDIO_BLOCKING
if (read_size > abuf_size) {
read_size = abuf_size;
}
#endif
#endif
while (TRUE) {
#ifdef NEEDED_LINEAR
c = read(audiof, buf2, read_size);
result = c;
if ( c > 0 ) {
result = c/2;
for (i = 0; i < c/2; i++) {
buf[i] = linear2ulaw(buf2[i]);
}
}
#else
c = read(audiof, buf, read_size);
#endif
if (c < 0) {
if (errno == EINTR) {
continue;
} else if (errno == EAGAIN) {
c = 0;
#ifdef NEEDED_LINEAR
result = 0;
#endif
}
}
break;
}
if (c < 0) {
perror("soundgrab");
}
#ifdef NEEDED_LINEAR
return result;
#else
return c;
#endif
}
/* SOUNDFLUSH -- Flush any queued sound. */
void soundflush()
{
signed char sb[BUFL]; //TS
#ifndef sun
int c;
#endif
#ifndef sun
#ifndef AUDIO_BLOCKING
while (TRUE) {
c = read(audiof, sb, BUFL < abuf_size ? BUFL : abuf_size);
if (c < 0 && errno == EAGAIN)
c = 0;
if (c < 0)
perror("soundflush");
if (c <= 0)
break;
}
#endif
#else
if (ioctl(audiof, I_FLUSH, FLUSHR)) {
perror("soundflush");
}
#endif
}
#endif /* AUDIO_DEVICE_FILE */
This archive was generated by hypermail 2.1.8 : Tue May 04 2004 - 09:43:56 EDT