home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / sun / volume3 / netfone next >
Text File  |  1991-10-25  |  38KB  |  1,356 lines

  1. Path: uunet!seismo!dimacs.rutgers.edu!aramis.rutgers.edu!athos.rutgers.edu!mcgrew
  2. From: mcgrew@athos.rutgers.edu (Charles Mcgrew)
  3. Newsgroups: comp.sources.sun
  4. Subject: v03i008:  netfone - speak over the network via sparcstations
  5. Message-ID: <Oct.25.11.58.35.1991.27806@athos.rutgers.edu>
  6. Date: 25 Oct 91 15:58:37 GMT
  7. Organization: Rutgers Univ., New Brunswick, N.J.
  8. Lines: 1345
  9. Approved: mcgrew@aramis.rutgers.edu
  10.  
  11. Submitted-by: John Walker <autodesk!throop!kelvin@uunet.uu.net>
  12. Posting-number: Volume 3, Issue 8
  13. Archive-name: netfone
  14.  
  15.  
  16. Chatting away over the network, courtesy of SPARCStations and your Ethernet
  17. or handy-dandy "via satellite" leased line....
  18.  
  19.                                NetFone
  20.                 Voice Communication Over Data Networks
  21.  
  22.                             by John Walker
  23.                  Revision 2  --  12th September 1991
  24.  
  25. The  phone  company never gives you a break!  You finally spring for a
  26. leased line so you can be right on the network  with  everybody  else,
  27. and you *still* have to pay every time you want to chat with somebody,
  28. even though you're both sitting in front of SPARCStations with digital
  29. audio capability, linked with a high-bandwidth network.
  30.  
  31. NetFone  uses  the  workstation  audio  chip  and  network  to   allow
  32. bidirectional  conversations  right  over  the  network.  Workstations
  33. linked by Ethernet can  generally  communicate  with  excellent  audio
  34. quality  and response.  Those linked by 56 Kb lines can also talk over
  35. the network, but with lower fidelity compressed audio that fits within
  36. the capacity of the data link.
  37.  
  38. Complete instructions for building, installing, and using NetFone  are
  39. given  in the manual page, netfone.1.  You can view the manual page on
  40. your screen with the command:
  41.  
  42.     make manpage
  43.  
  44. Building NetFone requires the audio library, "libaudio.a", supplied by
  45. Sun  in  SunOS 4.1.1 in /usr/demo/SOUND and the include files found in
  46. /usr/demo/SOUND/multimedia.  These  files  will  be  present  on  your
  47. workstation only if the "Demos" installation option was selected.  The
  48. multimedia support files from Sun appear to be in  a  rapid  state  of
  49. flux  and  you may need to change the directory names from which these
  50. files are accessed in the Makefile and/or adapt the source programs to
  51. accommodate changes made by Sun in subsequent versions of SunOS.
  52.  
  53. This program is in the public domain: "Do what thou wilt shall be  the
  54. whole  of  the  law".   I'd  appreciate receiving any bug fixes and/or
  55. enhancements,  which  I'll  incorporate  in  future  versions  of  the
  56. program.   Please leave the original attribution information intact so
  57. that credit and blame may be properly apportioned.
  58.  
  59. AUTHOR
  60.             John Walker
  61.             Autodesk SA
  62.             Avenue des Champs-Montants 14b
  63.             CH-2074 MARIN
  64.             Suisse/Schweiz/Svizzera/Svizra/Switzerland
  65.             Usenet: kelvin@Autodesk.com
  66.             Fax:    038/33 88 15
  67.             Voice:  038/33 76 33
  68.  
  69. ----------------------------- Cut here ----------------------- netfone.shar
  70. #! /bin/sh
  71. # This is a shell archive, meaning:
  72. # 1. Remove everything above the #! /bin/sh line.
  73. # 2. Save the resulting text in a file.
  74. # 3. Execute the file with /bin/sh (not csh) to create the files:
  75. #    README
  76. #    Makefile
  77. #    mike.c
  78. #    netfone.1
  79. #    soundbyte.c
  80. #    speaker.c
  81. # This archive created: Sat Sep 14 00:59:56 1991
  82. export PATH; PATH=/bin:$PATH
  83. echo shar: extracting "'README'" '(2296 characters)'
  84. if test -f 'README'
  85. then
  86.        echo shar: will not over-write existing file "'README'"
  87. else
  88. cat << \SHAR_EOF > 'README'
  89.  
  90.                                NetFone
  91.                 Voice Communication Over Data Networks
  92.  
  93.                             by John Walker
  94.                  Revision 2  --  12th September 1991
  95.  
  96. The  phone  company never gives you a break!  You finally spring for a
  97. leased line so you can be right on the network  with  everybody  else,
  98. and you *still* have to pay every time you want to chat with somebody,
  99. even though you're both sitting in front of SPARCStations with digital
  100. audio capability, linked with a high-bandwidth network.
  101.  
  102. NetFone  uses  the  workstation  audio  chip  and  network  to   allow
  103. bidirectional  conversations  right  over  the  network.  Workstations
  104. linked by Ethernet can  generally  communicate  with  excellent  audio
  105. quality  and response.  Those linked by 56 Kb lines can also talk over
  106. the network, but with lower fidelity compressed audio that fits within
  107. the capacity of the data link.
  108.  
  109. Complete instructions for building, installing, and using NetFone  are
  110. given  in the manual page, netfone.1.  You can view the manual page on
  111. your screen with the command:
  112.  
  113.     make manpage
  114.  
  115. Building NetFone requires the audio library, "libaudio.a", supplied by
  116. Sun  in  SunOS 4.1.1 in /usr/demo/SOUND and the include files found in
  117. /usr/demo/SOUND/multimedia.  These  files  will  be  present  on  your
  118. workstation only if the "Demos" installation option was selected.  The
  119. multimedia support files from Sun appear to be in  a  rapid  state  of
  120. flux  and  you may need to change the directory names from which these
  121. files are accessed in the Makefile and/or adapt the source programs to
  122. accommodate changes made by Sun in subsequent versions of SunOS.
  123.  
  124. This program is in the public domain: "Do what thou wilt shall be  the
  125. whole  of  the  law".   I'd  appreciate receiving any bug fixes and/or
  126. enhancements,  which  I'll  incorporate  in  future  versions  of  the
  127. program.   Please leave the original attribution information intact so
  128. that credit and blame may be properly apportioned.
  129.  
  130. AUTHOR
  131.             John Walker
  132.             Autodesk SA
  133.             Avenue des Champs-Montants 14b
  134.             CH-2074 MARIN
  135.             Suisse/Schweiz/Svizzera/Svizra/Switzerland
  136.             Usenet: kelvin@Autodesk.com
  137.             Fax:    038/33 88 15
  138.             Voice:  038/33 76 33
  139. SHAR_EOF
  140. fi # end of overwriting check
  141. echo shar: extracting "'Makefile'" '(1757 characters)'
  142. if test -f 'Makefile'
  143. then
  144.        echo shar: will not over-write existing file "'Makefile'"
  145. else
  146. cat << \SHAR_EOF > 'Makefile'
  147.  
  148. #    NetFone: Make file
  149.  
  150. #   Directory where the Sun sound utilities, including libaudio.a
  151. #   are installed.
  152. SOUND = /usr/demo/SOUND
  153.  
  154. #   Directory where the #include files for the Sun sound utilities
  155. #   are installed.
  156. MULTIMEDIA = $(SOUND)/multimedia
  157.  
  158. #   Internet socket port used by mike and speaker.  If you change this,
  159. #   you will not be able to exchange sound with users who've built
  160. #   NetFone with different values.
  161. INTERNET_PORT = 2074
  162.  
  163. #   Program name (shar will be $(PROG).shar)
  164. PROG =    netfone
  165.  
  166. #   Source files distributed in the .shar archive.
  167. SFILES = README Makefile mike.c netfone.1 soundbyte.c speaker.c
  168.  
  169. #   Special modes, if any, for C compilations.
  170. MODES = -O
  171.  
  172. CARGS = -I$(MULTIMEDIA) -DInternet_Port=$(INTERNET_PORT)
  173.  
  174. CFLAGS = $(MODES) $(CARGS)
  175.  
  176. all:    speaker mike
  177.  
  178. SPKROBJS = speaker.o soundbyte.o
  179.  
  180. speaker: $(SPKROBJS)
  181.     cc $(SPKROBJS) $(SOUND)/libaudio.a -lm -o speaker
  182.  
  183. MIKEOBJS = mike.o soundbyte.o
  184.  
  185. mike:    $(MIKEOBJS)
  186.     cc $(MIKEOBJS) -lm -o mike
  187.  
  188. speaker.o: speaker.c
  189.  
  190. mike.o: mike.c
  191.  
  192. manpage:
  193.     nroff -man netfone.1 | more
  194.  
  195. printman:
  196.     ptroff netfone.1 -man
  197.  
  198. shar:
  199.     shar -b -v $(SFILES) >$(PROG).shar
  200.  
  201. #   Note: the following LINT line feeds both main programs and the the
  202. #      subroutine file they share to LINT so  that  it  can    detect
  203. #      unused functions in the library, soundbyte.c This results in
  204. #      a harmless warning about the duplicate definition of main().
  205. #      NetFone  is  *not*  lint-free.   I  cannot  bring  myself to
  206. #      butcher the source to the extent that would be required.
  207. lint:
  208.     lint $(CARGS) mike.c speaker.c soundbyte.c
  209.  
  210. spell:
  211.     spell -b netfone.1 | fmt
  212.     spell -b README    | fmt
  213.  
  214. clean:
  215.     rm -f core *.out *.o *.bak *.shar speaker mike
  216.  
  217. backup:
  218.     mt -f $(TAPE) rew
  219.     tar cfbv $(TAPE) 126 *
  220.     mt -f $(TAPE) rew
  221. SHAR_EOF
  222. fi # end of overwriting check
  223. echo shar: extracting "'mike.c'" '(9498 characters)'
  224. if test -f 'mike.c'
  225. then
  226.        echo shar: will not over-write existing file "'mike.c'"
  227. else
  228. cat << \SHAR_EOF > 'mike.c'
  229. /*
  230.  
  231.     NetFone: Network sound transmission program
  232.  
  233.     Designed and implemented in July of 1991 by John Walker
  234.  
  235. */
  236.  
  237. #include <stdio.h>
  238. #include <fcntl.h>
  239. #include <sys/types.h>
  240. #include <sys/socket.h>
  241. #include <netinet/in.h>
  242. #include <netdb.h>
  243.  
  244. struct soundbuf {
  245.     int compression;
  246.     char sendinghost[16];
  247.     struct {
  248.         int buffer_len;
  249.         char buffer_val[8000];
  250.     } buffer;
  251. };
  252. typedef struct soundbuf soundbuf;
  253.  
  254. #define TRUE    1
  255. #define FALSE    0
  256.  
  257. static int sock;              /* Communication socket */
  258.  
  259. #define V    (void)
  260.  
  261. /*  Destination host descriptor.  */
  262.  
  263. struct destination {
  264.     struct destination *dnext;
  265.     char *server;
  266.     struct sockaddr_in name;
  267. };
  268.  
  269. static struct destination *dests = NULL, *dtail;
  270. static int compressing = FALSE;       /* Compress sound buffers */
  271. static int squelch = 0;           /* Squelch level if > 0 */
  272. static int ring = FALSE;          /* Force speaker & level on next pkt ? */
  273. static int agc = TRUE;              /* Automatic gain control active ? */
  274. static int rgain = 33;              /* Current recording gain level */
  275. static int debugging = FALSE;          /* Debugging enabled here and there ? */
  276. static char hostname[20];          /* Host name to send with packets */
  277. static int loopback = FALSE;          /* Remote loopback mode */
  278.  
  279. /*  ADDEST  --    Add destination host to host list.  */
  280.  
  281. static int addest(host)
  282.   char *host;
  283. {
  284.     struct destination *d;
  285.     struct hostent *hp, *gethostbyname();
  286.  
  287.     hp = gethostbyname(host);
  288.     if (hp == 0) {
  289.         fprintf(stderr, "%s: unknown host\n", host);
  290.     return FALSE;
  291.     }
  292.  
  293.     d = (struct destination *) malloc(sizeof(struct destination));
  294.     d->dnext = NULL;
  295.     d->server = host;
  296.     bcopy((char *) hp->h_addr, (char *) &(d->name.sin_addr), hp->h_length);
  297.     d->name.sin_family = AF_INET;
  298.     d->name.sin_port = htons(Internet_Port);
  299.     if (dests == NULL) {
  300.     dests = d;
  301.     } else {
  302.     dtail->dnext = d;
  303.     }
  304.     dtail = d;
  305.     return TRUE;
  306. }
  307.  
  308. /*  SENDMSG  --  Send a message to all active destinations.  */
  309.  
  310. static int sendmsg(sb)
  311.   struct soundbuf *sb;
  312. {
  313.     struct destination *d;
  314.  
  315.     for (d = dests; d != NULL; d = d->dnext) {
  316.     if (sendto(sock, sb, (sizeof(struct soundbuf)) - (8000 - sb->buffer.buffer_len),
  317.     0, (struct sockaddr *) &(d->name), sizeof d->name) < 0) {
  318.         perror("sending datagram message");
  319.     return FALSE;
  320.     }
  321.     }
  322.     return TRUE;
  323. }
  324.  
  325. /*  SENDFILE  --  Send a file or, if the file name is NULL or a
  326.           single period, send real-time sound input. */
  327.  
  328. static int sendfile(f)
  329.   char *f;
  330.     soundbuf netbuf;
  331. #define buf netbuf.buffer.buffer_val
  332.     int nread;
  333.     FILE *afile = NULL;
  334.  
  335.     strcpy(netbuf.sendinghost, hostname);
  336.     if (f != NULL && (strcmp(f, ".") != 0)) {
  337.         afile = fopen(f, "r");
  338.     if (afile == NULL) {
  339.             fprintf(stderr, "Unable to open sound file %s.\n", f);
  340.         return 2;
  341.     }
  342.     }
  343.  
  344.     /* Send a file */
  345.  
  346.     if (afile) {
  347.     while ((nread = fread(buf, 1, sizeof buf, afile)) > 0) {
  348.         netbuf.compression = FALSE | (ring ? 4 : 0);
  349.         ring = FALSE;
  350.         netbuf.compression |= debugging ? 2 : 0;
  351.         netbuf.compression |= loopback ? 16 : 0;
  352.         if (compressing) {
  353.         int i;
  354.  
  355.         nread /= 2;
  356.         for (i = 1; i < nread; i++) {
  357.             buf[i] = buf[i * 2];
  358.         }
  359.         netbuf.compression |= 1;
  360.         }
  361.         netbuf.buffer.buffer_len = nread;
  362.         if (!sendmsg(&netbuf)) {
  363.         fclose(afile);
  364.         return 1;
  365.         }
  366.         /* Horrible kludge.  Fake flow control by sleeping for about
  367.            long enough for the buffer to play. */
  368.  
  369.         usleep(950 * ((nread * (compressing ? 2 : 1)) / 8L));
  370.     }
  371.  
  372.     if (debugging) {
  373.             fprintf(stderr, "Sent sound file %s.\n", f);
  374.     }
  375.     fclose(afile);
  376.     } else {
  377.  
  378.     /* Send real-time sound. */
  379.  
  380.     if (!soundinit(O_RDONLY /* | O_NDELAY */ )) {
  381.             fprintf(stderr, "Unable to initialise audio.\n");
  382.         return 2;
  383.     }
  384.     if (agc) {
  385.         soundrecgain(rgain);      /* Set initial record level */
  386.     }
  387.     if (soundrecord()) {
  388.         while (TRUE) {
  389.         int soundel = soundgrab(buf, sizeof buf);
  390.         unsigned char *bs = (unsigned char *) buf;
  391.  
  392.         if (soundel > 0) {
  393.             register unsigned char *start = bs;
  394.             register int j;
  395.             int squelched = (squelch > 0);
  396.  
  397.             /* If entire buffer is less than squelch, ditch it. */
  398.  
  399.             if (squelch > 0) {
  400.             for (j = 0; j < soundel; j++) {
  401.                 if (((*start++ & 0x7F) ^ 0x7F) > squelch) {
  402.                 squelched = FALSE;
  403.                 break;
  404.                 }
  405.             }
  406.             }
  407.  
  408.             if (squelched) {
  409.             if (debugging) {
  410.                             printf("Entire buffer squelched.\n");
  411.             }
  412.             } else {
  413.             netbuf.compression = FALSE | (ring ? 4 : 0);
  414.             netbuf.compression |= debugging ? 2 : 0;
  415.             netbuf.compression |= loopback ? 16 : 0;
  416.  
  417.             /* If automatic gain control is enabled,
  418.                ride the gain pot to fill the dynamic range
  419.                optimally. */
  420.  
  421.             if (agc) {
  422.                 register unsigned char *start = bs;
  423.                 register int j;
  424.                 long msamp = 0;
  425.  
  426.                 for (j = 0; j < soundel; j++) {
  427.                 int tsamp = ((*start++ & 0x7F) ^ 0x7F);
  428.  
  429.                 msamp += tsamp;
  430.                 }
  431.                 msamp /= soundel;
  432.                 if (msamp < 0x30) {
  433.                 if (rgain < 100) {
  434.                     soundrecgain(++rgain);
  435.                 }
  436.                 } else if (msamp > 0x35) {
  437.                 if (rgain > 1) {
  438.                     soundrecgain(--rgain);
  439.                 }
  440.                 }
  441.             }
  442.  
  443.             ring = FALSE;
  444.             if (compressing) {
  445.                 int i;
  446.  
  447.                 soundel /= 2;
  448.                 for (i = 1; i < soundel; i++) {
  449.                 buf[i] = buf[i * 2];
  450.                 }
  451.                 netbuf.compression |= 1;
  452.             }
  453.             netbuf.buffer.buffer_len = soundel;
  454.             if (!sendmsg(&netbuf)) {
  455.                 return 1;
  456.             }
  457.             }
  458.         } else {
  459.             usleep(100000L);  /* Wait for some sound to arrive */
  460.         }
  461.         }
  462.     } else {
  463.             fprintf(stderr, "Unable to start recording.\n");
  464.         return 2;
  465.     }
  466.     }
  467.     return 0;
  468. }
  469.  
  470. /*  USAGE  --  Print how-to-call information.  */
  471.  
  472. static void usage()
  473. {
  474.     V fprintf(stderr, "mike  --  Sound transmission tool.\n");
  475.     V fprintf(stderr, "\n");
  476.     V fprintf(stderr, "Usage: mike hostname <options> [ file1 / . ]...\n");
  477.     V fprintf(stderr, "Options: (* indicates defaults)\n");
  478.     V fprintf(stderr, "           -C         Compress subsequent sound\n");
  479.     V fprintf(stderr, "           -D         Enable debug output\n");
  480.     V fprintf(stderr, "     *     -G         Automatic gain control\n");
  481.     V fprintf(stderr, "           -L         Remote loopback\n");
  482.     V fprintf(stderr, "           -M         Manual record gain control\n");
  483.     V fprintf(stderr, "     *     -N         Do not compress subsequent sound\n");
  484.     V fprintf(stderr, "           -Phostname Party line, add host to list\n");
  485.     V fprintf(stderr, "     *     -Q         Disable debug output\n");
  486.     V fprintf(stderr, "           -R         Ring--force volume, output to speaker\n");
  487.     V fprintf(stderr, "           -Sn        Squelch at level n (0-255)\n");
  488.     V fprintf(stderr, "           -U         Print this message\n");
  489.     V fprintf(stderr, "\n");
  490.     V fprintf(stderr, "par John Walker\n");
  491.     V fprintf(stderr, "    Autodesk SA Neuch\342tel\n");
  492.     V fprintf(stderr, "    Avenue des Champs-Montants 14b\n");
  493.     V fprintf(stderr, "    CH-2074 MARIN\n");
  494.     V fprintf(stderr, "    Suisse/Schweiz/Svizzera/Svizra/Switzerland\n");
  495.     V fprintf(stderr, "    Usenet: kelvin@Autodesk.com\n");
  496.     V fprintf(stderr, "    Fax:    038/33 88 15\n");
  497.     V fprintf(stderr, "    Voice:  038/33 76 33\n");
  498. }
  499.  
  500. /*  Main program.  */
  501.  
  502. main(argc, argv)
  503.   int argc;
  504.   char *argv[];
  505. {
  506.     int i, sentfile = 0;
  507.  
  508.     gethostname(hostname, sizeof hostname);
  509.  
  510.     /* Create the socket used to send data. */
  511.  
  512.     sock = socket(AF_INET, SOCK_DGRAM, 0);
  513.     if (sock < 0) {
  514.         perror("opening datagram socket");
  515.     return 1;
  516.     }
  517.  
  518.     /*    Process command line options.  */
  519.  
  520.     for (i = 1; i < argc; i++) {
  521.     char *op, opt;
  522.  
  523.     op = argv[i];
  524.         if (*op == '-') {
  525.         opt = *(++op);
  526.         if (islower(opt))
  527.         opt = toupper(opt);
  528.         switch (opt) {
  529.  
  530.                 case 'C':             /* -C  -- Compress sound samples */
  531.             compressing = TRUE;
  532.             break;
  533.  
  534.                 case 'D':             /* -D  --  Enable debug output  */
  535.             debugging = TRUE;
  536.             break;
  537.  
  538.                 case 'G':             /* -G  --  Automatic gain control */
  539.             agc = TRUE;
  540.             break;
  541.  
  542.                 case 'L':             /* -L  --  Remote loopback */
  543.             loopback = TRUE;
  544.             break;
  545.  
  546.                 case 'M':             /* -M  --  Manual record gain control */
  547.             agc = FALSE;
  548.             break;
  549.  
  550.                 case 'N':             /* -N  --  Do not compress sound samples */
  551.             compressing = FALSE;
  552.             break;
  553.  
  554.                 case 'P':             /* -Phost  --  Copy output to host  */
  555.             if (!addest(op + 1)) {
  556.             return 1;
  557.             }
  558.             break;
  559.  
  560.                 case 'Q':             /* -Q  --  Disable debug output  */
  561.             debugging = FALSE;
  562.             break;
  563.  
  564.                 case 'R':             /* -R  --  Ring: divert output to speaker */
  565.             ring = TRUE;
  566.             break;
  567.  
  568.                 case 'S':             /* -Sn  --  Squelch at level n */
  569.             if (strlen(op + 1) == 0) {
  570.             squelch = 50; /* Default squelch */
  571.             } else {
  572.             squelch = atoi(op + 1);
  573.             }
  574.             break;
  575.  
  576.                 case 'U':             /* -U  --  Print usage information */
  577.                 case '?':             /* -?  --  Print usage information */
  578.             usage();
  579.             return 0;
  580.         }
  581.     } else {
  582.         if (dests == NULL) {
  583.         if (!addest(op)) {
  584.             return 1;
  585.         }
  586.         } else {
  587.         int ok = sendfile(op);
  588.         if (ok != 0)
  589.             return ok;
  590.         sentfile++;
  591.         }
  592.     }
  593.     }
  594.  
  595.     if (dests == NULL) {
  596.     usage();
  597.     } else {
  598.     if (sentfile == 0) {
  599.         return sendfile(NULL);
  600.     }
  601.     }
  602.  
  603.     return 0;
  604. }
  605. SHAR_EOF
  606. fi # end of overwriting check
  607. echo shar: extracting "'netfone.1'" '(10566 characters)'
  608. if test -f 'netfone.1'
  609. then
  610.        echo shar: will not over-write existing file "'netfone.1'"
  611. else
  612. cat << \SHAR_EOF > 'netfone.1'
  613. '\" t
  614. .TH NETFONE 1 "12 SEP 1991"
  615. .UC 4
  616. .SH NAME
  617. mike, speaker \- Voice communication over a network
  618. .SH SYNOPSIS
  619. .B speaker
  620. .LP
  621. .B mike
  622. .I hostname
  623. [
  624. .B \-cdglmnqru
  625. ] [
  626. .BI \-p hostname
  627. ] [
  628. .BI \-s level
  629. ] [
  630. .I soundfile ...
  631. ]
  632. .SH DESCRIPTION
  633. .B netfone
  634. is an application that allows users with Sun SPARCStations connected
  635. by a network to converse, using the audio input and output facilities
  636. of the SPARCStation to digitise and later reconstruct the sound and
  637. the network to relay sound packets.  Audio files recorded with
  638. .BR record (6)
  639. or
  640. .BR soundtool (6)
  641. may be transmitted and played on remote workstations as well.
  642. Optional compression is provided, allowing conversations
  643. (albeit with lower quality audio) to take place over 56 Kb links as
  644. well as local Ethernet connections.
  645.  
  646. .B netfone 
  647. consists of two programs,
  648. .B mike
  649. and
  650. .BR speaker .
  651. The
  652. .B speaker
  653. program must be running on a workstation to allow it to receive
  654. sound sent with the
  655. .B mike
  656. program.  You can execute
  657. .B speaker
  658. in the background or install it as a standard daemon by
  659. adding the line:
  660.  
  661. .B "    speaker &"
  662.  
  663. to the end of your
  664. .B /etc/rc.local
  665. file.
  666.  
  667. You can send audio to workstation
  668. .I hostname
  669. running the
  670. .B speaker
  671. program with:
  672.  
  673. .BI "    mike " hostname
  674.  
  675. which sends real-time audio from the microphone jack, or:
  676.  
  677. .B "    mike "
  678. .I hostname
  679. .I soundfile
  680.  
  681. where
  682. .I soundfile
  683. is one or more files of prerecorded sound created with
  684. .BR soundtool (6)
  685. or
  686. .BR record (6).
  687. If
  688. .I soundfile
  689. is a single period, real-time audio from the microphone jack is
  690. selected.  This permits you to send one or more sound files, then
  691. switch to live audio all in a single command.
  692.  
  693. .BR mike " and " speaker
  694. are normally used in conjunction with the Sun program
  695. .BR gaintool (6)
  696. which allows interactive setting of the audio record and playback
  697. levels with a SunView tool.
  698. .B gaintool
  699. is supplied by Sun as part of the
  700. .I Demos
  701. installation option.
  702.  
  703. It's perfectly valid to send audio to a copy of
  704. .B speaker
  705. running on the same workstation as
  706. .BR mike .
  707. In fact, it's a very handy way to experiment.
  708.  
  709. .SH "BUILDING AND INSTALLING"
  710.  
  711. To install
  712. .B netfone
  713. on your Sun workstation, extract it from the
  714. archive in which it was delivered into a directory of its own.
  715. With this directory as the current directory, say:
  716.  
  717. .B "    make"
  718.  
  719. to build the programs.  You may wish to install the
  720. .B mike
  721. and
  722. .B speaker
  723. programs in a library directory so they will be generally accessible.
  724. This manual page, which may be displayed on the terminal with:
  725.  
  726. .B "    make manpage"
  727.  
  728. should be copied into your local manual page directory.
  729.  
  730. .SH OPTIONS
  731. .B speaker
  732. has no options and is totally non-interactive.  The following
  733. options may be specified on
  734. .BR mike .
  735. Options are processed left to right and sound files are sent with
  736. the modes specified by options to their left on the command line.
  737. .TP 10
  738. .B \-c
  739. Compress sound.
  740. .B mike
  741. normally transmits sound at the standard rate of
  742. 8000 samples per second.  When compression is enabled, this
  743. rate is halved to 4000 samples per second which reduces the bandwidth
  744. to that which can be accommodated by a 56 Kb line (which
  745. has a capacity of a little more than 6000 bytes per second).  The
  746. elided samples are reconstructed at the receiving end by
  747. .BR speaker .
  748. Compression reduces the audio quality, but the result is generally
  749. intelligible and certainly much better than the random pauses
  750. and lost words that occur if you try to send full bandwidth audio
  751. over a 56 Kb line.  Both sound files and real time audio may be
  752. compressed.  Compression of real time audio works best if the
  753. input audio signal is subjected to a 2 Khz low-pass filter; if
  754. higher frequency components are present they will cause aliasing
  755. in the sampling process, which can do strange things to the sound.
  756. Using a ``communications microphone'' rather than a full bandwidth
  757. microphone helps if you don't have access to a signal processor or
  758. equaliser to limit the bandwidth.
  759. .TP
  760. .B \-d
  761. Enables debug output from
  762. .I both
  763. the local copy of
  764. .B mike
  765. and the receiving copy of
  766. .BR speaker .
  767. .TP
  768. .B \-g
  769. Automatic gain control is enabled for real-time audio. The
  770. recording gain is dynamically adjusted to compensate for the
  771. amplitude of the sound received, using the maximum dynamic
  772. range without clipping.  If this switch is specified, the
  773. record gain cannot be manually set with
  774. .BR gaintool .
  775. Automatic gain control is on by default.
  776. .TP
  777. .B \-l
  778. Remote loopback is enabled.  Each packet received by
  779. .B speaker
  780. will be immediately transmitted back to a copy of
  781. .B speaker
  782. running on the originating machine.  You can use loopback to
  783. evaluate the quality of transmission over various kinds of
  784. communication links without the need to have a person at the
  785. other end.
  786. .TP
  787. .B \-m
  788. Manual gain control.  Allows you to manually set the recording level
  789. with
  790. .BR gaintool .
  791. .TP
  792. .B \-n
  793. Disables compression of sound.  This is the default; the switch
  794. permits canceling the effect of a previous
  795. .B \-c
  796. switch when sending multiple sound files with one
  797. .B mike
  798. command.
  799. .TP
  800. .BI \-p hostname
  801. Adds
  802. .I hostname
  803. to the list of hosts to which the sound is sent.  The first
  804. host is specified explicitly on the
  805. .B mike
  806. command line.  You may name additional hosts, all of which must be
  807. running
  808. .BR speaker ,
  809. to create a ``party line''.  The same sound will be sent to each
  810. host you name.  If you're on a 56 Kb line instead of an Ethernet,
  811. transmitting to multiple hosts will result in unacceptable delays
  812. and lost words; there simply isn't enough bandwidth to send duplicate
  813. packets.
  814. .TP
  815. .B \-q
  816. Quiet--disables debug output.  This is the default; the switch can be
  817. used to cancel the effect of a prior
  818. .B \-d
  819. switch.
  820. .TP
  821. .B \-r
  822. Ring.  This is used to get the attention of a user when you're
  823. trying to establish a connection.  The output, which the user may
  824. have diverted to the headphone jack, is forced to go to the
  825. workstation speaker and the playback volume is set to mid-level
  826. to guarantee audibility.  The receiving user may subsequently
  827. switch the output back to the headphones, if desired, with
  828. .BR gaintool .
  829. .TP
  830. .BI \-s level
  831. Squelch output whenever input volume is below the specified
  832. .IR level .
  833. The
  834. .I level
  835. specification is an arbitrary number from 1 to 255 with larger
  836. numbers denoting louder sound.  The default squelch value, if none
  837. is given on the
  838. .B \-s
  839. switch, is 50 which works reasonably well unless your computer room is
  840. very noisy (in which case you might want to avail yourself of a
  841. headset with a directional boom microphone).  Squelch interacts poorly
  842. with automatic gain control; if you wish to use squelch, specify the
  843. .B \-m
  844. switch and set the gain with
  845. .B gaintool
  846. for the best results.  Squelch is off by default, equivalent to a
  847. specification of
  848. .BR \-s0 .
  849. Enabling squelch allows multiple people to send sound to the same
  850. destination(s) and, as long as only one speaks at a time, for the
  851. result to be intelligible.  In order for this to work the recording
  852. and squelch levels must be set so that sound is sent only when you're
  853. talking.  Enabling debugging output with the
  854. .B \-d
  855. switch may help to determine the best settings.
  856. .TP
  857. .B \-u
  858. Prints how-to-call information.
  859. .SH FILES
  860. Audio is read and written from the
  861. .B /dev/audio
  862. device file.  The device will be busy for input whenever
  863. .B mike
  864. is running.  The
  865. .B speaker
  866. program acquires the audio device upon receiving sound, but automatically
  867. releases
  868. .B /dev/audio
  869. for output after 20 seconds elapse without any sound having been
  870. received.
  871. .SH BUGS
  872. .PP
  873. If sound from multiple sources arrives simultaneously at one machine,
  874. .B speaker
  875. interleaves the audio packet-by-packet.  This usually results in
  876. unintelligible gibberish, although it's normally adequate to allow
  877. ``butting into'' a conversation.  It might be possible to have
  878. .B speaker
  879. mix the sound into one output stream, but I haven't experimented
  880. with this approach.
  881. .PP
  882. No warning is given if the destination workstation is not running
  883. .BR speaker ;
  884. sound just disappears.
  885. .PP
  886. In order to deliver acceptable (or at least tolerable) performance across
  887. international satellite links,
  888. .BR mike " and " speaker
  889. use ``Internet datagram'' socket protocol which is essentially a
  890. ``fire and forget'' mechanism; neither flow control nor acknowledgement
  891. are provided.  Since sound most be delivered at the correct time in order
  892. to be intelligible, for real-time transmission there's little one can
  893. do anyway if data are lost.  Consequently, bogged down lines, transmission
  894. errors, etc., simply degrade or destroy the quality of the audio without
  895. providing explicit warnings at either end that anything's amiss.
  896. In addition, the lack of an end-to-end handshake deprives
  897. .B speaker
  898. of backpressure information to control the rate at which it dispatches
  899. packets when transmitting a sound file.  I fake flow control by calculating
  900. the time it will take to play each packet and causing
  901. .B speaker
  902. to
  903. .B usleep(\|) 
  904. that number of microseconds after sending it.  This is, of course,
  905. utterly beneath contempt, but it actually works quite nicely
  906. (at least as long as your machine isn't busy).  If you're motivated to
  907. replace all this datagram stuff with nice, clean RPC calls, don't bother.
  908. That's how I built the initial version of
  909. .BR netfone ,
  910. and although it ran OK on an Ethernet, it was a disaster on 56 Kb lines.
  911. .PP
  912. Acceptable performance over a 56 Kb line requires the line to be close
  913. to idle.  If file transfers or other bulk traffic are underway, you'll
  914. probably be disappointed.
  915. .PP
  916. SunOS 4.1 or above is required to build and use these programs.  As of
  917. this writing, Sun's multimedia support is in a state of rapid flux.
  918. You should expect changes from release to release which may require
  919. modifications to how these programs are built or within the programs
  920. themselves.  This version has been tested on SunOS 4.1.1.
  921. .PP
  922. .BR mike " and " speaker
  923. communicate using Internet port number 2074.  It is
  924. conceivable, although unlikely, that this might conflict with some other
  925. locally-developed network server.  You can change the port number by
  926. editing the
  927. .B Makefile
  928. to change the definition of ``INTERNET_PORT'' and rebuilding, but then your
  929. versions of
  930. .BR mike " and " speaker
  931. won't communicate with others that use the standard port number.
  932.  
  933. .ne 2
  934. .SH "SEE ALSO"
  935. .PD
  936. .BR audio (4),
  937. .BR gaintool (6),
  938. .BR rc (8),
  939. .BR record (6),
  940. .BR soundtool (6),
  941. .BR talk (1),
  942. .BR usleep (3)
  943.  
  944. .ne 10
  945. .SH AUTHOR
  946. .RS 5
  947. .nf
  948. John Walker
  949. Autodesk SA
  950. Avenue des Champs-Montants 14b
  951. CH-2074 MARIN
  952. Suisse/Schweiz/Svizzera/Svizra/Switzerland
  953. Usenet: kelvin@Autodesk.com
  954. Fax:    038/33 88 15
  955. Voice:  038/33 76 33
  956. .fi
  957. .RE
  958. SHAR_EOF
  959. fi # end of overwriting check
  960. echo shar: extracting "'soundbyte.c'" '(3658 characters)'
  961. if test -f 'soundbyte.c'
  962. then
  963.        echo shar: will not over-write existing file "'soundbyte.c'"
  964. else
  965. cat << \SHAR_EOF > 'soundbyte.c'
  966. /*
  967.  
  968.     NetFone: Sound interface functions
  969.  
  970.     Designed and implemented in July of 1991 by John Walker
  971.  
  972. */
  973.  
  974. #include <sys/types.h>
  975. #include <sys/dir.h>
  976. #include <sys/file.h>
  977.  
  978. #include <math.h>
  979. #include <fcntl.h>
  980. #include <errno.h>
  981. #include <stdio.h>
  982. #include <assert.h>
  983.  
  984. #include <sys/ioctl.h>
  985. #include <sun/audioio.h>
  986.  
  987. #define SoundFile       "/dev/audio"
  988. #define AUDIO_CTLDEV    "/dev/audioctl"
  989.  
  990. #define MAX_GAIN    100
  991.  
  992. #define TRUE  1
  993. #define FALSE 0
  994.  
  995. #define V     (void)
  996.  
  997. struct sound_buf {
  998.     struct sound_buf *snext;          /* Next sound buffer */
  999.     int sblen;                  /* Length of this sound buffer */
  1000.     unsigned char sbtext[2];          /* Actual sampled sound */
  1001. };
  1002.  
  1003. /*  Local variables  */
  1004.  
  1005. static int audiof = -1;           /* Audio device file descriptor */
  1006. static int Audio_fd;              /* Audio control port */
  1007. static audio_info_t Audio_info;       /* Current configuration info */
  1008. static int recording = FALSE;          /* Recording in progress ? */
  1009.  
  1010. /*  Forward functions  */
  1011.  
  1012. void soundpoll();
  1013.  
  1014. /* Convert local gain into device parameters */
  1015.  
  1016. static unsigned scale_gain(g)
  1017.   unsigned g;
  1018. {
  1019.     return (AUDIO_MIN_GAIN + (unsigned)
  1020.     irint(((double) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN)) *
  1021.     ((double)g / (double)MAX_GAIN)));
  1022. }
  1023.  
  1024.  
  1025. /*  SOUNDINIT  --  Open the sound peripheral and initialise for
  1026.            access.  Return TRUE if successful, FALSE
  1027.            otherwise.  */
  1028.  
  1029. int soundinit(iomode)
  1030.   int iomode;
  1031. {
  1032.     assert(audiof == -1);
  1033.     if ((audiof = open(SoundFile, iomode)) >= 0) {
  1034.  
  1035.     if ((Audio_fd = open(AUDIO_CTLDEV, O_RDWR)) < 0) {
  1036.         perror(AUDIO_CTLDEV);
  1037.         return FALSE;
  1038.     }
  1039.     return TRUE;
  1040.     }
  1041.     return FALSE;
  1042. }
  1043.  
  1044. /*  SOUNDTERM  --  Close the sound device.  */
  1045.  
  1046. void soundterm()
  1047. {
  1048.     if (audiof >= 0) {
  1049.        V close(audiof);
  1050.        V close(Audio_fd);
  1051.        audiof = -1;
  1052.     }
  1053. }
  1054.  
  1055. /*  SOUNDRECORD  --  Begin recording of sound.    */
  1056.  
  1057. int soundrecord()
  1058. {
  1059.     assert(!recording);
  1060.     recording = TRUE;
  1061.     return recording;
  1062. }
  1063.  
  1064. /*  SOUNDPLAY  --  Begin playing a sound.  */
  1065.  
  1066. void soundplay(len, buf)
  1067.   int len;
  1068.   unsigned char *buf;
  1069. {
  1070.     int ios;
  1071.  
  1072.     assert(audiof != -1);
  1073.     while (TRUE) {
  1074.     ios = write(audiof, buf, len);
  1075.     if (ios == -1) {
  1076.         usleep(100000);
  1077.     } else {
  1078.         if (ios < len) {
  1079.         buf += ios;
  1080.         len -= ios;
  1081.         } else {
  1082.         break;
  1083.         }
  1084.     }
  1085.     }
  1086. }
  1087.  
  1088. /*  SOUNDPLAYVOL  --  Set playback volume from 0 (silence) to 100 (full on). */
  1089.  
  1090. void soundplayvol(value)
  1091.   int value;
  1092. {
  1093.     AUDIO_INITINFO(&Audio_info);
  1094.     Audio_info.play.gain = scale_gain(value);
  1095.     if (ioctl(Audio_fd, AUDIO_SETINFO, &Audio_info) < 0) {
  1096.         perror("Set play volume");
  1097.     }
  1098. }
  1099.  
  1100. /*  SOUNDRECGAIN  --  Set recording gain from 0 (minimum) to 100 (maximum).  */
  1101.  
  1102. void soundrecgain(value)
  1103.   int value;
  1104. {
  1105.     AUDIO_INITINFO(&Audio_info);
  1106.     Audio_info.record.gain = scale_gain(value);
  1107.     if (ioctl(Audio_fd, AUDIO_SETINFO, &Audio_info) < 0) {
  1108.         perror("Set record gain");
  1109.     }
  1110. }
  1111.  
  1112. /*  SOUNDDEST  --  Set destination for generated sound.  If "where"
  1113.            is 0, sound goes to the built-in speaker; if
  1114.            1, to the audio output jack. */
  1115.  
  1116. void sounddest(where)
  1117.   int where;
  1118. {
  1119.     AUDIO_INITINFO(&Audio_info);
  1120.     Audio_info.play.port = (where == 0 ? AUDIO_SPEAKER : AUDIO_HEADPHONE);
  1121.     if (ioctl(Audio_fd, AUDIO_SETINFO, &Audio_info) < 0) {
  1122.         perror("Set output port");
  1123.     }
  1124. }
  1125.  
  1126. /*  SOUNDGRAB  --  Return audio information in the record queue.  */
  1127.  
  1128. int soundgrab(buf, len)
  1129.     char *buf;
  1130.     int len;
  1131. {
  1132.     if (recording) {
  1133.     long read_size;
  1134.  
  1135.     if (ioctl(audiof, FIONREAD, &read_size) < 0) {
  1136.             perror("FIONREAD ioctl failed");
  1137.     } else {
  1138.         if (read_size > len)
  1139.         read_size = len;
  1140.         read(audiof, buf, read_size);
  1141.         return read_size;
  1142.     }
  1143.     }
  1144.     return 0;
  1145. }
  1146. SHAR_EOF
  1147. fi # end of overwriting check
  1148. echo shar: extracting "'speaker.c'" '(5225 characters)'
  1149. if test -f 'speaker.c'
  1150. then
  1151.        echo shar: will not over-write existing file "'speaker.c'"
  1152. else
  1153. cat << \SHAR_EOF > 'speaker.c'
  1154. /*
  1155.  
  1156.     NetFone: Network sound play server
  1157.  
  1158.     Designed and implemented in July of 1991 by John Walker.
  1159.  
  1160. */
  1161.  
  1162. #include <stdio.h>
  1163. #include <fcntl.h>
  1164. #include <assert.h>
  1165. #include <signal.h>
  1166. #include "ulaw2linear.h"
  1167. #include <sys/types.h>
  1168. #include <sys/socket.h>
  1169. #include <netinet/in.h>
  1170. #include <netdb.h>
  1171.  
  1172. struct soundbuf {
  1173.     int compression;
  1174.     char sendinghost[16];
  1175.     struct {
  1176.         int buffer_len;
  1177.         char buffer_val[8000];
  1178.     } buffer;
  1179. };
  1180. typedef struct soundbuf soundbuf;
  1181.  
  1182. #define TRUE    1
  1183. #define FALSE    0
  1184.  
  1185. static int audiok = FALSE;          /* Audio initialised flag */
  1186. static int audiotime = 0;          /* Audio timeout counter */
  1187. static int debugging = FALSE;          /* Debugging enabled */
  1188. static char echost[24] = "";          /* Last echo host */
  1189.  
  1190. #define TickTock    10              /* Alarm interval in seconds */
  1191.  
  1192. /*  RELEASE  --  Signal-catching function which releases the audio
  1193.                  device if we haven't received anything to play in
  1194.          the last minute. */
  1195.  
  1196. static void release()
  1197. {
  1198.     if (debugging) {
  1199.         fprintf(stderr, "Tick....\n");
  1200.     }
  1201.     if (++audiotime >= 2) {
  1202.     soundterm();
  1203.     audiok = FALSE;
  1204.     if (debugging) {
  1205.             fprintf(stderr, "Speaker releasing audio device.\n");
  1206.     }
  1207.     } else {
  1208.     alarm(TickTock);          /* Wind the cat */
  1209.     }
  1210. }
  1211.  
  1212. /*  PLAYBUFFER    --  Send next buffer to audio output. */
  1213.  
  1214. static void playbuffer(msg)
  1215.   soundbuf *msg;
  1216. {
  1217.     char *val;
  1218.     int len;
  1219.     char auxbuf[8002];
  1220.  
  1221.     debugging = (msg->compression & 2) ? TRUE : FALSE;
  1222.  
  1223.     if (!audiok) {
  1224.     if (!soundinit(O_WRONLY)) {
  1225.             perror("opening audio output device");
  1226.             return;                   /* Can't acquire sound device */
  1227.     }
  1228.     audiok = TRUE;
  1229.     if (debugging) {
  1230.             fprintf(stderr, "Speaker opening audio device.\n");
  1231.     }
  1232.     signal(SIGALRM, release);     /* Set signal to handle timeout */
  1233.     alarm(TickTock);          /* Set alarm clock to free audio device */
  1234.     audiotime = 0;              /* Reset timeout counter */
  1235.     }
  1236.  
  1237.     if (debugging) {
  1238.         printf("Playing %d%s bytes from %s.\n", msg->buffer.buffer_len,
  1239.                 (msg->compression & 1) ? " compressed" : "", msg->sendinghost);
  1240.     }
  1241.     len = msg->buffer.buffer_len;
  1242.     val = msg->buffer.buffer_val;
  1243.  
  1244.     /* If the 4 bit is on, use    the 8 bit to re-route the sound.  This
  1245.        is normally used to divert the sound to the speaker to  get  an
  1246.        individual's attention.  */
  1247.  
  1248.     if (msg->compression & 4) {
  1249.     sounddest((msg->compression & 8) ? 1 : 0);
  1250.     if (!(msg->compression & 8)) {
  1251.         soundplayvol(50);          /* Make sure volume high enough */
  1252.     }
  1253.     }
  1254.  
  1255.     /* If the buffer contains compressed sound samples, reconstruct an
  1256.        approximation of the original  sound  by  performing  a    linear
  1257.        interpolation between each pair of adjacent compressed samples.
  1258.        Note that since the samples are logarithmically scaled, we must
  1259.        transform  them    to  linear  before interpolating, then back to
  1260.        log before storing the calculated sample. */
  1261.  
  1262.     if (msg->compression & 1) {
  1263.     int i;
  1264.     register char *ab = auxbuf;
  1265.  
  1266.     assert(len < sizeof auxbuf);
  1267.     for (i = 0; i < len; i++) {
  1268.         *ab++ = i == 0 ? *val :
  1269.         (audio_s2u((audio_u2s(*val) + audio_u2s(val[-1])) / 2));
  1270.         *ab++ = *val++;
  1271.     }
  1272.     len *= 2;
  1273.     val = auxbuf;
  1274.     }
  1275.  
  1276.     audiotime = 0;              /* Reset timeout counter */
  1277.     soundplay(len, val);
  1278. }
  1279.  
  1280. /*  Main program  */
  1281.  
  1282. int main()
  1283. {
  1284.     int sock;
  1285.     struct sockaddr_in name;
  1286.     struct soundbuf sb;
  1287.  
  1288.     /* Create the socket from which to read */
  1289.  
  1290.     sock = socket(AF_INET, SOCK_DGRAM, 0);
  1291.     if (sock < 0) {
  1292.         perror("opening datagram socket");
  1293.     return 1;
  1294.     }
  1295.  
  1296.     /* Create name with wildcards. */
  1297.  
  1298.     name.sin_family = AF_INET;
  1299.     name.sin_addr.s_addr = INADDR_ANY;
  1300.     name.sin_port = Internet_Port;
  1301.     if (bind(sock, (struct sockaddr *) &name, sizeof name) < 0) {
  1302.         perror("binding datagram socket");
  1303.     return 1;
  1304.     }
  1305.  
  1306.     /* Read from the socket. */
  1307.  
  1308.     while (TRUE) {
  1309.     if (read(sock, &sb, sizeof sb) < 0) {
  1310.             perror("receiving datagram packet");
  1311.     }
  1312.  
  1313.     /* If  the packet requests loop-back,  immediately dispatch it
  1314.        back to the host who sent it to us.    To prevent an infinite
  1315.        loop-back  cycle,  we clear the loop-back bit in the header
  1316.        before sending the message.    We leave the  host  of    origin
  1317.        unchanged,  allowing  the  sender to identify the packet as
  1318.        one he originated. */
  1319.  
  1320.     if (sb.compression & 16) {
  1321.  
  1322.             /* If the host we're bouncing back the packet to isn't the
  1323.            same  as  the  last one we bounced to, look up its host
  1324.            identity and save it as the last host. */
  1325.  
  1326.         if (strcmp(sb.sendinghost, echost) != 0) {
  1327.         struct hostent *hp, *gethostbyname();
  1328.  
  1329.         hp = gethostbyname(sb.sendinghost);
  1330.         if (hp != 0) {
  1331.             bcopy((char *) hp->h_addr, (char *) &(name.sin_addr),
  1332.               hp->h_length);
  1333.             name.sin_family = AF_INET;
  1334.             name.sin_port = htons(Internet_Port);
  1335.             strcpy(echost, sb.sendinghost);
  1336.         } else {
  1337.             echost[0] = 0;
  1338.         }
  1339.         }
  1340.         sb.compression &= ~16;    /* Prevent infinite loopback */
  1341.         if (sendto(sock, &sb,
  1342.         (sizeof(struct soundbuf)) - (8000 - sb.buffer.buffer_len),
  1343.         0, (struct sockaddr *) &(name), sizeof name) < 0) {
  1344.                 perror("sending datagram message");
  1345.        }
  1346.     }
  1347.  
  1348.     playbuffer(&sb);
  1349.     }
  1350. }
  1351. SHAR_EOF
  1352. fi # end of overwriting check
  1353. #    End of shell archive
  1354. exit 0
  1355.