home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #20 / NN_1992_20.iso / spool / comp / sources / misc / 3918 < prev    next >
Encoding:
Text File  |  1992-09-10  |  20.7 KB  |  840 lines

  1. Newsgroups: comp.sources.misc
  2. Path: sparky!kent
  3. From: Guido van Rossum <guido@cwi.nl>
  4. Subject:  v32i027:  radio2.0 - Broadcast FM/AM over Local Area Network, Patch01
  5. Message-ID: <1992Sep10.141840.16231@sparky.imd.sterling.com>
  6. Followup-To: comp.sources.d
  7. X-Md4-Signature: 96c8204ea252af922347fbab0d001977
  8. Sender: kent@sparky.imd.sterling.com (Kent Landfield)
  9. Organization: Sterling Software
  10. Date: Thu, 10 Sep 1992 14:18:40 GMT
  11. Approved: kent@sparky.imd.sterling.com
  12. Lines: 826
  13.  
  14. Submitted-by: Guido van Rossum <guido@cwi.nl>
  15. Posting-number: Volume 32, Issue 27
  16. Archive-name: radio2.0/patch01
  17. Patch-To: radio2.0: Volume30, Issue 85-86
  18. Environment: Sun, SGI, NeXT
  19.  
  20. Here is the first patch to radio 2.0.
  21.  
  22. The original was posted to alt.sources, and to comp.sources.misc.  It 
  23. is also available by anonymous ftp from ftp.cwi.nl [192.16.184.180], 
  24. directory pub, files radio2.0.tar.Z (main distribution) and tuner1.3.shar 
  25. (Motif tuner program).
  26.   
  27. Changes in 2.0 patchlevel 1
  28. ---------------------------
  29.  
  30. - On the sun and sgi, radio tries to open a connection to the X server
  31.   (specified by the $DISPLAY environment variable) and every now and
  32.   then makes a small request to exercise the connection.  This ensures
  33.   that if the user logs out, radio will quit.  If no connection to the X
  34.   server can be made, these checks are not made and a warning is printed
  35.   that reminds the user to kill radio when logging out.
  36.  
  37. - The usage message is more informative.
  38.  
  39. - The new option '-t' (tee) sends output to both stdout and the audio
  40.   device.  Thanks to Scott Hazen Mueller for suggesting this.
  41.  
  42. - The experimental option '-m mcastgrp' (for SGI only) specifies a
  43.   multicast group.  By multicasting instead of broadcasting, you can
  44.   reduce the load on hosts that aren't listening (see the man page).
  45.  
  46. Here are the patches -- happy listening!
  47.  
  48. diff -rcN ../orig/MANIFEST ./MANIFEST
  49. *** ../orig/MANIFEST    Thu Sep 10 08:55:29 1992
  50. --- ./MANIFEST    Thu Sep 10 08:57:14 1992
  51. ***************
  52. *** 16,20 ****
  53. --- 16,21 ----
  54.    recordulaw.c               1    
  55.    sndulaw.c                  1    
  56.    socklib.c                  1    
  57. +  stations.pl                0    
  58.    stations.py                1    
  59.    ttytuner.py                2    
  60. diff -rcN ../orig/Makefile ./Makefile
  61. *** ../orig/Makefile    Thu Sep 10 08:55:30 1992
  62. --- ./Makefile    Thu Sep 10 08:57:14 1992
  63. ***************
  64. *** 33,46 ****
  65.   # Platform-specific entries
  66.   
  67.   sun4.0:        # For SunOS 4.x
  68. !         make all
  69.   
  70.   sun4.1:        # For SunOS  4.1 with audio library (/usr/demo/SOUND)
  71. !         make all LIBS=/usr/demo/SOUND/libaudio.a \
  72.               CFLAGS='-DREMHDR -I/usr/demo/SOUND'
  73.   
  74.   sgi:        # For SGI IRIX 4.0
  75. !         make all recordulaw playulaw LIBS=-laudio
  76.   
  77.   next:        # NeXT 2.1
  78.           make all sndulaw
  79. --- 33,46 ----
  80.   # Platform-specific entries
  81.   
  82.   sun4.0:        # For SunOS 4.x
  83. !         make all LIBS=-lX11
  84.   
  85.   sun4.1:        # For SunOS  4.1 with audio library (/usr/demo/SOUND)
  86. !         make all LIBS='-lX11 /usr/demo/SOUND/libaudio.a' \
  87.               CFLAGS='-DREMHDR -I/usr/demo/SOUND'
  88.   
  89.   sgi:        # For SGI IRIX 4.0
  90. !         make all recordulaw playulaw LIBS='-lX11 -laudio'
  91.   
  92.   next:        # NeXT 2.1
  93.           make all sndulaw
  94. diff -rcN ../orig/README ./README
  95. *** ../orig/README    Thu Sep 10 08:55:31 1992
  96. --- ./README    Thu Sep 10 08:57:15 1992
  97. ***************
  98. *** 1,7 ****
  99.   Welcome to the wonderful world of Local Area Network radio!
  100.   ===========================================================
  101.   
  102. ! This is Radio version 2.0, patchlevel 0.
  103.   
  104.   If you have a local area network full of workstations with audio
  105.   capabilities and at least one FM/AM radio or other audio source, you
  106. --- 1,7 ----
  107.   Welcome to the wonderful world of Local Area Network radio!
  108.   ===========================================================
  109.   
  110. ! This is Radio version 2.0, patchlevel 1.
  111.   
  112.   If you have a local area network full of workstations with audio
  113.   capabilities and at least one FM/AM radio or other audio source, you
  114. ***************
  115. *** 48,53 ****
  116. --- 48,73 ----
  117.   This software is copyrighted.  See the notice at the end of this file.
  118.   
  119.   
  120. + Changes in 2.0 patchlevel 1
  121. + ---------------------------
  122. + On the sun and sgi, radio tries to open a connection to the X server
  123. + (specified by the $DISPLAY environment variable) and every now and
  124. + then makes a small request to exercise the connection.  This ensures
  125. + that if the user logs out, radio will quit.  If no connection to the X
  126. + server can be made, these checks are not made and a warning is printed
  127. + that reminds the user to kill radio when logging out.
  128. + The usage message is more informative.
  129. + The new option '-t' (tee) sends output to both stdout and the audio
  130. + device.  Thanks to Scott Hazen Mueller for suggesting this.
  131. + The experimental option '-m mcastgrp' (for SGI only) specifies a
  132. + multicast group.  By multicasting instead of broadcasting, you can
  133. + reduce the load on hosts that aren't listening (see the man page).
  134.   Changes since version 1.0 patchlevel 4
  135.   --------------------------------------
  136.   
  137. ***************
  138. *** 217,222 ****
  139. --- 237,250 ----
  140.   the users on each host where it finds a listener.  You must then be
  141.   able to log in to that host remotely (with rlogin or rsh) without
  142.   typing your password.
  143. + There is also one Perl program, just to show that you don't need to be
  144. + entirely helpless if you don't have Python nor Motif:
  145. + The Perl program "stations.pl" listens for and prints essential
  146. + information about stations.  Extension to the functionality if
  147. + "stations.py" is left as an exercise to the reader.
  148.   
  149.   Author
  150.   ------
  151. diff -rcN ../orig/patchlevel.h ./patchlevel.h
  152. *** ../orig/patchlevel.h    Thu Sep 10 08:55:36 1992
  153. --- ./patchlevel.h    Thu Sep 10 08:57:15 1992
  154. ***************
  155. *** 1,1 ****
  156. ! #define PATCHLEVEL 0
  157. --- 1,1 ----
  158. ! #define PATCHLEVEL 1
  159. diff -rcN ../orig/playulaw.c ./playulaw.c
  160. *** ../orig/playulaw.c    Thu Sep 10 08:55:36 1992
  161. --- ./playulaw.c    Thu Sep 10 08:57:15 1992
  162. ***************
  163. *** 114,124 ****
  164.       signal(SIGINT, cleanup_handler);
  165.       signal(SIGTERM, cleanup_handler);
  166.   
  167. -     /* Set the output sampling rate to 8000 Hz */
  168. -     pvbuf[0] = AL_OUTPUT_RATE;
  169. -     pvbuf[1] = AL_RATE_8000;
  170. -     ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 2L);
  171.       /* Configure and open an SGI audio port */
  172.       config = ALnewconfig();
  173.       ALsetchannels(config, AL_MONO);
  174. --- 114,119 ----
  175. ***************
  176. *** 129,134 ****
  177. --- 124,135 ----
  178.           perror("ALopenport");
  179.           exit(1);
  180.       }
  181. +     /* Set the output sampling rate to 8000 Hz */
  182. +     /* Do this after ALopenport so we needn't undo it if that fails */
  183. +     pvbuf[0] = AL_OUTPUT_RATE;
  184. +     pvbuf[1] = AL_RATE_8000;
  185. +     ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 2L);
  186.   #else
  187.       /* Write to /dev/audio */
  188.       if ((ofd = open("/dev/audio", O_WRONLY | O_NDELAY)) < 0) {
  189. diff -rcN ../orig/radio.c ./radio.c
  190. *** ../orig/radio.c    Thu Sep 10 08:55:49 1992
  191. --- ./radio.c    Thu Sep 10 08:57:15 1992
  192. ***************
  193. *** 41,46 ****
  194. --- 41,48 ----
  195.      -n           noninterruptable -- by default radio will be interruptable
  196.           by other sound outputting programs, hoping they do not
  197.           take too long.  This option turns off that feature.
  198. +    -t        tee mode: send output to stdout as well as to audio h/w
  199. +    -m mcastgrp    multicast group (SGI only)
  200.   */
  201.   
  202.   #define BCASTCTLPORT      54319
  203. ***************
  204. *** 53,61 ****
  205. --- 55,66 ----
  206.   
  207.   #ifdef sgi
  208.   #define USE_AL
  209. + #define CHECK_X_SERVER
  210. + #define HAVE_MCAST
  211.   #endif
  212.   #ifdef sun
  213.   #define USE_SUN
  214. + #define CHECK_X_SERVER
  215.   #endif
  216.   #ifdef NeXT
  217.   #define USE_NX
  218. ***************
  219. *** 72,77 ****
  220. --- 77,86 ----
  221.   #include <sys/time.h>
  222.   #include <netinet/in.h>
  223.   
  224. + #ifdef HAVE_MCAST
  225. + #include <arpa/inet.h>
  226. + #endif
  227.   #ifdef USE_AL
  228.   #include <audio.h>
  229.   #include "libst.h"
  230. ***************
  231. *** 96,101 ****
  232. --- 105,111 ----
  233.   
  234.   int interruptable = 1;
  235.   int actlfd = -1;
  236. + int afd = -1;
  237.   
  238.   void sigpoll_handler();
  239.   #endif /* USE_SUN */
  240. ***************
  241. *** 106,111 ****
  242. --- 116,126 ----
  243.   SNDSoundStruct *snd[NUM_BUFFER];
  244.   #endif /* USE_NX */
  245.   
  246. + #ifdef CHECK_X_SERVER
  247. + #include <X11/Xlib.h>
  248. + Display *xdisplay = 0;
  249. + #endif
  250.   /* getopt() interface */
  251.   extern int optind;
  252.   extern char * optarg;
  253. ***************
  254. *** 114,123 ****
  255. --- 129,142 ----
  256.   int pausing = 0; /* Flag set when pausing */
  257.   int ofd = -1; /* Output file descriptor */
  258.   int volume = -1; /* -v parameter */
  259. + int pdebug = 0; /* -p parameter */
  260. + char *mcastgrp = 0; /* -m parameter */
  261.   
  262.   /* Forward functions */
  263.   void open_speaker();
  264.   void close_speaker();
  265. + void checkalive();
  266. + void setmcast();
  267.   
  268.   main(argc, argv)
  269.       int argc;
  270. ***************
  271. *** 131,142 ****
  272.       int fromlen;
  273.       int c;
  274.       int filter = 0;
  275.       int nfds;
  276.       fd_set inputset;
  277.       int n;
  278. -     int pdebug = 0;
  279.       char *localname = (char *) NULL;
  280.       char *remotename = (char *) NULL;
  281.   #ifdef USE_AL
  282.       short obuf[BUFFERSIZE];
  283.       int i;
  284. --- 150,163 ----
  285.       int fromlen;
  286.       int c;
  287.       int filter = 0;
  288. +     int tee = 0;
  289.       int nfds;
  290.       fd_set inputset;
  291.       int n;
  292.       char *localname = (char *) NULL;
  293.       char *remotename = (char *) NULL;
  294. +     struct timeval timeout;
  295. +     int packetcount;
  296.   #ifdef USE_AL
  297.       short obuf[BUFFERSIZE];
  298.       int i;
  299. ***************
  300. *** 145,153 ****
  301.       int akt_buf;
  302.   #endif
  303.   
  304. ! /* Always change these two macros together! */
  305. ! #define OPTIONS "c:dfl:np:r:sv:"
  306. ! #define USAGE "usage: %s [-c ctlport] [-d] [-f] [-l localhost] [-n] [-p port]\n\t[-r remotehost] [-s] [-v volume(0-100)]\n"
  307.   
  308.       while ((c = getopt(argc, argv, OPTIONS)) != EOF) {
  309.           switch (c) {
  310. --- 166,189 ----
  311.       int akt_buf;
  312.   #endif
  313.   
  314. ! /* Always change these two macros and the following switch together! */
  315. ! #define OPTIONS "c:dfl:m:np:r:stv:"
  316. ! #define USAGE "usage: %s [options]\n\
  317. ! User options:\n\
  318. ! -p port      : port to listen to (default 54321; 1..99 ==> 54321..54419)\n\
  319. ! -v volume    : volume setting (1-100; default unchanged)\n\
  320. ! Expert options:\n\
  321. ! -f           : filter mode (write data to stdout)\n\
  322. ! -t           : tee mode (write data to stdout as well as to audio device)\n\
  323. ! -n           : not interruptable by other sources (Sun only)\n\
  324. ! -c ctlport   : control port for tuner programs (default 54320)\n\
  325. ! -s           : secure mode: no control port (disallow tuner programs)\n\
  326. ! Guru options:\n\
  327. ! -l localhost : listen to packets to this host only\n\
  328. ! -r remothost : receive packets from that host only\n\
  329. ! -m mcastgrp  : multicast group (SGI only)\n\
  330. ! -d           : debugging mode (writes messages to stderr)\n\
  331. ! "
  332.   
  333.       while ((c = getopt(argc, argv, OPTIONS)) != EOF) {
  334.           switch (c) {
  335. ***************
  336. *** 171,186 ****
  337.           case 'd':
  338.               pdebug = 1;
  339.               break;
  340. ! #ifdef USE_SUN
  341.           case 'n':
  342.               interruptable = 0;
  343.               break;
  344. - #endif /* USE_SUN */
  345.           case 's':
  346.               ctlport = -1;
  347.               break;
  348.           case 'f':
  349.               filter = 1;
  350.               break;
  351.           case 'v':
  352.               volume = atoi(optarg);
  353. --- 207,236 ----
  354.           case 'd':
  355.               pdebug = 1;
  356.               break;
  357. !         case 'm':
  358. ! #ifdef HAVE_MCAST
  359. !             mcastgrp = optarg;
  360. ! #else
  361. !             fprintf(stderr, "(-m not supported here)\n");
  362. ! #endif
  363. !             break;
  364.           case 'n':
  365. + #ifdef USE_SUN
  366.               interruptable = 0;
  367. + #else
  368. +             fprintf(stderr, "(-n not supported here)\n");
  369. + #endif
  370.               break;
  371.           case 's':
  372.               ctlport = -1;
  373.               break;
  374.           case 'f':
  375.               filter = 1;
  376. +             tee = 0;
  377. +             break;
  378. +         case 't':
  379. +             tee = 1;
  380. +             filter = 0;
  381.               break;
  382.           case 'v':
  383.               volume = atoi(optarg);
  384. ***************
  385. *** 188,198 ****
  386.           }
  387.       }
  388.   
  389. !     if (filter) {
  390.           ofd = fileno(stdout);
  391. !     }
  392. !     else {
  393.           open_speaker();
  394.       }
  395.   
  396.       if (ctlport >= 0)
  397. --- 238,261 ----
  398.           }
  399.       }
  400.   
  401. !     /* Meaning of the 'tee' and 'filter' flags:
  402. !        At most one of these can be on.
  403. !        if tee is on: write stdout and "/dev/audio";
  404. !        if filter is on: write stdout only;
  405. !        if both are off: write "/dev/audio" only;
  406. !        where "/dev/audio" stands for whatever audio hardware we have. */
  407. !     if (filter || tee)
  408.           ofd = fileno(stdout);
  409. !     if (!filter) {
  410.           open_speaker();
  411. + #ifdef CHECK_X_SERVER
  412. +         xdisplay = XOpenDisplay((char *)NULL);
  413. +         if (xdisplay == NULL) {
  414. +             fprintf(stderr,
  415. + "radio: warning: no X server -- you must kill radio when you log out!\n");
  416. +         }
  417. + #endif
  418.       }
  419.   
  420.       if (ctlport >= 0)
  421. ***************
  422. *** 202,219 ****
  423.           ctls = -1;
  424.   
  425.       s = opensock("data", localname, receiveport, remotename, SENDPORT, 0);
  426.   
  427.       for (;;) {
  428.           /*
  429.           ** Wait until one of the sockets becomes ready
  430.           */
  431. !         nfds = (s > ctls ? s : ctls) + 1;
  432. !         FD_ZERO(&inputset);
  433. !         FD_SET(s, &inputset);
  434. !         if (ctls >= 0)
  435. !             FD_SET(ctls, &inputset);
  436. !         while (select(nfds, &inputset, 0, 0, 0) < 1) {
  437. !             if(errno != EINTR) {
  438.                   perror("select");
  439.                   exit(1);
  440.               }
  441. --- 265,294 ----
  442.           ctls = -1;
  443.   
  444.       s = opensock("data", localname, receiveport, remotename, SENDPORT, 0);
  445. +     if (mcastgrp)
  446. +         setmcast(s, mcastgrp);
  447. +     packetcount = 0;
  448.   
  449.       for (;;) {
  450.           /*
  451.           ** Wait until one of the sockets becomes ready
  452.           */
  453. !         for (;;) {
  454. !             nfds = (s > ctls ? s : ctls) + 1;
  455. !             FD_ZERO(&inputset);
  456. !             FD_SET(s, &inputset);
  457. !             if (ctls >= 0)
  458. !                 FD_SET(ctls, &inputset);
  459. !             timeout.tv_sec = 30;
  460. !             timeout.tv_usec = 0;
  461. !             n = select(nfds, &inputset, 0, 0, &timeout);
  462. !             if (n > 0)
  463. !                 break;
  464. !             if (n == 0) {
  465. !                 checkalive();
  466. !             }
  467. !             else if (errno != EINTR) {
  468.                   perror("select");
  469.                   exit(1);
  470.               }
  471. ***************
  472. *** 241,247 ****
  473.               else
  474.                   pdebug++;
  475.           }
  476. !         if ( n <= CTLPKTSIZE ) {
  477.               /*
  478.               ** It looks like a control packet. Check it.
  479.               */
  480. --- 316,322 ----
  481.               else
  482.                   pdebug++;
  483.           }
  484. !         if (n <= CTLPKTSIZE) {
  485.               /*
  486.               ** It looks like a control packet. Check it.
  487.               */
  488. ***************
  489. *** 278,283 ****
  490. --- 353,360 ----
  491.                       s = opensock("new data", localname,
  492.                                receiveport, remotename,
  493.                                SENDPORT, 0);
  494. +                     if (mcastgrp)
  495. +                         setmcast(s, mcastgrp);
  496.                       break;
  497.                   case 'i':        /* Info */
  498.                       sprintf(buf, "radio:I:%d:%d",
  499. ***************
  500. *** 320,326 ****
  501.                       obuf[i] = st_ulaw_to_linear(buf[i]);
  502.                   ALwritesamps(aport, obuf, (long)n);
  503.               }
  504. -             else
  505.   #endif /* USE_AL */
  506.   #ifdef USE_NX
  507.               if (!filter) {
  508. --- 397,402 ----
  509. ***************
  510. *** 337,349 ****
  511.                           akt_buf+1, 5, 0, 0, 0);
  512.                   akt_buf = (akt_buf + 1) % NUM_BUFFER;
  513.               }
  514. !             else
  515. ! #endif/* USE_NX */
  516. !             if (write(ofd, buf, n) != n) {
  517. !                 perror("write");
  518. !                 break;
  519.               }
  520.           }
  521.       }
  522.   
  523.       exit(0);
  524. --- 413,438 ----
  525.                           akt_buf+1, 5, 0, 0, 0);
  526.                   akt_buf = (akt_buf + 1) % NUM_BUFFER;
  527.               }
  528. ! #endif /* USE_NX */
  529. ! #ifdef USE_SUN
  530. !             if (!filter) {
  531. !                 if (write(afd, buf, n) != n) {
  532. !                     perror("write afd");
  533. !                     break;
  534. !                 }
  535. !             }
  536. ! #endif /* USE_SUN */
  537. !             if (filter || tee) {
  538. !                 if (write(ofd, buf, n) != n) {
  539. !                     perror("write ofd");
  540. !                     break;
  541. !                 }
  542.               }
  543.           }
  544. +         if (++packetcount > (30*8000 / BUFFERSIZE)) {
  545. +             checkalive();
  546. +             packetcount = 0;
  547. +         }
  548.       }
  549.   
  550.       exit(0);
  551. ***************
  552. *** 416,422 ****
  553.       audio_info_t info;
  554.   
  555.       /* Write to AUDIO_IODEV */
  556. !     if ((ofd = open(AUDIO_IODEV, O_WRONLY)) < 0) {
  557.           perror(AUDIO_IODEV);
  558.           exit(1);
  559.       }
  560. --- 505,511 ----
  561.       audio_info_t info;
  562.   
  563.       /* Write to AUDIO_IODEV */
  564. !     if ((afd = open(AUDIO_IODEV, O_WRONLY)) < 0) {
  565.           perror(AUDIO_IODEV);
  566.           exit(1);
  567.       }
  568. ***************
  569. *** 425,431 ****
  570.       if (volume >= 0) {
  571.           AUDIO_INITINFO(&info);
  572.           info.play.gain = (AUDIO_MAX_GAIN * volume) / 100;
  573. !         if (ioctl(ofd, AUDIO_SETINFO, &info))
  574.               perror("volume setting");
  575.       }
  576.   
  577. --- 514,520 ----
  578.       if (volume >= 0) {
  579.           AUDIO_INITINFO(&info);
  580.           info.play.gain = (AUDIO_MAX_GAIN * volume) / 100;
  581. !         if (ioctl(afd, AUDIO_SETINFO, &info))
  582.               perror("volume setting");
  583.       }
  584.   
  585. ***************
  586. *** 449,458 ****
  587.   
  588.   void close_speaker()
  589.   {
  590. !     (void) ioctl(ofd, I_FLUSH, FLUSHW);
  591. !     close(ofd);
  592.       close(actlfd);
  593. !     ofd = actlfd = -1;
  594.   }
  595.   
  596.   void sigpoll_handler()
  597. --- 538,547 ----
  598.   
  599.   void close_speaker()
  600.   {
  601. !     (void) ioctl(afd, I_FLUSH, FLUSHW);
  602. !     close(afd);
  603.       close(actlfd);
  604. !     afd = actlfd = -1;
  605.   }
  606.   
  607.   void sigpoll_handler()
  608. ***************
  609. *** 463,472 ****
  610.           perror("AUDIO_GETINFO");
  611.       }
  612.       else if (ap.play.waiting) {
  613. !         (void) ioctl(ofd, I_FLUSH, FLUSHW);
  614. !         close(ofd);
  615.           /* The open() call blocks until we can use the device again */
  616. !         if ((ofd = open(AUDIO_IODEV, O_WRONLY)) < 0) {
  617.               perror(AUDIO_IODEV);
  618.               exit(1);
  619.           }
  620. --- 552,561 ----
  621.           perror("AUDIO_GETINFO");
  622.       }
  623.       else if (ap.play.waiting) {
  624. !         (void) ioctl(afd, I_FLUSH, FLUSHW);
  625. !         close(afd);
  626.           /* The open() call blocks until we can use the device again */
  627. !         if ((afd = open(AUDIO_IODEV, O_WRONLY)) < 0) {
  628.               perror(AUDIO_IODEV);
  629.               exit(1);
  630.           }
  631. ***************
  632. *** 488,494 ****
  633.       int err;
  634.   
  635.       /* Alloc NUM_BUFFER Sounds */
  636. !     for( akt_buf = NUM_BUFFER; akt_buf > 0; akt_buf--) {
  637.           if (err = SNDAlloc(&snd[akt_buf-1], BUFFERSIZE,
  638.                      SND_FORMAT_MULAW_8,
  639.                      SND_RATE_CODEC, 1, 4)) {
  640. --- 577,583 ----
  641.       int err;
  642.   
  643.       /* Alloc NUM_BUFFER Sounds */
  644. !     for (akt_buf = NUM_BUFFER; akt_buf > 0; akt_buf--) {
  645.           if (err = SNDAlloc(&snd[akt_buf-1], BUFFERSIZE,
  646.                      SND_FORMAT_MULAW_8,
  647.                      SND_RATE_CODEC, 1, 4)) {
  648. ***************
  649. *** 505,507 ****
  650. --- 594,644 ----
  651.   }
  652.   
  653.   #endif /* USE_NX */
  654. + void checkalive()
  655. + {
  656. + #ifdef CHECK_X_SERVER
  657. +     if (xdisplay) {
  658. +         Window focus;
  659. +         int revert_to;
  660. +         if (pdebug)
  661. +             fprintf(stderr, "polling X server...\n");
  662. +         /* Do a simple X request that needs a server round trip...
  663. +            The error handler will kill us when the server is dead,
  664. +            so that radio dies when the user logs out. */
  665. +         XGetInputFocus(xdisplay, &focus, &revert_to);
  666. +         if (pdebug)
  667. +             fprintf(stderr, "X server OK\n");
  668. +     }
  669. +     else if (pdebug)
  670. +         fprintf(stderr, "checkalive() is a no-op\n");
  671. + #endif /* CHECK_X_SERVER */
  672. + }
  673. + void setmcast(s, group)
  674. +     int s;
  675. +     char *group;
  676. + {
  677. + #ifdef HAVE_MCAST
  678. +     struct in_addr grpaddr;
  679. +     struct in_addr ifaddr;
  680. +     struct ip_mreq mreq;
  681. +     grpaddr.s_addr = inet_addr(group);
  682. +     if (!IN_MULTICAST(grpaddr.s_addr)) {
  683. +         fprintf(stderr, "Bad multicast group: %s\n", group);
  684. +         exit(1);
  685. +     }
  686. +     
  687. +     ifaddr.s_addr = htonl(INADDR_ANY);
  688. +     
  689. +     mreq.imr_multiaddr = grpaddr;
  690. +     mreq.imr_interface = ifaddr;
  691. +     if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
  692. +                &mreq, sizeof(mreq)) < 0) {
  693. +         perror("setsockopt mreq");
  694. +         exit(1);
  695. +     }
  696. + #endif
  697. + }
  698. diff -rcN ../orig/radio.man ./radio.man
  699. *** ../orig/radio.man    Thu Sep 10 08:55:37 1992
  700. --- ./radio.man    Thu Sep 10 08:57:16 1992
  701. ***************
  702. *** 14,22 ****
  703.   .B \-l
  704.   .I addr
  705.   ] [
  706. ! .B \-n
  707.   ]
  708. !       [
  709.   .B \-p
  710.   .I port
  711.   ] [
  712. --- 14,25 ----
  713.   .B \-l
  714.   .I addr
  715.   ] [
  716. ! .B \-m
  717. ! .I mcastgrp
  718.   ]
  719. !  [
  720. ! .B \-n
  721. ! ] [
  722.   .B \-p
  723.   .I port
  724.   ] [
  725. ***************
  726. *** 25,30 ****
  727. --- 28,35 ----
  728.   ] [
  729.   .B \-s
  730.   ] [
  731. + .B \-t
  732. + ] [
  733.   .B \-v
  734.   .I volume
  735.   ]
  736. ***************
  737. *** 73,78 ****
  738. --- 78,94 ----
  739.   .I addr
  740.   (useful for forwarding stations).
  741.   .TP 10
  742. + .BI "\-m " mcastgrp
  743. + Multicast group (SGI only).
  744. + This only makes sense if the same multicast group is passed to the
  745. + .B \-b
  746. + option of
  747. + .IR broadcast (1).
  748. + Using multicasting instead of broadcasting reduces the load on
  749. + machines that aren't listening.
  750. + Unfortunately, the choice of multicast groups is a black art.
  751. + In any case you probably need a multicast group per station.
  752. + .TP 10
  753.   .B \-n
  754.   Noninterruptable mode (Sun Sparc only).
  755.   By default,
  756. ***************
  757. *** 99,104 ****
  758. --- 115,124 ----
  759.   can override the port specified with \fB\-p\fP by sending a control
  760.   message to the control port of your radio program.
  761.   .TP 10
  762. + .B \-t
  763. + Tee mode: write the U-LAW audio data to stdout as well as
  764. + sending it to the audio hardware.
  765. + .TP 10
  766.   .BI "\-v " volume
  767.   Set the initial volume, on a scale from 0 to 100.  (SGI and Sun Sparc only.)
  768.   By default, the volume is left unchanged.
  769. ***************
  770. *** 107,113 ****
  771.   .SH AUTHOR
  772.   Guido van Rossum
  773.   .SH VERSION
  774. ! This manual page documents radio version 2.0, patchlevel 0.
  775.   .SH SEE ALSO
  776.   broadcast(1)
  777.   .SH COPYRIGHT
  778. --- 127,133 ----
  779.   .SH AUTHOR
  780.   Guido van Rossum
  781.   .SH VERSION
  782. ! This manual page documents radio version 2.0, patchlevel 1.
  783.   .SH SEE ALSO
  784.   broadcast(1)
  785.   .SH COPYRIGHT
  786. diff -rcN ../orig/stations.pl ./stations.pl
  787. *** ../orig/stations.pl    Wed Dec 31 18:00:00 1969
  788. --- ./stations.pl    Thu Sep 10 08:57:45 1992
  789. ***************
  790. *** 0 ****
  791. --- 1,28 ----
  792. + #!/usr/bin/perl
  793. + ##
  794. + ## Find radio stations
  795. + ##
  796. + ## (A small subset of the functionality of stations.py for now)
  797. + ##
  798. + ## Written by;  Jeff Beadles  jeff@onion.rain.com
  799. + ##
  800. + # this emulates #! processing on machines that don't support it.
  801. + eval "exec /usr/bin/perl -S $0 $*"
  802. +     if $running_under_some_shell_and_not_perl;
  803. + require 'sys/socket.ph';
  804. + ($name, $aliases, $proto) = getprotobyname('udp');
  805. + $this = pack('S n a4 x8' , &AF_INET, 54317, "\0\0\0\0");
  806. + socket(S, &AF_INET, &SOCK_DGRAM, $proto)  || die "socket: $!";
  807. + bind(S, $this)                            || die "bind:   $!";
  808. + while (1) {
  809. +     recv(S, $buf, 1024, 0) || die "recv:  $!\n";
  810. +     chop($buf);
  811. +     ($t_radio,$t_s,$t_name,$t_port,$t_xmit,$t_log,$t_age) = split(/:/,$buf,7);
  812. +     print "Bogus message '$buf'\n" if ($t_radio ne "radio");
  813. +     print "Receiving station '$t_name' on port $t_port\n";
  814. + }
  815. exit 0 # Just in case...
  816.