home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume32 / radio2.0 / patch01 next >
Text File  |  1992-09-11  |  21KB  |  835 lines

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