home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
misc
/
volume32
/
radio2.0
/
patch01
next >
Wrap
Text File
|
1992-09-11
|
21KB
|
835 lines
Newsgroups: comp.sources.misc
From: Guido van Rossum <guido@cwi.nl>
Subject: v32i027: radio2.0 - Broadcast FM/AM over Local Area Network, Patch01
Message-ID: <1992Sep10.141840.16231@sparky.imd.sterling.com>
X-Md4-Signature: 96c8204ea252af922347fbab0d001977
Date: Thu, 10 Sep 1992 14:18:40 GMT
Approved: kent@sparky.imd.sterling.com
Submitted-by: Guido van Rossum <guido@cwi.nl>
Posting-number: Volume 32, Issue 27
Archive-name: radio2.0/patch01
Patch-To: radio2.0: Volume30, Issue 85-86
Environment: Sun, SGI, NeXT
Here is the first patch to radio 2.0.
The original was posted to alt.sources, and to comp.sources.misc. It
is also available by anonymous ftp from ftp.cwi.nl [192.16.184.180],
directory pub, files radio2.0.tar.Z (main distribution) and tuner1.3.shar
(Motif tuner program).
Changes in 2.0 patchlevel 1
---------------------------
- On the sun and sgi, radio tries to open a connection to the X server
(specified by the $DISPLAY environment variable) and every now and
then makes a small request to exercise the connection. This ensures
that if the user logs out, radio will quit. If no connection to the X
server can be made, these checks are not made and a warning is printed
that reminds the user to kill radio when logging out.
- The usage message is more informative.
- The new option '-t' (tee) sends output to both stdout and the audio
device. Thanks to Scott Hazen Mueller for suggesting this.
- The experimental option '-m mcastgrp' (for SGI only) specifies a
multicast group. By multicasting instead of broadcasting, you can
reduce the load on hosts that aren't listening (see the man page).
Here are the patches -- happy listening!
diff -rcN ../orig/MANIFEST ./MANIFEST
*** ../orig/MANIFEST Thu Sep 10 08:55:29 1992
--- ./MANIFEST Thu Sep 10 08:57:14 1992
***************
*** 16,20 ****
--- 16,21 ----
recordulaw.c 1
sndulaw.c 1
socklib.c 1
+ stations.pl 0
stations.py 1
ttytuner.py 2
diff -rcN ../orig/Makefile ./Makefile
*** ../orig/Makefile Thu Sep 10 08:55:30 1992
--- ./Makefile Thu Sep 10 08:57:14 1992
***************
*** 33,46 ****
# Platform-specific entries
sun4.0: # For SunOS 4.x
! make all
sun4.1: # For SunOS 4.1 with audio library (/usr/demo/SOUND)
! make all LIBS=/usr/demo/SOUND/libaudio.a \
CFLAGS='-DREMHDR -I/usr/demo/SOUND'
sgi: # For SGI IRIX 4.0
! make all recordulaw playulaw LIBS=-laudio
next: # NeXT 2.1
make all sndulaw
--- 33,46 ----
# Platform-specific entries
sun4.0: # For SunOS 4.x
! make all LIBS=-lX11
sun4.1: # For SunOS 4.1 with audio library (/usr/demo/SOUND)
! make all LIBS='-lX11 /usr/demo/SOUND/libaudio.a' \
CFLAGS='-DREMHDR -I/usr/demo/SOUND'
sgi: # For SGI IRIX 4.0
! make all recordulaw playulaw LIBS='-lX11 -laudio'
next: # NeXT 2.1
make all sndulaw
diff -rcN ../orig/README ./README
*** ../orig/README Thu Sep 10 08:55:31 1992
--- ./README Thu Sep 10 08:57:15 1992
***************
*** 1,7 ****
Welcome to the wonderful world of Local Area Network radio!
===========================================================
! This is Radio version 2.0, patchlevel 0.
If you have a local area network full of workstations with audio
capabilities and at least one FM/AM radio or other audio source, you
--- 1,7 ----
Welcome to the wonderful world of Local Area Network radio!
===========================================================
! This is Radio version 2.0, patchlevel 1.
If you have a local area network full of workstations with audio
capabilities and at least one FM/AM radio or other audio source, you
***************
*** 48,53 ****
--- 48,73 ----
This software is copyrighted. See the notice at the end of this file.
+ Changes in 2.0 patchlevel 1
+ ---------------------------
+
+ On the sun and sgi, radio tries to open a connection to the X server
+ (specified by the $DISPLAY environment variable) and every now and
+ then makes a small request to exercise the connection. This ensures
+ that if the user logs out, radio will quit. If no connection to the X
+ server can be made, these checks are not made and a warning is printed
+ that reminds the user to kill radio when logging out.
+
+ The usage message is more informative.
+
+ The new option '-t' (tee) sends output to both stdout and the audio
+ device. Thanks to Scott Hazen Mueller for suggesting this.
+
+ The experimental option '-m mcastgrp' (for SGI only) specifies a
+ multicast group. By multicasting instead of broadcasting, you can
+ reduce the load on hosts that aren't listening (see the man page).
+
+
Changes since version 1.0 patchlevel 4
--------------------------------------
***************
*** 217,222 ****
--- 237,250 ----
the users on each host where it finds a listener. You must then be
able to log in to that host remotely (with rlogin or rsh) without
typing your password.
+
+ There is also one Perl program, just to show that you don't need to be
+ entirely helpless if you don't have Python nor Motif:
+
+ The Perl program "stations.pl" listens for and prints essential
+ information about stations. Extension to the functionality if
+ "stations.py" is left as an exercise to the reader.
+
Author
------
diff -rcN ../orig/patchlevel.h ./patchlevel.h
*** ../orig/patchlevel.h Thu Sep 10 08:55:36 1992
--- ./patchlevel.h Thu Sep 10 08:57:15 1992
***************
*** 1,1 ****
! #define PATCHLEVEL 0
--- 1,1 ----
! #define PATCHLEVEL 1
diff -rcN ../orig/playulaw.c ./playulaw.c
*** ../orig/playulaw.c Thu Sep 10 08:55:36 1992
--- ./playulaw.c Thu Sep 10 08:57:15 1992
***************
*** 114,124 ****
signal(SIGINT, cleanup_handler);
signal(SIGTERM, cleanup_handler);
- /* Set the output sampling rate to 8000 Hz */
- pvbuf[0] = AL_OUTPUT_RATE;
- pvbuf[1] = AL_RATE_8000;
- ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 2L);
-
/* Configure and open an SGI audio port */
config = ALnewconfig();
ALsetchannels(config, AL_MONO);
--- 114,119 ----
***************
*** 129,134 ****
--- 124,135 ----
perror("ALopenport");
exit(1);
}
+
+ /* Set the output sampling rate to 8000 Hz */
+ /* Do this after ALopenport so we needn't undo it if that fails */
+ pvbuf[0] = AL_OUTPUT_RATE;
+ pvbuf[1] = AL_RATE_8000;
+ ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 2L);
#else
/* Write to /dev/audio */
if ((ofd = open("/dev/audio", O_WRONLY | O_NDELAY)) < 0) {
diff -rcN ../orig/radio.c ./radio.c
*** ../orig/radio.c Thu Sep 10 08:55:49 1992
--- ./radio.c Thu Sep 10 08:57:15 1992
***************
*** 41,46 ****
--- 41,48 ----
-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.
+ -t tee mode: send output to stdout as well as to audio h/w
+ -m mcastgrp multicast group (SGI only)
*/
#define BCASTCTLPORT 54319
***************
*** 53,61 ****
--- 55,66 ----
#ifdef sgi
#define USE_AL
+ #define CHECK_X_SERVER
+ #define HAVE_MCAST
#endif
#ifdef sun
#define USE_SUN
+ #define CHECK_X_SERVER
#endif
#ifdef NeXT
#define USE_NX
***************
*** 72,77 ****
--- 77,86 ----
#include <sys/time.h>
#include <netinet/in.h>
+ #ifdef HAVE_MCAST
+ #include <arpa/inet.h>
+ #endif
+
#ifdef USE_AL
#include <audio.h>
#include "libst.h"
***************
*** 96,101 ****
--- 105,111 ----
int interruptable = 1;
int actlfd = -1;
+ int afd = -1;
void sigpoll_handler();
#endif /* USE_SUN */
***************
*** 106,111 ****
--- 116,126 ----
SNDSoundStruct *snd[NUM_BUFFER];
#endif /* USE_NX */
+ #ifdef CHECK_X_SERVER
+ #include <X11/Xlib.h>
+ Display *xdisplay = 0;
+ #endif
+
/* getopt() interface */
extern int optind;
extern char * optarg;
***************
*** 114,123 ****
--- 129,142 ----
int pausing = 0; /* Flag set when pausing */
int ofd = -1; /* Output file descriptor */
int volume = -1; /* -v parameter */
+ int pdebug = 0; /* -p parameter */
+ char *mcastgrp = 0; /* -m parameter */
/* Forward functions */
void open_speaker();
void close_speaker();
+ void checkalive();
+ void setmcast();
main(argc, argv)
int argc;
***************
*** 131,142 ****
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;
#ifdef USE_AL
short obuf[BUFFERSIZE];
int i;
--- 150,163 ----
int fromlen;
int c;
int filter = 0;
+ int tee = 0;
int nfds;
fd_set inputset;
int n;
char *localname = (char *) NULL;
char *remotename = (char *) NULL;
+ struct timeval timeout;
+ int packetcount;
#ifdef USE_AL
short obuf[BUFFERSIZE];
int i;
***************
*** 145,153 ****
int akt_buf;
#endif
! /* Always change these two macros together! */
! #define OPTIONS "c:dfl:np:r:sv:"
! #define USAGE "usage: %s [-c ctlport] [-d] [-f] [-l localhost] [-n] [-p port]\n\t[-r remotehost] [-s] [-v volume(0-100)]\n"
while ((c = getopt(argc, argv, OPTIONS)) != EOF) {
switch (c) {
--- 166,189 ----
int akt_buf;
#endif
! /* Always change these two macros and the following switch together! */
! #define OPTIONS "c:dfl:m:np:r:stv:"
! #define USAGE "usage: %s [options]\n\
! User options:\n\
! -p port : port to listen to (default 54321; 1..99 ==> 54321..54419)\n\
! -v volume : volume setting (1-100; default unchanged)\n\
! Expert options:\n\
! -f : filter mode (write data to stdout)\n\
! -t : tee mode (write data to stdout as well as to audio device)\n\
! -n : not interruptable by other sources (Sun only)\n\
! -c ctlport : control port for tuner programs (default 54320)\n\
! -s : secure mode: no control port (disallow tuner programs)\n\
! Guru options:\n\
! -l localhost : listen to packets to this host only\n\
! -r remothost : receive packets from that host only\n\
! -m mcastgrp : multicast group (SGI only)\n\
! -d : debugging mode (writes messages to stderr)\n\
! "
while ((c = getopt(argc, argv, OPTIONS)) != EOF) {
switch (c) {
***************
*** 171,186 ****
case 'd':
pdebug = 1;
break;
! #ifdef USE_SUN
case 'n':
interruptable = 0;
break;
- #endif /* USE_SUN */
case 's':
ctlport = -1;
break;
case 'f':
filter = 1;
break;
case 'v':
volume = atoi(optarg);
--- 207,236 ----
case 'd':
pdebug = 1;
break;
! case 'm':
! #ifdef HAVE_MCAST
! mcastgrp = optarg;
! #else
! fprintf(stderr, "(-m not supported here)\n");
! #endif
! break;
case 'n':
+ #ifdef USE_SUN
interruptable = 0;
+ #else
+ fprintf(stderr, "(-n not supported here)\n");
+ #endif
break;
case 's':
ctlport = -1;
break;
case 'f':
filter = 1;
+ tee = 0;
+ break;
+ case 't':
+ tee = 1;
+ filter = 0;
break;
case 'v':
volume = atoi(optarg);
***************
*** 188,198 ****
}
}
! if (filter) {
ofd = fileno(stdout);
! }
! else {
open_speaker();
}
if (ctlport >= 0)
--- 238,261 ----
}
}
! /* Meaning of the 'tee' and 'filter' flags:
! At most one of these can be on.
! if tee is on: write stdout and "/dev/audio";
! if filter is on: write stdout only;
! if both are off: write "/dev/audio" only;
! where "/dev/audio" stands for whatever audio hardware we have. */
!
! if (filter || tee)
ofd = fileno(stdout);
! if (!filter) {
open_speaker();
+ #ifdef CHECK_X_SERVER
+ xdisplay = XOpenDisplay((char *)NULL);
+ if (xdisplay == NULL) {
+ fprintf(stderr,
+ "radio: warning: no X server -- you must kill radio when you log out!\n");
+ }
+ #endif
}
if (ctlport >= 0)
***************
*** 202,219 ****
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);
}
--- 265,294 ----
ctls = -1;
s = opensock("data", localname, receiveport, remotename, SENDPORT, 0);
+ if (mcastgrp)
+ setmcast(s, mcastgrp);
+
+ packetcount = 0;
for (;;) {
/*
** Wait until one of the sockets becomes ready
*/
! for (;;) {
! nfds = (s > ctls ? s : ctls) + 1;
! FD_ZERO(&inputset);
! FD_SET(s, &inputset);
! if (ctls >= 0)
! FD_SET(ctls, &inputset);
! timeout.tv_sec = 30;
! timeout.tv_usec = 0;
! n = select(nfds, &inputset, 0, 0, &timeout);
! if (n > 0)
! break;
! if (n == 0) {
! checkalive();
! }
! else if (errno != EINTR) {
perror("select");
exit(1);
}
***************
*** 241,247 ****
else
pdebug++;
}
! if ( n <= CTLPKTSIZE ) {
/*
** It looks like a control packet. Check it.
*/
--- 316,322 ----
else
pdebug++;
}
! if (n <= CTLPKTSIZE) {
/*
** It looks like a control packet. Check it.
*/
***************
*** 278,283 ****
--- 353,360 ----
s = opensock("new data", localname,
receiveport, remotename,
SENDPORT, 0);
+ if (mcastgrp)
+ setmcast(s, mcastgrp);
break;
case 'i': /* Info */
sprintf(buf, "radio:I:%d:%d",
***************
*** 320,326 ****
obuf[i] = st_ulaw_to_linear(buf[i]);
ALwritesamps(aport, obuf, (long)n);
}
- else
#endif /* USE_AL */
#ifdef USE_NX
if (!filter) {
--- 397,402 ----
***************
*** 337,349 ****
akt_buf+1, 5, 0, 0, 0);
akt_buf = (akt_buf + 1) % NUM_BUFFER;
}
! else
! #endif/* USE_NX */
! if (write(ofd, buf, n) != n) {
! perror("write");
! break;
}
}
}
exit(0);
--- 413,438 ----
akt_buf+1, 5, 0, 0, 0);
akt_buf = (akt_buf + 1) % NUM_BUFFER;
}
! #endif /* USE_NX */
! #ifdef USE_SUN
! if (!filter) {
! if (write(afd, buf, n) != n) {
! perror("write afd");
! break;
! }
! }
! #endif /* USE_SUN */
! if (filter || tee) {
! if (write(ofd, buf, n) != n) {
! perror("write ofd");
! break;
! }
}
}
+ if (++packetcount > (30*8000 / BUFFERSIZE)) {
+ checkalive();
+ packetcount = 0;
+ }
}
exit(0);
***************
*** 416,422 ****
audio_info_t info;
/* Write to AUDIO_IODEV */
! if ((ofd = open(AUDIO_IODEV, O_WRONLY)) < 0) {
perror(AUDIO_IODEV);
exit(1);
}
--- 505,511 ----
audio_info_t info;
/* Write to AUDIO_IODEV */
! if ((afd = open(AUDIO_IODEV, O_WRONLY)) < 0) {
perror(AUDIO_IODEV);
exit(1);
}
***************
*** 425,431 ****
if (volume >= 0) {
AUDIO_INITINFO(&info);
info.play.gain = (AUDIO_MAX_GAIN * volume) / 100;
! if (ioctl(ofd, AUDIO_SETINFO, &info))
perror("volume setting");
}
--- 514,520 ----
if (volume >= 0) {
AUDIO_INITINFO(&info);
info.play.gain = (AUDIO_MAX_GAIN * volume) / 100;
! if (ioctl(afd, AUDIO_SETINFO, &info))
perror("volume setting");
}
***************
*** 449,458 ****
void close_speaker()
{
! (void) ioctl(ofd, I_FLUSH, FLUSHW);
! close(ofd);
close(actlfd);
! ofd = actlfd = -1;
}
void sigpoll_handler()
--- 538,547 ----
void close_speaker()
{
! (void) ioctl(afd, I_FLUSH, FLUSHW);
! close(afd);
close(actlfd);
! afd = actlfd = -1;
}
void sigpoll_handler()
***************
*** 463,472 ****
perror("AUDIO_GETINFO");
}
else if (ap.play.waiting) {
! (void) ioctl(ofd, I_FLUSH, FLUSHW);
! close(ofd);
/* The open() call blocks until we can use the device again */
! if ((ofd = open(AUDIO_IODEV, O_WRONLY)) < 0) {
perror(AUDIO_IODEV);
exit(1);
}
--- 552,561 ----
perror("AUDIO_GETINFO");
}
else if (ap.play.waiting) {
! (void) ioctl(afd, I_FLUSH, FLUSHW);
! close(afd);
/* The open() call blocks until we can use the device again */
! if ((afd = open(AUDIO_IODEV, O_WRONLY)) < 0) {
perror(AUDIO_IODEV);
exit(1);
}
***************
*** 488,494 ****
int err;
/* 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)) {
--- 577,583 ----
int err;
/* 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)) {
***************
*** 505,507 ****
--- 594,644 ----
}
#endif /* USE_NX */
+
+
+ void checkalive()
+ {
+ #ifdef CHECK_X_SERVER
+ if (xdisplay) {
+ Window focus;
+ int revert_to;
+ if (pdebug)
+ fprintf(stderr, "polling X server...\n");
+ /* Do a simple X request that needs a server round trip...
+ The error handler will kill us when the server is dead,
+ so that radio dies when the user logs out. */
+ XGetInputFocus(xdisplay, &focus, &revert_to);
+ if (pdebug)
+ fprintf(stderr, "X server OK\n");
+ }
+ else if (pdebug)
+ fprintf(stderr, "checkalive() is a no-op\n");
+ #endif /* CHECK_X_SERVER */
+ }
+
+ void setmcast(s, group)
+ int s;
+ char *group;
+ {
+ #ifdef HAVE_MCAST
+ struct in_addr grpaddr;
+ struct in_addr ifaddr;
+ struct ip_mreq mreq;
+
+ grpaddr.s_addr = inet_addr(group);
+ if (!IN_MULTICAST(grpaddr.s_addr)) {
+ fprintf(stderr, "Bad multicast group: %s\n", group);
+ exit(1);
+ }
+
+ ifaddr.s_addr = htonl(INADDR_ANY);
+
+ mreq.imr_multiaddr = grpaddr;
+ mreq.imr_interface = ifaddr;
+ if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ &mreq, sizeof(mreq)) < 0) {
+ perror("setsockopt mreq");
+ exit(1);
+ }
+ #endif
+ }
diff -rcN ../orig/radio.man ./radio.man
*** ../orig/radio.man Thu Sep 10 08:55:37 1992
--- ./radio.man Thu Sep 10 08:57:16 1992
***************
*** 14,22 ****
.B \-l
.I addr
] [
! .B \-n
]
! [
.B \-p
.I port
] [
--- 14,25 ----
.B \-l
.I addr
] [
! .B \-m
! .I mcastgrp
]
! [
! .B \-n
! ] [
.B \-p
.I port
] [
***************
*** 25,30 ****
--- 28,35 ----
] [
.B \-s
] [
+ .B \-t
+ ] [
.B \-v
.I volume
]
***************
*** 73,78 ****
--- 78,94 ----
.I addr
(useful for forwarding stations).
.TP 10
+ .BI "\-m " mcastgrp
+ Multicast group (SGI only).
+ This only makes sense if the same multicast group is passed to the
+ .B \-b
+ option of
+ .IR broadcast (1).
+ Using multicasting instead of broadcasting reduces the load on
+ machines that aren't listening.
+ Unfortunately, the choice of multicast groups is a black art.
+ In any case you probably need a multicast group per station.
+ .TP 10
.B \-n
Noninterruptable mode (Sun Sparc only).
By default,
***************
*** 99,104 ****
--- 115,124 ----
can override the port specified with \fB\-p\fP by sending a control
message to the control port of your radio program.
.TP 10
+ .B \-t
+ Tee mode: write the U-LAW audio data to stdout as well as
+ sending it to the audio hardware.
+ .TP 10
.BI "\-v " volume
Set the initial volume, on a scale from 0 to 100. (SGI and Sun Sparc only.)
By default, the volume is left unchanged.
***************
*** 107,113 ****
.SH AUTHOR
Guido van Rossum
.SH VERSION
! This manual page documents radio version 2.0, patchlevel 0.
.SH SEE ALSO
broadcast(1)
.SH COPYRIGHT
--- 127,133 ----
.SH AUTHOR
Guido van Rossum
.SH VERSION
! This manual page documents radio version 2.0, patchlevel 1.
.SH SEE ALSO
broadcast(1)
.SH COPYRIGHT
diff -rcN ../orig/stations.pl ./stations.pl
*** ../orig/stations.pl Wed Dec 31 18:00:00 1969
--- ./stations.pl Thu Sep 10 08:57:45 1992
***************
*** 0 ****
--- 1,28 ----
+ #!/usr/bin/perl
+ ##
+ ## Find radio stations
+ ##
+ ## (A small subset of the functionality of stations.py for now)
+ ##
+ ## Written by; Jeff Beadles jeff@onion.rain.com
+ ##
+ # this emulates #! processing on machines that don't support it.
+ eval "exec /usr/bin/perl -S $0 $*"
+ if $running_under_some_shell_and_not_perl;
+
+ require 'sys/socket.ph';
+
+ ($name, $aliases, $proto) = getprotobyname('udp');
+
+ $this = pack('S n a4 x8' , &AF_INET, 54317, "\0\0\0\0");
+
+ socket(S, &AF_INET, &SOCK_DGRAM, $proto) || die "socket: $!";
+ bind(S, $this) || die "bind: $!";
+
+ while (1) {
+ recv(S, $buf, 1024, 0) || die "recv: $!\n";
+ chop($buf);
+ ($t_radio,$t_s,$t_name,$t_port,$t_xmit,$t_log,$t_age) = split(/:/,$buf,7);
+ print "Bogus message '$buf'\n" if ($t_radio ne "radio");
+ print "Receiving station '$t_name' on port $t_port\n";
+ }
exit 0 # Just in case...