home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume26 / radio202 / part02 < prev    next >
Encoding:
Text File  |  1993-04-14  |  40.1 KB  |  1,681 lines

  1. Newsgroups: comp.sources.unix
  2. From: guido.van.rossum@cwi.nl (Guido van Rossum)
  3. Subject: v26i163: radio - UDP broadcast/receive utilities for audio data, V2.0.2, Part02/02
  4. Sender: unix-sources-moderator@vix.com
  5. Approved: paul@vix.com
  6.  
  7. Submitted-By: guido.van.rossum@cwi.nl (Guido van Rossum)
  8. Posting-Number: Volume 26, Issue 163
  9. Archive-Name: radio2.0.2/part02
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 2 (of 2)."
  18. # Contents:  broadcast.c checkradio.py radio.c
  19. # Wrapped by vixie@gw.home.vix.com on Thu Apr 15 18:45:44 1993
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'broadcast.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'broadcast.c'\"
  23. else
  24. echo shar: Extracting \"'broadcast.c'\" \(12098 characters\)
  25. sed "s/^X//" >'broadcast.c' <<'END_OF_FILE'
  26. X/***********************************************************
  27. Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The
  28. Netherlands.
  29. X
  30. X                        All Rights Reserved
  31. X
  32. Permission to use, copy, modify, and distribute this software and its 
  33. documentation for any purpose and without fee is hereby granted, 
  34. provided that the above copyright notice appear in all copies and that
  35. both that copyright notice and this permission notice appear in 
  36. supporting documentation, and that the names of Stichting Mathematisch
  37. Centrum or CWI not be used in advertising or publicity pertaining to
  38. distribution of the software without specific, written prior permission.
  39. X
  40. STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
  41. THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  42. XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
  43. XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  44. WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  45. ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  46. OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  47. X
  48. X******************************************************************/
  49. X
  50. X/* Broadcast audio packets over UDP.
  51. X   Standard input should be an audio source, e.g. /dev/audio
  52. X   (on a Sun) or a pipe from a program generating audio, e.g.
  53. X   recordulaw or cdsend (on an SGI Indigo).  Default input format is
  54. X   8-bit U-LAW; use -l to read 16-bit linear instead (all mono 8000
  55. X   samples/sec).
  56. X
  57. X   Command line options:
  58. X
  59. X   -a        ADPCM encoding -- half the data, slightly worse sound
  60. X   -A        ADPCM encoding without state, even worse sound
  61. X   -b ipaddr    IP address to broadcast to; may be repeated
  62. X        (default broadcast on local net)
  63. X   -c port    listen to this control port (default 54319)
  64. X   -d        debug output
  65. X   -l        take linear input (signed shorts in native byte order)
  66. X   -m ttl    Multicast TTL (0 host, 1 subnet, 32 site, 64 region)
  67. X   -n        no silence detection
  68. X   -p port    broadcast to this port number (default 54321)
  69. X   -t           time output; use when input is faster than realtime
  70. X        (e.g., read from a file file)
  71. X   -N name    station name (default your username)
  72. X   -L file    log file (default /ufs/<username>/CDlog)
  73. X   -P file    program file (default /ufs/<username>/CD)
  74. X*/
  75. X
  76. X#include "radio.h"
  77. X#include "adpcm.h"
  78. X
  79. X#include <stdio.h>
  80. X#include <errno.h>
  81. X#include <stdlib.h>
  82. X#include <fcntl.h>
  83. X
  84. X#include <sys/types.h>
  85. X#include <sys/socket.h>
  86. X#include <netinet/in.h>
  87. X#include <netdb.h>
  88. X#include <sys/time.h>
  89. X#include <sys/stat.h>
  90. X
  91. extern long time();
  92. X
  93. X#ifdef SUNHACKS
  94. X#include <sys/sockio.h>        /* For SIOCGIF* */
  95. X#include <net/if.h>        /* For struct if* */
  96. X#endif
  97. X
  98. X#ifdef REMHDR
  99. X#include <multimedia/libaudio.h>
  100. X#include <multimedia/audio_filehdr.h>
  101. X#endif
  102. X
  103. X#ifdef NeXT
  104. X#include <sound/sound.h>
  105. X#endif
  106. X
  107. X#ifdef __sgi
  108. X#include <limits.h>
  109. X#include <sys/prctl.h>
  110. X#include <sys/schedctl.h>
  111. X#endif
  112. X
  113. extern int optind;
  114. extern char * optarg;
  115. X
  116. char *progname;
  117. char infostring[CTLPKTSIZE];
  118. struct timeval zerotime;
  119. struct timeval tstart;
  120. int pdebug = 0;
  121. X
  122. X#define NBCADDR 10        /* Max number of broadcast addresses */
  123. int nbcaddr = 0;        /* Number of broadcast address options */
  124. struct sockaddr_in bcaddr[NBCADDR];    /* Broadcast addresses */
  125. struct sockaddr_in infoaddr[NBCADDR];    /* Ditto for info messages */
  126. X
  127. int port = RCVPORT;
  128. char *name = 0;
  129. char *logfile = 0;
  130. char *programfile = 0;
  131. char *user;
  132. char *home;
  133. X
  134. long packetcount = 0;
  135. int transmitting = 1;
  136. int encoding = PCM_64;
  137. X
  138. char *
  139. whoami()
  140. X{
  141. X    char *user = getenv("LOGNAME");
  142. X    if (user == NULL) {
  143. X        user = getenv("USER");
  144. X        if (user == NULL)
  145. X            user = "???";
  146. X        /* XXX should use getpwbyuid(getuid) if HOME missing */
  147. X    }
  148. X    return user;
  149. X}
  150. X
  151. char *
  152. whereami()
  153. X{
  154. X    return getenv("HOME");
  155. X    /* XXX should use getpwbyname(user) if HOME missing */
  156. X}
  157. X
  158. int
  159. makeinfo()
  160. X{
  161. X    FILE *fp;
  162. X    int n;
  163. X    struct stat s;
  164. X    long age;
  165. X
  166. X    if (stat(programfile, &s) >= 0)
  167. X        age = time((long*)0) - s.st_mtime;
  168. X    else
  169. X        age = -1;
  170. X    sprintf(infostring, "radio:S:%s:%d:%d:%s:%ld:",
  171. X        name, port, transmitting, logfile, age);
  172. X    n = strlen(infostring);
  173. X    fp = fopen(programfile, "r");
  174. X    if (fp != NULL) {
  175. X        fgets(infostring + n, sizeof infostring - n, fp);
  176. X        fclose(fp);
  177. X        n = strlen(infostring);
  178. X        if (infostring[n-1] == '\n')
  179. X            infostring[--n] = '\0';
  180. X    }
  181. X    return n;
  182. X}
  183. X
  184. void
  185. sendinfo(s, addr, addrsize)
  186. X    int s; /* Socket */
  187. X    struct sockaddr *addr;
  188. X    int addrsize;
  189. X{
  190. X    int n = makeinfo();
  191. X    if (sendto(s, infostring, n, 0, addr, addrsize) < 0)
  192. X        perror("sendto in sendinfo");
  193. X}
  194. X
  195. main(argc, argv)
  196. X    int argc;
  197. X    char **argv;
  198. X{
  199. X    char *broadcastaddr = NULL;
  200. X    char real_buf[HEADERSIZE + 3 + BUFFERSIZE];
  201. X    char tmp_buf[BUFFERSIZE];
  202. X    short lin_buf[BUFFERSIZE];
  203. X    char *buf;
  204. X    int on = 1;
  205. X    int i, n;
  206. X    int s, ctls;
  207. X    int c;
  208. X    int timing = 0;
  209. X    fd_set inputav;
  210. X    struct sockaddr_in locsin;
  211. X    struct sockaddr_in ctlsin;
  212. X    int ctlsinsize;
  213. X    int ctlport = BCASTCTLPORT;
  214. X    int noisy = 0;
  215. X    int linear = 0;
  216. X    struct adpcm_state state;
  217. X#ifdef HAVE_MCAST
  218. X    u_char ttl = MULTICAST_TTL;
  219. X#endif
  220. X
  221. X#ifdef __sgi
  222. X    (void) schedctl(NDPRI, 0, NDPNORMMAX);
  223. X    setuid(getuid());
  224. X#endif
  225. X
  226. X    progname = argv[0];
  227. X
  228. X/* Always change these two macros and the following switch together! */
  229. X#define OPTIONS "Aab:c:dlm:np:tL:N:P:"
  230. X#define USAGE    \
  231. X    "usage: %s [-A] [-a] [-b broadcastaddr] ... [-c ctlport] [-d] [-l]\n\
  232. X\t[-m ttl] [-n] [-p port] [-t]\n\t[-N name] [-L logfile] [-P programfile]\n"
  233. X
  234. X    while ((c = getopt(argc, argv, OPTIONS)) != EOF) {
  235. X        switch (c) {
  236. X        default:
  237. X        case '?':
  238. X            fprintf(stderr, USAGE, progname);
  239. X            exit(2);
  240. X        case 'A':
  241. X            encoding = ADPCM_32;
  242. X            break;
  243. X        case 'a':
  244. X            encoding = ADPCM_32_W_STATE;
  245. X            break;
  246. X        case 'b':
  247. X            if (nbcaddr >= NBCADDR) {
  248. X                fprintf(stderr,
  249. X                    "%s: too many -b options (max %d)\n",
  250. X                    progname, NBCADDR);
  251. X                exit(2);
  252. X            }
  253. X            if (setipaddr(optarg, &bcaddr[nbcaddr]) < 0) {
  254. X                fprintf(stderr,
  255. X                    "%s: bad broadcast address '%s'\n",
  256. X                    progname, broadcastaddr);
  257. X                exit(2);
  258. X            }
  259. X            nbcaddr++;
  260. X            break;
  261. X        case 'c':
  262. X            ctlport = atoi(optarg);
  263. X            break;
  264. X        case 'd':
  265. X            pdebug = 1;
  266. X            break;
  267. X        case 'l':
  268. X            linear = 1;
  269. X            break;
  270. X        case 'm':
  271. X#ifdef HAVE_MCAST
  272. X            ttl = atoi(optarg);
  273. X#else
  274. X            fprintf(stderr, "(-m not supported here)\n");
  275. X#endif
  276. X            break;
  277. X        case 'n':
  278. X            noisy = 1;
  279. X            break;
  280. X        case 'p':
  281. X            port = atoi(optarg);
  282. X            break;
  283. X        case 't':
  284. X            timing = 1;
  285. X            break;
  286. X        case 'L':
  287. X            logfile = optarg;
  288. X            break;
  289. X        case 'N':
  290. X            name = optarg;
  291. X            break;
  292. X        case 'P':
  293. X            programfile = optarg;
  294. X            break;
  295. X        }
  296. X    }
  297. X
  298. X    user = whoami();
  299. X    home = whereami();
  300. X
  301. X    if (logfile == 0) {
  302. X        static char logbuf[100];
  303. X        sprintf(logbuf, "%s/.CDlog", home);
  304. X        logfile = logbuf;
  305. X    }
  306. X    if (name == 0)
  307. X        name = user;
  308. X    if (programfile == 0) {
  309. X        static char programbuf[100];
  310. X        sprintf(programbuf, "%s/.CD", home);
  311. X        programfile = programbuf;
  312. X    }
  313. X
  314. X    s = opensock("data", (char *)NULL, SENDPORT, (char *)NULL, 0, 1);
  315. X
  316. X    if (nbcaddr == 0) {
  317. X#if defined(HAVE_MCAST) && defined (DEFMCAST)
  318. X        if (setipaddr(DEFMCAST, &bcaddr[nbcaddr]) < 0) {
  319. X            fprintf(stderr,
  320. X                "%s: bad broadcast address '%s'\n",
  321. X                progname, broadcastaddr);
  322. X            exit(2);
  323. X        }
  324. X#else
  325. X        configure(s, &bcaddr[0]);
  326. X#endif
  327. X        nbcaddr = 1;
  328. X    }
  329. X
  330. X    for (i = 0; i < nbcaddr; i++) {
  331. X        bcaddr[i].sin_port = htons(port);
  332. X        bcaddr[i].sin_family = AF_INET;
  333. X        infoaddr[i] = bcaddr[i];
  334. X        infoaddr[i].sin_port = htons(INFOPORT);
  335. X    }
  336. X
  337. X#ifdef HAVE_MCAST
  338. X    if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
  339. X        perror("mcast ttl");
  340. X#endif
  341. X
  342. X    ctls = opensock("control", (char *)NULL, ctlport, (char *)NULL, 0, 0);
  343. X
  344. X    if(timing) {
  345. X        if (!linear) {
  346. X#ifdef REMHDR
  347. X            Audio_hdr hp;
  348. X            (void) audio_read_filehdr(0, &hp, NULL, NULL);
  349. X#endif
  350. X#ifdef NeXT
  351. X            SNDSoundStruct s;
  352. X            (void) fread((void *)&s, sizeof(SNDSoundStruct), 1,
  353. X                     stdin);
  354. X#endif
  355. X        }
  356. X        gettimeofday(&tstart, 0);
  357. X    }
  358. X
  359. X    real_buf[0] = AUDIO_TYPE;
  360. X    real_buf[1] = encoding;
  361. X
  362. X    state.valprev = 0;
  363. X    state.index = 0;
  364. X
  365. X    for (;;) {
  366. X        if (linear) {
  367. X            n = fread(lin_buf, sizeof(short), BUFFERSIZE, stdin);
  368. X            buf = real_buf + HEADERSIZE;
  369. X        }
  370. X        else {
  371. X            if (encoding == PCM_64)
  372. X                buf = real_buf + HEADERSIZE;
  373. X            else
  374. X                buf = tmp_buf;
  375. X            n = fread(buf, 1, BUFFERSIZE, stdin);
  376. X        }
  377. X        if (n <= 0) {
  378. X            if (n < 0)
  379. X                perror("fread");
  380. X            break;
  381. X        }
  382. X        if(timing)
  383. X            waiting(SAMPLINGRATE, BUFFERSIZE);
  384. X        if (!linear && !noisy && silent(buf, n)) {
  385. X            if (transmitting) {
  386. X                if (pdebug)
  387. X                    fprintf(stderr, "start silence\n");
  388. X                transmitting = 0;
  389. X            }
  390. X        }
  391. X        else {
  392. X            if (!transmitting) {
  393. X                if (pdebug)
  394. X                    fprintf(stderr, "end silence\n");
  395. X                packetcount = 0;
  396. X                transmitting = 1;
  397. X            }
  398. X            switch (encoding) {
  399. X            case PCM_64:
  400. X                if (linear) {
  401. X                    for (i = 0; i < n; i++) {
  402. X                        buf[i] = st_linear_to_ulaw(
  403. X                             lin_buf[i]);
  404. X                    }
  405. X                }
  406. X                break;
  407. X            case ADPCM_32:
  408. X                buf = real_buf + HEADERSIZE;
  409. X                if (linear)
  410. X                    adpcm_coder(lin_buf, buf, n,
  411. X                         (struct adpcm_state *)0);
  412. X                else
  413. X                    ulaw_adpcm_coder(tmp_buf, buf, n,
  414. X                         (struct adpcm_state *)0);
  415. X                n = (n+1)/2;
  416. X                break;
  417. X            case ADPCM_32_W_STATE:
  418. X                buf = real_buf + HEADERSIZE;
  419. X                *buf++ = (state.valprev>>8) & 0xff;
  420. X                *buf++ = state.valprev & 0xff;
  421. X                *buf++ = state.index;
  422. X                if (linear)
  423. X                    adpcm_coder(lin_buf, buf, n, &state);
  424. X                else
  425. X                    ulaw_adpcm_coder(tmp_buf, buf, n,
  426. X                             &state);
  427. X                n = (n+1)/2 + 3;
  428. X                break;
  429. X            }
  430. X            for (i = 0; i < nbcaddr; i++) {
  431. X                /* Send data packets to all bcast ports */
  432. X                if (sendto(s, real_buf, HEADERSIZE+n, 0,
  433. X                       &bcaddr[i], sizeof bcaddr[i]) !=
  434. X                                                HEADERSIZE+n) {
  435. X                    perror("sendto");
  436. X                }
  437. X            }
  438. X            if (packetcount % INFOFREQ == 0) {
  439. X                /* Send info packets to all info ports
  440. X                   and to all bcast ports */
  441. X                if (pdebug)
  442. X                    fprintf(stderr, "sending info\n");
  443. X                for (i = 0; i < nbcaddr; i++) {
  444. X                    sendinfo(s, &infoaddr[i],
  445. X                         sizeof infoaddr[i]);
  446. X                    sendinfo(s, &bcaddr[i],
  447. X                         sizeof bcaddr[i]);
  448. X                }
  449. X            }
  450. X            if (pdebug) {
  451. X                if(packetcount % 8 == 0) {
  452. X                    fprintf(stderr, "%ld packets sent\n",
  453. X                        packetcount);
  454. X                }
  455. X            }
  456. X            packetcount++;
  457. X        }
  458. X        if (ctls >= 0) {
  459. X            FD_ZERO(&inputav);
  460. X            FD_SET(ctls, &inputav);
  461. X            if (select(ctls+1, &inputav, 0, 0, &zerotime) == 1) {
  462. X                ctlsinsize = sizeof(ctlsin);
  463. X                n = recvfrom(ctls, buf, BUFFERSIZE, 0,
  464. X                         &ctlsin, &ctlsinsize);
  465. X                if (n < 0) {
  466. X                    perror("recvfrom");
  467. X                    exit(1);
  468. X                }
  469. X                if (n >= 7 &&
  470. X                    strncmp(buf, "radio:s", 7) == 0) {
  471. X                    sendinfo(ctls, &ctlsin, ctlsinsize);
  472. X                }
  473. X                else {
  474. X                    fprintf(stderr,
  475. X                        "%s: Funny ctl message\n",
  476. X                        progname);
  477. X                }
  478. X            }
  479. X        }
  480. X    }
  481. X
  482. X    exit(0);
  483. X}
  484. X
  485. configure(s, addr_ret)
  486. X    int s;
  487. X    struct sockaddr_in *addr_ret;
  488. X{
  489. X#ifdef SUNHACKS
  490. X    char buf[BUFSIZ];
  491. X    struct ifconf ifc;
  492. X    struct ifreq ifreq;
  493. X
  494. X    ifc.ifc_len = sizeof(buf);
  495. X    ifc.ifc_buf = buf;
  496. X    if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
  497. X        perror("ioctl SIOCGIFCONF");
  498. X        exit(1);
  499. X    }
  500. X    ifreq = *ifc.ifc_req;
  501. X    if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
  502. X        perror("ioctl SIOCGIFBRDADDR");
  503. X        exit(1);
  504. X    }
  505. X    * (struct sockaddr *) addr_ret = ifreq.ifr_broadaddr;
  506. X#else
  507. X    addr_ret->sin_addr.s_addr = INADDR_BROADCAST;
  508. X#endif
  509. X}
  510. X
  511. X/*
  512. X * routine to sleep between consecutive packets
  513. X */
  514. X
  515. waiting(rate, data)
  516. X    int rate;
  517. X    int data;
  518. X{
  519. X    static int bytes = 0; /* packets already sent */
  520. X
  521. X    struct timeval tnow;
  522. X    int tsleep;
  523. X
  524. X    bytes += data;
  525. X    gettimeofday(&tnow, 0);
  526. X
  527. X    tsleep =  ((double) bytes/(double) rate) * 1000000
  528. X        - ((tnow.tv_sec - tstart.tv_sec) * 1000000
  529. X                    + tnow.tv_usec - tstart.tv_usec);
  530. X    if (tsleep > 0) {
  531. X        struct timeval t;
  532. X
  533. X        t.tv_sec = tsleep / 1000000;
  534. X        t.tv_usec = tsleep % 1000000;
  535. X        (void) select(0, NULL, NULL, NULL, &t);
  536. X    }
  537. X}
  538. X
  539. X/*
  540. X * Silence detection.
  541. X * You may have to play with these parameters.
  542. X * Our input is rather noisy, hence we have a rather high threshold.
  543. X */
  544. X
  545. X#define DEADTIME (20*SAMPLINGRATE) /* After this much silence we cut off */
  546. X#define THRESHOLD 75 /* Max silent U-LAW value (after normalization) */
  547. X
  548. silent(buf, n)
  549. X    register char *buf;
  550. X    register int n;
  551. X{
  552. X    static int dead = DEADTIME; /* State */
  553. X    register int abs;
  554. X
  555. X    dead += n;
  556. X    while (--n >= 0) {
  557. X        abs = 127 - ((*buf++) & 127);
  558. X        if (abs > THRESHOLD) {
  559. X            dead = 0;
  560. X            return 0;
  561. X        }
  562. X    }
  563. X    return (dead > DEADTIME);
  564. X}
  565. END_OF_FILE
  566. if test 12098 -ne `wc -c <'broadcast.c'`; then
  567.     echo shar: \"'broadcast.c'\" unpacked with wrong size!
  568. fi
  569. # end of 'broadcast.c'
  570. fi
  571. if test -f 'checkradio.py' -a "${1}" != "-c" ; then 
  572.   echo shar: Will not clobber existing file \"'checkradio.py'\"
  573. else
  574. echo shar: Extracting \"'checkradio.py'\" \(8719 characters\)
  575. sed "s/^X//" >'checkradio.py' <<'END_OF_FILE'
  576. X# /***********************************************************
  577. X# Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The
  578. X# Netherlands.
  579. X# 
  580. X#                         All Rights Reserved
  581. X# 
  582. X# Permission to use, copy, modify, and distribute this software and its 
  583. X# documentation for any purpose and without fee is hereby granted, 
  584. X# provided that the above copyright notice appear in all copies and that
  585. X# both that copyright notice and this permission notice appear in 
  586. X# supporting documentation, and that the names of Stichting Mathematisch
  587. X# Centrum or CWI not be used in advertising or publicity pertaining to
  588. X# distribution of the software without specific, written prior permission.
  589. X# 
  590. X# STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
  591. X# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  592. X# FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
  593. X# FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  594. X# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  595. X# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  596. X# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  597. X# 
  598. X# ******************************************************************/
  599. X
  600. X# Continuously check radio transmissions on one or more ports.
  601. X# After an idea of Behr de Ruiter.
  602. X#
  603. X# usage: checkradio [-t] [port] ...
  604. X#
  605. X# Ports are given as command line arguments, default is radio's default.
  606. X# Shorthands 1..99 can be used as for radio's -p argument.
  607. X#
  608. X# With the -t option, repeatedly print status for each port argument.
  609. X# Without -t, pop up a GL window displaying the CD file if there is noise.
  610. X
  611. X# For best results, use /ufs/guido/bin/sgi/python to execute this.
  612. X# Don't make the file executable; then dynamic loading of audioop fails!
  613. X
  614. X# XXX To do:
  615. X# - need an option to suppress looping when using -t
  616. X# - need a `status only' option that sets exit status only
  617. X# - DELAY and LOOP should be under control of command line options
  618. X# - add options to specify font, colors and so on
  619. X# - optionally tune radio to the first station transmitting noise
  620. X# - should listen to info packets instead
  621. X# - move the symbolic constants and some subroutines to separate modules
  622. X
  623. X
  624. import sys
  625. import socket
  626. import audioop
  627. import string
  628. import time
  629. import os
  630. from stat import *
  631. from SOCKET import *
  632. import getopt
  633. X
  634. X
  635. X# Parametrizations
  636. X
  637. CTL_PORT = 54319            # control port
  638. PORT_OFFSET = 54320            # port offset if 1 <= port <= 99
  639. DEF_PORT = 54321            # default port (if no args)
  640. LOOP = 15                # listen for this many tenths seconds
  641. DELAY = 10                # seconds between successive tries
  642. LIMIT = 256                # silence threshold
  643. BUFSIZE = 1500                # read buffer size
  644. X
  645. X
  646. X# Status constants returned by checkport()
  647. X
  648. TUNED = 'already tuned in'
  649. BINDFAILURE = 'bind failure'
  650. DEAD = 'not transmitting'
  651. SILENT = 'transmitting silence'
  652. NOISY = 'transmitting'
  653. X
  654. X
  655. X# Main program
  656. X
  657. def main():
  658. X    try:
  659. X        optlist, args = getopt.getopt(sys.argv[1:], 'tx:y:')
  660. X    except getopt.error:
  661. X        sys.stdout = sys.stderr
  662. X        print 'usage: checkradio',
  663. X        print '[-x xorg] [-y yorg] [-t] [port] ...'
  664. X        print '-x xorg, -y yorg: left top origin of window',
  665. X        print '(negative values: right bottom)'
  666. X        print '-t: tty mode output (looping), no window'
  667. X        sys.exit(2)
  668. X    #
  669. X    do_win = 1
  670. X    x, y = 140, 4
  671. X    for opt, arg in optlist:
  672. X        if opt == '-t':
  673. X            do_win = 0
  674. X        elif opt == '-x':
  675. X            x = int(eval(arg))
  676. X        elif opt == '-y':
  677. X            y = int(eval(arg))
  678. X    #
  679. X    ports = []
  680. X    for arg in args:
  681. X        p = int(eval(arg))
  682. X        if 1 <= p <= 99:
  683. X            p = p + PORT_OFFSET
  684. X        ports.append(p)
  685. X    if not ports:
  686. X        ports.append(DEF_PORT)
  687. X    #
  688. X    if do_win:
  689. X        wincode(ports, (x, y))
  690. X    else:
  691. X        ttycode(ports)
  692. X
  693. X
  694. X# Code for tty version
  695. X
  696. def ttycode(ports):
  697. X    while 1:
  698. X        for p in ports:
  699. X            print 'port', p, ':',
  700. X            sys.stdout.flush()
  701. X            status, sender = checkport(p)
  702. X            if status in (NOISY, SILENT):
  703. X                cdname = getinfostring(p, sender)
  704. X                if cdname:
  705. X                    status = status + ': ' + cdname
  706. X            print status
  707. X        time.sleep(DELAY)
  708. X
  709. def getinfostring(port, sender):
  710. X    name, port, transmitting, logfile, age, contents = \
  711. X        getinfo(port, sender)
  712. X    if 0 <= age < 99999:
  713. X        contents = contents + ' (' + formatage(age) + ')'
  714. X    return contents
  715. X
  716. def formatage(age):
  717. X    if age < 60: return `age` + ' sec'
  718. X    if age < 3600: return `age/60` + ' min'
  719. X    if age < 24*3600: return `age/3600` + ' hrs'
  720. X    return `age/(24*3600)` + ' days'
  721. X
  722. X
  723. X# Code for GL window version
  724. X
  725. X# Parameters
  726. timer_rate = 60 # Seconds
  727. color_choices = [95, 94, 93, 92, 91, 90, 89, 88]
  728. X
  729. def wincode(ports, org):
  730. X    if len(ports) > 1:
  731. X        sys.stderr.write('warning: only the first port arg is used\n')
  732. X    port = ports[0]
  733. X    import gl, GL, DEVICE, fm
  734. X    #gl.foreground()
  735. X    fh = fm.findfont('Helvetica').scalefont(8)
  736. X    fh.setfont()
  737. X    str, age = getinfopair(port)
  738. X    # Always create the window initially -- to initialize gl
  739. X    wid = createwin(org, fh, str)
  740. X    gl.qdevice(DEVICE.TIMER1)
  741. X    gl.noise(DEVICE.TIMER1, timer_rate*60) # 60th of a second
  742. X    while 1:
  743. X        dev, val = gl.qread()
  744. X        if dev == DEVICE.REDRAW:
  745. X            redraw_window(wid, str, age)
  746. X        elif dev == DEVICE.TIMER1:
  747. X            oldstr = str
  748. X            str, age = getinfopair(port)
  749. X            if str <> oldstr:
  750. X                if wid > 0:
  751. X                    org = currentorg(org)
  752. X                    deletewin(wid)
  753. X                    wid = -1
  754. X                if str:
  755. X                    wid = createwin(org, fh, str)
  756. X            elif wid > 0:
  757. X                redraw_window(wid, str, age)
  758. X
  759. def currentorg((oldx, oldy)):
  760. X    import gl, GL
  761. X    x, y = gl.getorigin()
  762. X    if oldx >= 0 and oldy >= 0: return (oldx, oldy)
  763. X    xsize, ysize = gl.getsize()
  764. X    xmax = gl.getgdesc(GL.GD_XPMAX)
  765. X    ymax = gl.getgdesc(GL.GD_YPMAX)
  766. X    if oldx < 0:
  767. X        x = (x + xsize) - (xmax+1)
  768. X        if x >= 0: x = -1
  769. X    if oldy < 0:
  770. X        y = (y + ysize) - (ymax+1)
  771. X        if y >= 0: y = -1
  772. X    return x, y
  773. X
  774. def redraw_window(wid, str, age):
  775. X    import gl, GL, fm
  776. X    mins = age/60 # Convert to minutes
  777. X    
  778. X    gl.color(color_choices[min(max(0, mins/9), len(color_choices)-1)])
  779. X    gl.clear()
  780. X    
  781. X    gl.color(GL.BLACK)
  782. X
  783. X    xsize, ysize = gl.getsize()
  784. X    gl.bgnclosedline()
  785. X    gl.v2i(0, 0)
  786. X    gl.v2i(0, ysize-1)
  787. X    gl.v2i(xsize-1, ysize-1)
  788. X    gl.v2i(xsize-1, 0)
  789. X    gl.endclosedline()
  790. X
  791. X    gl.cmov2i(4, 4)
  792. X    fm.prstr(str)
  793. X
  794. def createwin((x, y), fh, str):
  795. X    import gl, GL, DEVICE
  796. X    gl.noborder()
  797. X    xsize = fh.getstrwidth(str) + 7
  798. X    ysize = 16
  799. X    if x < 0 or y < 0:
  800. X        xmax = gl.getgdesc(GL.GD_XPMAX)
  801. X        ymax = gl.getgdesc(GL.GD_YPMAX)
  802. X        if x < 0: x = x + (xmax+1) - xsize
  803. X        if y < 0: y = y + (ymax+1) - ysize
  804. X    gl.prefposition(x, x + xsize, y, y + ysize)
  805. X    wid = gl.winopen('checkradio')
  806. X    gl.qenter(DEVICE.REDRAW, wid)
  807. X    return wid
  808. X
  809. def deletewin(wid):
  810. X    import gl, GL, DEVICE
  811. X    gl.winclose(wid)
  812. X
  813. def getinfopair(port):
  814. X    state, sender = checkport(port)
  815. X    if state not in (NOISY, SILENT):
  816. X        return '', 99999
  817. X    name, port, transmitting, logfile, age, contents = \
  818. X        getinfo(port, sender)
  819. X    return contents, age
  820. X
  821. X
  822. X# Common code
  823. X
  824. def checkport(port):
  825. X    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  826. X    try:
  827. X        s.setsockopt(SOL_SOCKET, SO_REUSEPORT, 1)
  828. X    except socket.error:
  829. X        print 'warning: cannot set socket option SO_REUSEPORT'
  830. X    try:
  831. X        s.bind('', port)
  832. X    except socket.error, msg:
  833. X        if msg == (114, 'Address already in use'):
  834. X            return TUNED, msg
  835. X        else:
  836. X            return BINDFAILURE, msg
  837. X    transmitting = 0
  838. X    noise = 0
  839. X    sender = None
  840. X    for i in range(LOOP):
  841. X        if i: time.millisleep(100)
  842. X        while s.avail():
  843. X            data, sender = s.recvfrom(BUFSIZE)
  844. X            if data[:6] == 'radio:': continue
  845. X            transmitting = 1
  846. X            lindata = audioop.ulaw2lin(data, 2)
  847. X            n = audioop.max(lindata, 2)
  848. X            if n > LIMIT:
  849. X                noise = n
  850. X                break
  851. X        if noise: break
  852. X    s.close()
  853. X    if not transmitting:
  854. X        return DEAD, sender
  855. X    if not noise:
  856. X        return SILENT, sender
  857. X    return NOISY, sender
  858. X
  859. def getinfo(port, sender):
  860. X    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  861. X    s.sendto('radio:s', (sender[0], CTL_PORT))
  862. X    for i in range(LOOP):
  863. X        time.millisleep(100)
  864. X        while s.avail():
  865. X            data, realsender = s.recvfrom(BUFSIZE)
  866. X            if data[:7] == 'radio:S':
  867. X                return decodeinfo(data)
  868. X
  869. def decodeinfo(data):
  870. X    fields = string.splitfields(data, ':')
  871. X    name = fields[2]
  872. X    port = eval(fields[3])
  873. X    if fields[4:]:
  874. X        transmitting = eval(fields[4])
  875. X        logfile = fields[5]
  876. X        age = eval(fields[6])
  877. X        contents = string.joinfields(fields[7:], ':')
  878. X    else:
  879. X        transmitting = -1
  880. X        programfile = '/ufs/' + name + '/CD'
  881. X        logfile = programfile + 'log'
  882. X        age = getage(programfile)
  883. X        if age == None:
  884. X            age = -1
  885. X        contents = getcontents(programfile)
  886. X        if contents == None:
  887. X            contents = '???'
  888. X    return name, port, transmitting, logfile, age, contents
  889. X    return None
  890. X
  891. def getcontents(filename):
  892. X    try:
  893. X        f = open(filename, 'r')
  894. X    except IOError:
  895. X        return None
  896. X    res = f.readline()
  897. X    f.close()
  898. X    return string.strip(res)
  899. X
  900. def getage(filename):
  901. X    try:
  902. X        st = os.stat(filename)
  903. X    except os.error:
  904. X        return None
  905. X    return time.time() - st[ST_MTIME]
  906. X
  907. X
  908. X# Call the main program
  909. X
  910. try:
  911. X    main()
  912. except KeyboardInterrupt:
  913. X    print
  914. X    print '[Interrupt]'
  915. END_OF_FILE
  916. if test 8719 -ne `wc -c <'checkradio.py'`; then
  917.     echo shar: \"'checkradio.py'\" unpacked with wrong size!
  918. fi
  919. # end of 'checkradio.py'
  920. fi
  921. if test -f 'radio.c' -a "${1}" != "-c" ; then 
  922.   echo shar: Will not clobber existing file \"'radio.c'\"
  923. else
  924. echo shar: Extracting \"'radio.c'\" \(16417 characters\)
  925. sed "s/^X//" >'radio.c' <<'END_OF_FILE'
  926. X/***********************************************************
  927. Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The
  928. Netherlands.
  929. X
  930. X                        All Rights Reserved
  931. X
  932. Permission to use, copy, modify, and distribute this software and its 
  933. documentation for any purpose and without fee is hereby granted, 
  934. provided that the above copyright notice appear in all copies and that
  935. both that copyright notice and this permission notice appear in 
  936. supporting documentation, and that the names of Stichting Mathematisch
  937. Centrum or CWI not be used in advertising or publicity pertaining to
  938. distribution of the software without specific, written prior permission.
  939. X
  940. STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
  941. THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  942. XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
  943. XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  944. WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  945. ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  946. OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  947. X
  948. X******************************************************************/
  949. X
  950. X/* Receive audio UDP packets transmitted by broadcast.
  951. X
  952. X   Command line options:
  953. X
  954. X   -p port    tune to this port number (default 54321)
  955. X                (port numbers 1..99 are shorthands for 54321 and up)
  956. X   -v volume    output volume (range 0-100; default unchanged)
  957. X        (you can auso use [x_]gaintool or a similar tool to
  958. X        set the output volume etc.)
  959. X   -c port    use this control port (default 54320)
  960. X   -s        'secure' mode: don't listen to the control port
  961. X   -f        work as a filter: send output to stdout instead of
  962. X        directly to the audio hardware
  963. X   -l addr    listen only for packets to <arg> ip address
  964. X   -r addr    listen only for packets from <arg>
  965. X   -d        debug packets
  966. X   -n           noninterruptable -- by default radio will be interruptable
  967. X        by other sound outputting programs, hoping they do not
  968. X        take too long.  This option turns off that feature.
  969. X   -t        tee mode: send output to stdout as well as to audio h/w
  970. X   -m mcastgrp    multicast group (SGI only)
  971. X*/
  972. X
  973. X#include "radio.h"
  974. X#include "patchlevel.h"
  975. X
  976. X#include <stdio.h>
  977. X#include <errno.h>
  978. X#include <stdlib.h>
  979. X#include <fcntl.h>
  980. X#include <signal.h>
  981. X#include <netdb.h>
  982. X#include <sys/types.h>
  983. X#include <sys/socket.h>
  984. X#include <sys/time.h>
  985. X#include <netinet/in.h>
  986. X
  987. X#include "adpcm.h"
  988. X
  989. X#ifdef HAVE_MCAST
  990. X#include <arpa/inet.h>
  991. X
  992. X#ifdef DEFMCAST
  993. char defmcast[] = DEFMCAST;
  994. X#else
  995. char *defmcast = 0;
  996. X#endif /* DEFMCAST */
  997. X
  998. X#endif /* HAVE_MCAST */
  999. X
  1000. X#ifdef USE_AL
  1001. X#include <audio.h>
  1002. X#include "libst.h"
  1003. X
  1004. long savestate[] = {
  1005. X    AL_OUTPUT_RATE, 0,
  1006. X    /* The following two must be the last pairs! */
  1007. X    AL_LEFT_SPEAKER_GAIN, 0,
  1008. X    AL_RIGHT_SPEAKER_GAIN, 0,
  1009. X};
  1010. X
  1011. ALport aport;
  1012. X
  1013. void cleanup_handler();
  1014. X#endif /* USE_AL */
  1015. X
  1016. X#ifdef USE_SUN
  1017. X#include <stropts.h>
  1018. X#include <sun/audioio.h>
  1019. X
  1020. X#define AUDIO_IODEV     "/dev/audio"
  1021. X#define AUDIO_CTLDEV    "/dev/audioctl"
  1022. X
  1023. int interruptable = 1;
  1024. int actlfd = -1;
  1025. int afd = -1;
  1026. X
  1027. void sigpoll_handler();
  1028. X#endif /* USE_SUN */
  1029. X  
  1030. X#ifdef USE_NX
  1031. X#include <sound/sound.h>
  1032. X#define NUM_BUFFER 10
  1033. SNDSoundStruct *snd[NUM_BUFFER];
  1034. X#endif /* USE_NX */
  1035. X
  1036. X#ifdef CHECK_X_SERVER
  1037. X#include <X11/Xlib.h>
  1038. Display *xdisplay = 0;
  1039. X#endif /* CHECK_X_SERVER */
  1040. X
  1041. X/* getopt() interface */
  1042. extern int optind;
  1043. extern char * optarg;
  1044. X
  1045. X/* Globals */
  1046. int pausing = 0; /* Flag set when pausing */
  1047. int ofd = -1; /* Output file descriptor */
  1048. int volume = -1; /* -v parameter */
  1049. int pdebug = 0; /* -p parameter */
  1050. char *mcastgrp = 0; /* -m parameter */
  1051. X
  1052. X/* Forward functions */
  1053. void open_speaker();
  1054. void close_speaker();
  1055. void checkalive();
  1056. void setmcast(); /* Forward */
  1057. X
  1058. main(argc, argv)
  1059. X    int argc;
  1060. X    char **argv;
  1061. X{
  1062. X    int receiveport = RCVPORT;
  1063. X    int ctlport = RADIOCTLPORT;
  1064. X    char real_buf[BUFFERSIZE + HEADERSIZE];
  1065. X    char tmp_buf[BUFFERSIZE];
  1066. X    int encoding;
  1067. X    char *buf;
  1068. X    int s, ctls, curs;
  1069. X    struct sockaddr from;
  1070. X    int fromlen;
  1071. X    int c;
  1072. X    int filter = 0;
  1073. X    int tee = 0;
  1074. X    int nfds;
  1075. X    fd_set inputset;
  1076. X    int n;
  1077. X    char *localname = (char *) NULL;
  1078. X    char *remotename = (char *) NULL;
  1079. X    struct timeval timeout;
  1080. X    int packetcount;
  1081. X    struct adpcm_state state;
  1082. X#ifdef USE_AL
  1083. X    short obuf[BUFFERSIZE];
  1084. X    int i;
  1085. X    int curdatalinear;
  1086. X#endif
  1087. X#ifdef USE_NX
  1088. X    int akt_buf;
  1089. X#endif
  1090. X
  1091. X/* Always change these two macros and the following switch together! */
  1092. X#define OPTIONS "c:dfl:m:np:r:stv:"
  1093. X#define USAGE "usage: %s [options]\n\
  1094. User options:\n\
  1095. X-p port      : port to listen to (default 54321; 1..99 ==> 54321..54419)\n\
  1096. X-v volume    : volume setting (1-100; default unchanged)\n\
  1097. XExpert options:\n\
  1098. X-f           : filter mode (write data to stdout)\n\
  1099. X-t           : tee mode (write data to stdout as well as to audio device)\n\
  1100. X-n           : not interruptable by other sources (Sun only)\n\
  1101. X-c ctlport   : control port for tuner programs (default 54320)\n\
  1102. X-s           : secure mode: no control port (disallow tuner programs)\n\
  1103. Guru options:\n\
  1104. X-l localhost : listen to packets to this host only\n\
  1105. X-r remothost : receive packets from that host only\n\
  1106. X-m mcastgrp  : multicast group (not always supported)\n\
  1107. X-d           : debugging mode (writes messages to stderr)\n\
  1108. X"
  1109. X
  1110. X    while ((c = getopt(argc, argv, OPTIONS)) != EOF) {
  1111. X        switch (c) {
  1112. X        case '?':
  1113. X            fprintf(stderr, USAGE, argv[0]);
  1114. X            exit(2);
  1115. X        case 'p':
  1116. X            receiveport = atoi(optarg);
  1117. X            if (0 < receiveport && receiveport < 100)
  1118. X                receiveport += RCVPORT-1;
  1119. X            break;
  1120. X        case 'c':
  1121. X            ctlport = atoi(optarg);
  1122. X            break;
  1123. X        case 'l':
  1124. X            localname = optarg;
  1125. X            break;
  1126. X        case 'r':
  1127. X            remotename = optarg;
  1128. X            break;
  1129. X        case 'd':
  1130. X            pdebug = 1;
  1131. X            break;
  1132. X        case 'm':
  1133. X#ifdef HAVE_MCAST
  1134. X            mcastgrp = optarg;
  1135. X#else
  1136. X            fprintf(stderr, "(-m not supported here)\n");
  1137. X#endif
  1138. X            break;
  1139. X        case 'n':
  1140. X#ifdef USE_SUN
  1141. X            interruptable = 0;
  1142. X#else
  1143. X            fprintf(stderr, "(-n not supported here)\n");
  1144. X#endif
  1145. X            break;
  1146. X        case 's':
  1147. X            ctlport = -1;
  1148. X            break;
  1149. X        case 'f':
  1150. X            filter = 1;
  1151. X            tee = 0;
  1152. X            break;
  1153. X        case 't':
  1154. X            tee = 1;
  1155. X            filter = 0;
  1156. X            break;
  1157. X        case 'v':
  1158. X            volume = atoi(optarg);
  1159. X            break;
  1160. X        }
  1161. X    }
  1162. X
  1163. X    /* Meaning of the 'tee' and 'filter' flags:
  1164. X       At most one of these can be on.
  1165. X       if tee is on: write stdout and "/dev/audio";
  1166. X       if filter is on: write stdout only;
  1167. X       if both are off: write "/dev/audio" only;
  1168. X       where "/dev/audio" stands for whatever audio hardware we have. */
  1169. X
  1170. X    if (filter || tee)
  1171. X        ofd = fileno(stdout);
  1172. X    if (!filter) {
  1173. X        open_speaker();
  1174. X#ifdef CHECK_X_SERVER
  1175. X        xdisplay = XOpenDisplay((char *)NULL);
  1176. X        if (xdisplay == NULL) {
  1177. X            fprintf(stderr,
  1178. X"radio: warning: no X server -- you must kill radio when you log out!\n");
  1179. X        }
  1180. X#endif
  1181. X    }
  1182. X
  1183. X    if (ctlport >= 0)
  1184. X        ctls = opensock("control", (char *)NULL, ctlport,
  1185. X                (char *)NULL, 0, 0);
  1186. X    else
  1187. X        ctls = -1;
  1188. X
  1189. X    s = opensock("data", localname, receiveport, remotename, SENDPORT, 0);
  1190. X#ifdef HAVE_MCAST
  1191. X    if (mcastgrp)
  1192. X        setmcast(s, mcastgrp);
  1193. X    else if (defmcast)
  1194. X        setmcast(s, defmcast);
  1195. X#endif
  1196. X
  1197. X    packetcount = 0;
  1198. X
  1199. X    for (;;) {
  1200. X        /*
  1201. X        ** Wait until one of the sockets becomes ready
  1202. X        */
  1203. X        for (;;) {
  1204. X            nfds = (s > ctls ? s : ctls) + 1;
  1205. X            FD_ZERO(&inputset);
  1206. X            FD_SET(s, &inputset);
  1207. X            if (ctls >= 0)
  1208. X                FD_SET(ctls, &inputset);
  1209. X            timeout.tv_sec = 30;
  1210. X            timeout.tv_usec = 0;
  1211. X            n = select(nfds, &inputset, 0, 0, &timeout);
  1212. X            if (n > 0)
  1213. X                break;
  1214. X            if (n == 0) {
  1215. X                checkalive();
  1216. X            }
  1217. X            else if (errno != EINTR) {
  1218. X                perror("select");
  1219. X                exit(1);
  1220. X            }
  1221. X        }
  1222. X        if (ctls >= 0 && FD_ISSET(ctls, &inputset))
  1223. X            curs = ctls;
  1224. X        else if (FD_ISSET(s, &inputset))
  1225. X            curs = s;
  1226. X        /*
  1227. X        ** Read, and check for control packet
  1228. X        */
  1229. X        fromlen = sizeof(from);
  1230. X        buf = real_buf;
  1231. X        n = recvfrom(curs, buf, HEADERSIZE + BUFFERSIZE, 0,
  1232. X                 &from, &fromlen);
  1233. X        if (n <= 0) {
  1234. X            if (n == 0)
  1235. X                continue; /* Ignore empty packets */
  1236. X            perror("read");
  1237. X            break;
  1238. X        }
  1239. X        if (pdebug) {
  1240. X            if(pdebug == 8) {
  1241. X                fprintf(stderr, "8 packets received\n");
  1242. X                pdebug = 1;
  1243. X            }
  1244. X            else
  1245. X                pdebug++;
  1246. X        }
  1247. X        if (n <= CTLPKTSIZE) {
  1248. X            /*
  1249. X            ** It looks like a control packet. Check it.
  1250. X            */
  1251. X            buf[n] = '\0';
  1252. X            if (strncmp(buf, "radio:", 6) == 0) {
  1253. X                if (pdebug)
  1254. X                    fprintf(stderr, "control packet\n");
  1255. X                switch(buf[6]) {
  1256. X                case 'e':        /* Echo */
  1257. X                    buf[6] = 'E';
  1258. X                    sendto(curs, buf, n, 0,
  1259. X                           &from, fromlen);
  1260. X                    break;
  1261. X                case 'S':    /* Status from broadcast */
  1262. X                    if (pdebug)
  1263. X                        fprintf(stderr,
  1264. X                            "Status %s\n", buf);
  1265. X                    break;
  1266. X                case 't':        /* Tune */
  1267. X                    if (curs != ctls) {
  1268. X                        if (pdebug)
  1269. X                          fprintf(stderr,
  1270. X                            "radio: illegal tune\n");
  1271. X                        break;
  1272. X                    }
  1273. X#ifdef USE_SUN
  1274. X                    if (!filter) {
  1275. X                        (void) ioctl(ofd, I_FLUSH,
  1276. X                                 FLUSHW);
  1277. X                    }
  1278. X#endif /* USE_SUN */
  1279. X                    receiveport = atoi(buf+8);
  1280. X                    close(s);
  1281. X                    s = opensock("new data", localname,
  1282. X                             receiveport, remotename,
  1283. X                             SENDPORT, 0);
  1284. X                    if (mcastgrp)
  1285. X                        setmcast(s, mcastgrp);
  1286. X                    break;
  1287. X                case 'i':        /* Info */
  1288. X                    sprintf(buf, "radio:I:%d:%d:%s.%d",
  1289. X                        !pausing, receiveport,
  1290. X                        VERSION, PATCHLEVEL);
  1291. X                    sendto(curs, buf, strlen(buf), 0,
  1292. X                           &from, fromlen);
  1293. X                    break;
  1294. X#ifndef USE_NX /* XXX I don't know how to close_speaker() on the NeXT */
  1295. X                case 'p':        /* Pause */
  1296. X                case '0': /* Backward compatibility */
  1297. X                    if (!filter && !pausing) {
  1298. X                        close_speaker();
  1299. X                        pausing = 1;
  1300. X                    }
  1301. X                    break;
  1302. X                case 'c':        /* Continue */
  1303. X                case '1': /* Backward compatibility */
  1304. X                    if (pausing) {
  1305. X                        open_speaker();
  1306. X                        pausing = 0;
  1307. X                    }
  1308. X                    break;
  1309. X#endif /* USE_NX */
  1310. X                default:
  1311. X                    if (pdebug)
  1312. X                        fprintf(stderr,
  1313. X                          "radio: illegal cmd '%c'\n",
  1314. X                          buf[6]);
  1315. X                }
  1316. X            }
  1317. X            else if (pdebug) {
  1318. X                fprintf(stderr,
  1319. X                    "radio: ill-formatted command\n");
  1320. X            }
  1321. X        }
  1322. X        else if (!pausing) {
  1323. X            encoding = PCM_64;
  1324. X#ifdef USE_AL
  1325. X            curdatalinear = 0;
  1326. X#endif /* USE_AL */            
  1327. X            if ((buf[0]&0xff) == AUDIO_TYPE) {
  1328. X                encoding = buf[1]&0xff;
  1329. X                buf += HEADERSIZE;
  1330. X                n -= HEADERSIZE;
  1331. X            }
  1332. X            else {
  1333. X                if (pdebug)
  1334. X                    fprintf(stderr,
  1335. X                        "radio: non-IVS packet\n");
  1336. X                continue;
  1337. X            }
  1338. X            switch (encoding) {
  1339. X
  1340. X            case PCM_64:
  1341. X                break;
  1342. X
  1343. X            case ADPCM_32:
  1344. X                n = n*2;
  1345. X#ifdef USE_AL
  1346. X                /*
  1347. X                ** For SGI and non-filter mode, don't convert
  1348. X                ** via ulaw but straight to linear
  1349. X                */
  1350. X                if (!filter) {
  1351. X                    curdatalinear = 1;
  1352. X                    adpcm_decoder(buf, obuf, n,
  1353. X                              (struct adpcm_state *)0);
  1354. X                }
  1355. X                else
  1356. X#endif /* USE_AL */
  1357. X                {
  1358. X                    adpcm_ulaw_decoder(buf, tmp_buf, n,
  1359. X                           (struct adpcm_state *)0);
  1360. X                    buf = tmp_buf;
  1361. X                }
  1362. X                break;
  1363. X
  1364. X            case ADPCM_32_W_STATE:
  1365. X                state.valprev =
  1366. X                    ((buf[0]&0xff)<<8) | (buf[1]&0xff);
  1367. X                state.index = buf[2]&0xff;
  1368. X                buf += 3;
  1369. X                n -= 3;
  1370. X                n = n*2;
  1371. X#ifdef USE_AL                
  1372. X                if (!filter) {
  1373. X                    adpcm_decoder(buf, obuf, n, &state);
  1374. X                    curdatalinear = 1;
  1375. X                }
  1376. X                else
  1377. X#endif /* USE_AL */
  1378. X                {
  1379. X                    adpcm_ulaw_decoder(buf, tmp_buf, n,
  1380. X                               &state);
  1381. X                    buf = tmp_buf;
  1382. X                }
  1383. X                break;
  1384. X
  1385. X            default:
  1386. X                if (pdebug)
  1387. X                    fprintf(stderr,
  1388. X                        "radio: unknown encoding %d\n",
  1389. X                        encoding);
  1390. X                /* Ignore the package */
  1391. X                continue;
  1392. X
  1393. X            }
  1394. X#ifdef USE_AL
  1395. X            if (!filter) {
  1396. X                    if (!curdatalinear)
  1397. X                    for (i = 0; i < n; i++)
  1398. X                        obuf[i] =
  1399. X                        st_ulaw_to_linear(buf[i]&0xff);
  1400. X                ALwritesamps(aport, obuf, (long)n);
  1401. X            }
  1402. X#endif /* USE_AL */
  1403. X#ifdef USE_NX
  1404. X            if (!filter) {
  1405. X                int dummy;
  1406. X                char *ptr;
  1407. X                
  1408. X                (void) SNDGetDataPointer(snd[akt_buf], &ptr,
  1409. X                             &dummy, &dummy);
  1410. X                
  1411. X                SNDWait(akt_buf+1);
  1412. X                memcpy(ptr, buf, n);
  1413. X                snd[akt_buf] -> dataSize = n;
  1414. X                SNDStartPlaying(snd[akt_buf],
  1415. X                        akt_buf+1, 5, 0, 0, 0);
  1416. X                akt_buf = (akt_buf + 1) % NUM_BUFFER;
  1417. X            }
  1418. X#endif /* USE_NX */
  1419. X#ifdef USE_SUN
  1420. X            if (!filter) {
  1421. X                if (write(afd, buf, n) != n) {
  1422. X                    perror("write afd");
  1423. X                    break;
  1424. X                }
  1425. X            }
  1426. X#endif /* USE_SUN */
  1427. X            if (filter || tee) {
  1428. X                if (write(ofd, buf, n) != n) {
  1429. X                    perror("write ofd");
  1430. X                    break;
  1431. X                }
  1432. X            }
  1433. X        }
  1434. X        if (++packetcount > (30*SAMPLINGRATE / BUFFERSIZE)) {
  1435. X            checkalive();
  1436. X            packetcount = 0;
  1437. X        }
  1438. X    }
  1439. X
  1440. X    exit(0);
  1441. X}
  1442. X
  1443. X#ifdef USE_AL
  1444. X
  1445. void open_speaker()
  1446. X{
  1447. X    ALconfig config;
  1448. X    long pvbuf[6];
  1449. X    
  1450. X    /* Fetch the original state */
  1451. X    ALgetparams(AL_DEFAULT_DEVICE, savestate,
  1452. X            sizeof(savestate) / sizeof(long));
  1453. X    
  1454. X    /* Set signal handlers */
  1455. X    signal(SIGINT, cleanup_handler);
  1456. X    signal(SIGTERM, cleanup_handler);
  1457. X    
  1458. X    /* Set the output sampling rate */
  1459. X    pvbuf[0] = AL_OUTPUT_RATE;
  1460. X    pvbuf[1] = SAMPLINGRATE; /* XXX Assume AL_RATE_n is n */
  1461. X    
  1462. X    /* Maybe also set the volume */
  1463. X    if (volume >= 0) {
  1464. X        pvbuf[2] = AL_LEFT_SPEAKER_GAIN;
  1465. X        pvbuf[3] = volume*255/100;
  1466. X        pvbuf[4] = AL_RIGHT_SPEAKER_GAIN;
  1467. X        pvbuf[5] = volume*255/100;
  1468. X        ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 6L);
  1469. X    }
  1470. X    else
  1471. X        ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 2L);
  1472. X    
  1473. X    /* Configure and open an SGI audio port */
  1474. X    config = ALnewconfig();
  1475. X    ALsetchannels(config, AL_MONO);
  1476. X    ALsetwidth(config, AL_SAMPLE_16);
  1477. X    ALsetqueuesize(config, 16000); /* 2 seconds slop */
  1478. X    aport = ALopenport("radio", "w", config);
  1479. X    if (aport == NULL) {
  1480. X        perror("ALopenport");
  1481. X        exit(1);
  1482. X    }
  1483. X}
  1484. X
  1485. void close_speaker()
  1486. X{
  1487. X    ALcloseport(aport);
  1488. X    aport = NULL;
  1489. X}
  1490. X
  1491. void cleanup_handler(sig)
  1492. X    int sig;
  1493. X{
  1494. X    signal(sig, SIG_DFL);
  1495. X    if (!pausing) {/* Don't reset anything if we're pausing */
  1496. X        long n = sizeof(savestate) / sizeof(long);
  1497. X        if (volume < 0)
  1498. X            n -= 4; /* Don't reset volume if we didn't set it */
  1499. X        ALsetparams(AL_DEFAULT_DEVICE, savestate, n);
  1500. X    }
  1501. X    kill(getpid(), sig);
  1502. X}
  1503. X
  1504. X#endif /* USE_AL */
  1505. X
  1506. X
  1507. X#ifdef USE_SUN
  1508. X
  1509. void open_speaker()
  1510. X{    
  1511. X    audio_info_t info;
  1512. X
  1513. X    /* Write to AUDIO_IODEV */
  1514. X    if ((afd = open(AUDIO_IODEV, O_WRONLY)) < 0) {
  1515. X        perror(AUDIO_IODEV);
  1516. X        exit(1);
  1517. X    }
  1518. X
  1519. X    /* Set the volume */
  1520. X    if (volume >= 0) {
  1521. X        AUDIO_INITINFO(&info);
  1522. X        info.play.gain = (AUDIO_MAX_GAIN * volume) / 100;
  1523. X        if (ioctl(afd, AUDIO_SETINFO, &info))
  1524. X            perror("volume setting");
  1525. X    }
  1526. X
  1527. X    /* We need to open the audio control port to detect
  1528. X       if someone else wants to output to /dev/audio.
  1529. X       If this fails (e.g., in SunOS 4.0), print a message
  1530. X       but don't exit. */
  1531. X    if (interruptable) {
  1532. X        if ((actlfd = open(AUDIO_CTLDEV, O_RDWR)) < 0) {
  1533. X            perror(AUDIO_CTLDEV);
  1534. X        }
  1535. X        else if (ioctl(actlfd, I_SETSIG, S_MSG) < 0) {
  1536. X            perror("I_SETSIG");
  1537. X        }
  1538. X        else if (signal(SIGPOLL, sigpoll_handler) < 0) {
  1539. X            perror("signal(SIGPOLL)");
  1540. X            exit(1);
  1541. X        }
  1542. X    }
  1543. X}
  1544. X
  1545. void close_speaker()
  1546. X{
  1547. X    (void) ioctl(afd, I_FLUSH, FLUSHW);
  1548. X    close(afd);
  1549. X    close(actlfd);
  1550. X    afd = actlfd = -1;
  1551. X}
  1552. X
  1553. void sigpoll_handler()
  1554. X{
  1555. X    audio_info_t ap;
  1556. X
  1557. X    if (ioctl(actlfd, AUDIO_GETINFO, &ap) < 0) {
  1558. X        perror("AUDIO_GETINFO");
  1559. X    }
  1560. X    else if (ap.play.waiting) {
  1561. X        (void) ioctl(afd, I_FLUSH, FLUSHW);
  1562. X        close(afd);
  1563. X        /* The open() call blocks until we can use the device again */
  1564. X        if ((afd = open(AUDIO_IODEV, O_WRONLY)) < 0) {
  1565. X            perror(AUDIO_IODEV);
  1566. X            exit(1);
  1567. X        }
  1568. X        ap.play.waiting = 0;
  1569. X        if (ioctl(actlfd, AUDIO_SETINFO, &ap) < 0) {
  1570. X            perror("AUDIO_SETINFO");
  1571. X        }
  1572. X    }
  1573. X}
  1574. X
  1575. X#endif /* USE_SUN */
  1576. X
  1577. X
  1578. X#ifdef USE_NX
  1579. X
  1580. void open_speaker()
  1581. X{
  1582. X    int akt_buf;
  1583. X    int err;
  1584. X
  1585. X    /* Alloc NUM_BUFFER Sounds */
  1586. X    for (akt_buf = NUM_BUFFER; akt_buf > 0; akt_buf--) {
  1587. X        if (err = SNDAlloc(&snd[akt_buf-1], BUFFERSIZE,
  1588. X                   SND_FORMAT_MULAW_8,
  1589. X                   SND_RATE_CODEC, 1, 4)) {
  1590. X            fprintf(stderr, "init: %s\n", SNDSoundError(err));
  1591. X            exit(1);
  1592. X        }
  1593. X    }
  1594. X    akt_buf = 0;
  1595. X}
  1596. X
  1597. void close_speaker()
  1598. X{
  1599. X    /* XXX how to do this? */
  1600. X}
  1601. X
  1602. X#endif /* USE_NX */
  1603. X
  1604. X
  1605. void checkalive()
  1606. X{
  1607. X#ifdef CHECK_X_SERVER
  1608. X    if (xdisplay) {
  1609. X        Window focus;
  1610. X        int revert_to;
  1611. X        if (pdebug)
  1612. X            fprintf(stderr, "polling X server...\n");
  1613. X        /* Do a simple X request that needs a server round trip...
  1614. X           The error handler will kill us when the server is dead,
  1615. X           so that radio dies when the user logs out. */
  1616. X        XGetInputFocus(xdisplay, &focus, &revert_to);
  1617. X        if (pdebug)
  1618. X            fprintf(stderr, "X server OK\n");
  1619. X    }
  1620. X    else if (pdebug)
  1621. X        fprintf(stderr, "checkalive() is a no-op\n");
  1622. X#endif /* CHECK_X_SERVER */
  1623. X}
  1624. X
  1625. void setmcast(s, group)
  1626. X    int s;
  1627. X    char *group;
  1628. X{
  1629. X#ifdef HAVE_MCAST
  1630. X    struct hostent *hostentry;
  1631. X    struct in_addr grpaddr;
  1632. X    struct in_addr ifaddr;
  1633. X    struct ip_mreq mreq;
  1634. X
  1635. X    if (hostentry = gethostbyname(group))
  1636. X    {
  1637. X        bcopy(hostentry->h_addr, &grpaddr.s_addr, sizeof(grpaddr.s_addr));
  1638. X    }
  1639. X    else
  1640. X        grpaddr.s_addr = inet_addr(group);
  1641. X
  1642. X    if (!IN_MULTICAST(grpaddr.s_addr)) {
  1643. X        fprintf(stderr, "Bad multicast group: %s\n", group);
  1644. X        exit(1);
  1645. X    }
  1646. X    
  1647. X    ifaddr.s_addr = htonl(INADDR_ANY);
  1648. X    
  1649. X    mreq.imr_multiaddr = grpaddr;
  1650. X    mreq.imr_interface = ifaddr;
  1651. X    if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
  1652. X               &mreq, sizeof(mreq)) < 0) {
  1653. X        perror("setsockopt mreq");
  1654. X        exit(1);
  1655. X    }
  1656. X#endif /* HAVE_MCAST */
  1657. X}
  1658. END_OF_FILE
  1659. if test 16417 -ne `wc -c <'radio.c'`; then
  1660.     echo shar: \"'radio.c'\" unpacked with wrong size!
  1661. fi
  1662. # end of 'radio.c'
  1663. fi
  1664. echo shar: End of archive 2 \(of 2\).
  1665. cp /dev/null ark2isdone
  1666. MISSING=""
  1667. for I in 1 2 ; do
  1668.     if test ! -f ark${I}isdone ; then
  1669.     MISSING="${MISSING} ${I}"
  1670.     fi
  1671. done
  1672. if test "${MISSING}" = "" ; then
  1673.     echo You have unpacked both archives.
  1674.     rm -f ark[1-9]isdone
  1675. else
  1676.     echo You still need to unpack the following archives:
  1677.     echo "        " ${MISSING}
  1678. fi
  1679. ##  End of shell archive.
  1680. exit 0
  1681.