This is radio.c in view mode; [Download] [Up]
/***********************************************************
Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The
Netherlands.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the names of Stichting Mathematisch
Centrum or CWI not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior permission.
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
******************************************************************/
/* Receive audio UDP packets transmitted by broadcast.
Command line options:
-p port tune to this port number (default 54321)
(port numbers 1..99 are shorthands for 54321 and up)
-v volume output volume (range 0-100; default unchanged)
-c port use this control port (default 54320)
-s 'secure' mode: don't listen to the control port
-f work as a filter: send output to stdout instead of
directly to the audio hardware
-l addr listen only for packets to <arg> ip address
-r addr listen only for packets from <arg>
-d debug packets
-n noninterruptable -- by default radio will be interruptable
by other sound outputting programs, hoping they do not
take too long. This option turns off that feature.
*/
#define BCASTCTLPORT 54319
#define RADIOCTLPORT 54320
#define RCVPORT 54321
#define SENDPORT 54318
#define BUFFERSIZE 1400
#define CTLPKTSIZE 100
#ifdef sgi
#define USE_AL
#endif
#ifdef sun
#define USE_SUN
#endif
#ifdef NeXT
#define USE_NX
#endif
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#ifdef USE_AL
#include <audio.h>
#include "libst.h"
long savestate[] = {
AL_OUTPUT_RATE, 0,
AL_LEFT_SPEAKER_GAIN, 0,
AL_RIGHT_SPEAKER_GAIN, 0,
};
#endif
#ifdef USE_SUN
#include <stropts.h>
#include <sun/audioio.h>
#define AUDIO_IODEV "/dev/audio"
#define AUDIO_CTLDEV "/dev/audioctl"
int interruptable = 1;
int actlfd = -1;
#endif
#ifdef USE_NX
#include <sound/sound.h>
#define NUM_BUFFER 10
#endif
/* getopt() interface */
extern int optind;
extern char * optarg;
/* Forward */
void sigpoll_handler();
void cleanup_handler();
/* Globals */
int ofd; /* Output file descriptor */
main(argc, argv)
int argc;
char **argv;
{
int receiveport = RCVPORT;
int ctlport = RADIOCTLPORT;
char buf[BUFFERSIZE];
int s, ctls, curs;
struct sockaddr from;
int fromlen;
int c;
int filter = 0;
int nfds;
fd_set inputset;
int n;
int pdebug = 0;
char *localname = (char *) NULL;
char *remotename = (char *) NULL;
int volume = -1;
#ifdef USE_SUN
audio_info_t info;
#endif
#ifdef USE_AL
short obuf[BUFFERSIZE];
ALport aport;
ALconfig config;
int i;
long pvbuf[6];
#endif
#ifdef USE_NX
int err;
SNDSoundStruct *snd[NUM_BUFFER];
int akt_buf;
#endif
/* Always change these two macros together! */
#define OPTIONS "c:dfl:np:r:sv:"
#define USAGE "usage: %s [-d] [-f] [-n] [-s] [-p port] [-v volume(0-100)] [-c ctlport] [-l localhost] [-r remotehost]\n"
while ((c = getopt(argc, argv, OPTIONS)) != EOF) {
switch (c) {
case '?':
fprintf(stderr, USAGE, argv[0]);
exit(2);
case 'p':
receiveport = atoi(optarg);
if (0 < receiveport && receiveport < 100)
receiveport += RCVPORT-1;
break;
case 'c':
ctlport = atoi(optarg);
break;
case 'l':
localname = optarg;
break;
case 'r':
remotename = optarg;
break;
case 'd':
pdebug = 1;
break;
#ifdef USE_SUN
case 'n':
interruptable = 0;
break;
#endif
case 's':
ctlport = -1;
break;
case 'f':
filter = 1;
break;
case 'v':
volume = atoi(optarg);
break;
}
}
if (filter) {
ofd = fileno(stdout);
}
else {
#ifdef USE_AL
/* Fetch the original state */
ALgetparams(AL_DEFAULT_DEVICE, savestate,
sizeof(savestate) / sizeof(long));
/* Set signal handlers */
signal(SIGINT, cleanup_handler);
signal(SIGTERM, cleanup_handler);
/* Set the device to 8000 Hz */
pvbuf[0] = AL_OUTPUT_RATE;
pvbuf[1] = AL_RATE_8000;
/* Maybe also set the volume */
if (volume >= 0) {
pvbuf[2] = AL_LEFT_SPEAKER_GAIN;
pvbuf[3] = volume*255/100;
pvbuf[4] = AL_RIGHT_SPEAKER_GAIN;
pvbuf[5] = volume*255/100;
ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 6L);
}
else
ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 2L);
/* Configure and open an SGI audio port */
config = ALnewconfig();
ALsetchannels(config, AL_MONO);
ALsetwidth(config, AL_SAMPLE_16);
ALsetqueuesize(config, 16000); /* 2 seconds slop */
aport = ALopenport("radio", "w", config);
if (aport == NULL) {
perror("ALopenport");
exit(1);
}
#endif
#ifdef USE_SUN
/* Write to AUDIO_IODEV */
if ((ofd = open(AUDIO_IODEV, O_WRONLY)) < 0) {
perror(AUDIO_IODEV);
exit(1);
}
/* Set the volume */
if (volume >= 0) {
AUDIO_INITINFO(&info);
info.play.gain = (AUDIO_MAX_GAIN * volume) / 100;
if (ioctl(ofd, AUDIO_SETINFO, &info))
perror("volume setting");
}
/* We need to open the audio control port to detect
if someone else wants to output to /dev/audio.
If this fails (e.g., in SunOS 4.0), print a message
but don't exit. */
if (interruptable) {
if ((actlfd = open(AUDIO_CTLDEV, O_RDWR)) < 0) {
perror(AUDIO_CTLDEV);
}
else if (ioctl(actlfd, I_SETSIG, S_MSG) < 0) {
perror("I_SETSIG");
}
else if (signal(SIGPOLL, sigpoll_handler) < 0) {
perror("signal(SIGPOLL)");
exit(1);
}
}
#endif
#ifdef USE_NX
/* Alloc NUM_BUFFER Sounds */
for( akt_buf = NUM_BUFFER; akt_buf > 0; akt_buf--) {
if (err = SNDAlloc(&snd[akt_buf-1], BUFFERSIZE,
SND_FORMAT_MULAW_8,
SND_RATE_CODEC, 1, 4)) {
fprintf(stderr,
"init: %s\n", SNDSoundError(err));
}
}
akt_buf = 0;
#endif
}
if (ctlport >= 0)
ctls = opensock("control", (char *)NULL, ctlport,
(char *)NULL, 0, 0);
else
ctls = -1;
s = opensock("data", localname, receiveport, remotename, SENDPORT, 0);
for (;;) {
/*
** Wait until one of the sockets becomes ready
*/
nfds = (s > ctls ? s : ctls) + 1;
FD_ZERO(&inputset);
FD_SET(s, &inputset);
if (ctls >= 0)
FD_SET(ctls, &inputset);
while (select(nfds, &inputset, 0, 0, 0) < 1) {
if(errno != EINTR) {
perror("select");
exit(1);
}
}
if (ctls >= 0 && FD_ISSET(ctls, &inputset))
curs = ctls;
else if (FD_ISSET(s, &inputset))
curs = s;
/*
** Read, and check for control packet
*/
fromlen = sizeof(from);
n = recvfrom(curs, buf, BUFFERSIZE, 0, &from, &fromlen);
if (n <= 0) {
if (n == 0)
continue; /* Ignore empty packets */
perror("read");
break;
}
if (pdebug) {
if(pdebug == 8) {
fprintf(stderr, "8 packets received\n");
pdebug = 1;
}
else
pdebug++;
}
if ( n <= CTLPKTSIZE ) {
/*
** It looks like a control packet. Check it.
*/
if (strncmp(buf, "radio:", 6) == 0) {
if (pdebug)
fprintf(stderr, "control packet\n");
switch(buf[6]) {
case 'e': /* Echo */
buf[6] = 'E';
sendto(curs, buf, n, 0,
&from, fromlen);
break;
case 't': /* Tune */
if (curs != ctls) {
if (pdebug)
fprintf(stderr,
"radio: illegal tune\n");
break;
}
#ifdef USE_SUN
if (!filter) {
(void) ioctl(ofd, I_FLUSH,
FLUSHW);
}
#endif
buf[n] = '\0';
receiveport = atoi(buf+8);
close(s);
s = opensock("new data", localname,
receiveport, remotename,
SENDPORT, 0);
break;
case 'i': /* Info */
sprintf(buf, "radio:I:%d",
receiveport);
sendto(curs, buf, strlen(buf), 0,
&from, fromlen);
break;
default:
if (pdebug)
fprintf(stderr,
"radio: illegal cmd 0x%x\n",
buf[6]);
}
}
else if (pdebug) {
fprintf(stderr,
"radio: ill-formatted command\n");
}
}
else {
#ifdef USE_AL
if (!filter) {
for (i = 0; i < n; i++)
obuf[i] = st_ulaw_to_linear(buf[i]);
ALwritesamps(aport, obuf, (long)n);
}
else
#endif
#ifdef USE_NX
if (!filter) {
int dummy;
char *ptr;
(void) SNDGetDataPointer(snd[akt_buf], &ptr, &dummy, &dummy);
SNDWait( akt_buf+1);
memcpy( ptr, buf, n);
snd[akt_buf] -> dataSize = n;
SNDStartPlaying(snd[akt_buf],akt_buf+1,5,0,0,0 );
akt_buf = ( akt_buf + 1) % NUM_BUFFER;
}
else
#endif
if (write(ofd, buf, n) != n) {
perror("write");
break;
}
}
}
exit(0);
}
#ifdef USE_SUN
void sigpoll_handler()
{
audio_info_t ap;
if (ioctl(actlfd, AUDIO_GETINFO, &ap) < 0) {
perror("AUDIO_GETINFO");
}
if (ap.play.waiting) {
close(ofd);
if ((ofd = open(AUDIO_IODEV, O_WRONLY)) < 0) {
perror(AUDIO_IODEV);
exit(1);
}
ap.play.waiting = 0;
if (ioctl(actlfd, AUDIO_SETINFO, &ap) < 0) {
perror("AUDIO_SETINFO");
}
}
}
#endif /*USE_SUN*/
#ifdef USE_AL
void cleanup_handler(sig)
int sig;
{
signal(sig, SIG_DFL);
ALsetparams(AL_DEFAULT_DEVICE, savestate,
sizeof(savestate) / sizeof(long));
kill(getpid(), sig);
}
#endif /* USE_AL */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.