home *** CD-ROM | disk | FTP | other *** search
- /***********************************************************
- Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The
- Netherlands.
-
- All Rights Reserved
-
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation, and that the names of Stichting Mathematisch
- Centrum or CWI not be used in advertising or publicity pertaining to
- distribution of the software without specific, written prior permission.
-
- STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
- THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
- FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ******************************************************************/
-
- /* Broadcast audio packets over UDP.
- Standard input should be an audio source, e.g. /dev/audio
- (on a Sun) or a pipe from a program generating audio, e.g.
- recordulaw or cdsend (on an SGI Indigo). Default input format is
- 8-bit U-LAW; use -l to read 16-bit linear instead (all mono 8000
- samples/sec).
-
- Command line options:
-
- -a ADPCM encoding -- half the data, slightly worse sound
- -A ADPCM encoding without state, even worse sound
- -b ipaddr IP address to broadcast to; may be repeated
- (default broadcast on local net)
- -c port listen to this control port (default 54319)
- -d debug output
- -l take linear input (signed shorts in native byte order)
- -m ttl Multicast TTL (0 host, 1 subnet, 32 site, 64 region)
- -n no silence detection
- -p port broadcast to this port number (default 54321)
- -t time output; use when input is faster than realtime
- (e.g., read from a file file)
- -N name station name (default your username)
- -L file log file (default /ufs/<username>/CDlog)
- -P file program file (default /ufs/<username>/CD)
- */
-
- #include "radio.h"
- #include "adpcm.h"
-
- #include <stdio.h>
- #include <errno.h>
- #include <stdlib.h>
- #include <fcntl.h>
-
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netdb.h>
- #include <sys/time.h>
- #include <sys/stat.h>
-
- extern long time();
-
- #ifdef SUNHACKS
- #include <sys/sockio.h> /* For SIOCGIF* */
- #include <net/if.h> /* For struct if* */
- #endif
-
- #ifdef REMHDR
- #include <multimedia/libaudio.h>
- #include <multimedia/audio_filehdr.h>
- #endif
-
- #ifdef NeXT
- #include <sound/sound.h>
- #endif
-
- #ifdef __sgi
- #include <limits.h>
- #include <sys/prctl.h>
- #include <sys/schedctl.h>
- #endif
-
- extern int optind;
- extern char * optarg;
-
- char *progname;
- char infostring[CTLPKTSIZE];
- struct timeval zerotime;
- struct timeval tstart;
- int pdebug = 0;
-
- #define NBCADDR 10 /* Max number of broadcast addresses */
- int nbcaddr = 0; /* Number of broadcast address options */
- struct sockaddr_in bcaddr[NBCADDR]; /* Broadcast addresses */
- struct sockaddr_in infoaddr[NBCADDR]; /* Ditto for info messages */
-
- int port = RCVPORT;
- char *name = 0;
- char *logfile = 0;
- char *programfile = 0;
- char *user;
- char *home;
-
- long packetcount = 0;
- int transmitting = 1;
- int encoding = PCM_64;
-
- char *
- whoami()
- {
- char *user = getenv("LOGNAME");
- if (user == NULL) {
- user = getenv("USER");
- if (user == NULL)
- user = "???";
- /* XXX should use getpwbyuid(getuid) if HOME missing */
- }
- return user;
- }
-
- char *
- whereami()
- {
- return getenv("HOME");
- /* XXX should use getpwbyname(user) if HOME missing */
- }
-
- int
- makeinfo()
- {
- FILE *fp;
- int n;
- struct stat s;
- long age;
-
- if (stat(programfile, &s) >= 0)
- age = time((long*)0) - s.st_mtime;
- else
- age = -1;
- sprintf(infostring, "radio:S:%s:%d:%d:%s:%ld:",
- name, port, transmitting, logfile, age);
- n = strlen(infostring);
- fp = fopen(programfile, "r");
- if (fp != NULL) {
- fgets(infostring + n, sizeof infostring - n, fp);
- fclose(fp);
- n = strlen(infostring);
- if (infostring[n-1] == '\n')
- infostring[--n] = '\0';
- }
- return n;
- }
-
- void
- sendinfo(s, addr, addrsize)
- int s; /* Socket */
- struct sockaddr *addr;
- int addrsize;
- {
- int n = makeinfo();
- if (sendto(s, infostring, n, 0, addr, addrsize) < 0)
- perror("sendto in sendinfo");
- }
-
- main(argc, argv)
- int argc;
- char **argv;
- {
- char *broadcastaddr = NULL;
- char real_buf[HEADERSIZE + 3 + BUFFERSIZE];
- char tmp_buf[BUFFERSIZE];
- short lin_buf[BUFFERSIZE];
- char *buf;
- int on = 1;
- int i, n;
- int s, ctls;
- int c;
- int timing = 0;
- fd_set inputav;
- struct sockaddr_in locsin;
- struct sockaddr_in ctlsin;
- int ctlsinsize;
- int ctlport = BCASTCTLPORT;
- int noisy = 0;
- int linear = 0;
- struct adpcm_state state;
- #ifdef HAVE_MCAST
- u_char ttl = MULTICAST_TTL;
- #endif
-
- #ifdef __sgi
- (void) schedctl(NDPRI, 0, NDPNORMMAX);
- setuid(getuid());
- #endif
-
- progname = argv[0];
-
- /* Always change these two macros and the following switch together! */
- #define OPTIONS "Aab:c:dlm:np:tL:N:P:"
- #define USAGE \
- "usage: %s [-A] [-a] [-b broadcastaddr] ... [-c ctlport] [-d] [-l]\n\
- \t[-m ttl] [-n] [-p port] [-t]\n\t[-N name] [-L logfile] [-P programfile]\n"
-
- while ((c = getopt(argc, argv, OPTIONS)) != EOF) {
- switch (c) {
- default:
- case '?':
- fprintf(stderr, USAGE, progname);
- exit(2);
- case 'A':
- encoding = ADPCM_32;
- break;
- case 'a':
- encoding = ADPCM_32_W_STATE;
- break;
- case 'b':
- if (nbcaddr >= NBCADDR) {
- fprintf(stderr,
- "%s: too many -b options (max %d)\n",
- progname, NBCADDR);
- exit(2);
- }
- if (setipaddr(optarg, &bcaddr[nbcaddr]) < 0) {
- fprintf(stderr,
- "%s: bad broadcast address '%s'\n",
- progname, broadcastaddr);
- exit(2);
- }
- nbcaddr++;
- break;
- case 'c':
- ctlport = atoi(optarg);
- break;
- case 'd':
- pdebug = 1;
- break;
- case 'l':
- linear = 1;
- break;
- case 'm':
- #ifdef HAVE_MCAST
- ttl = atoi(optarg);
- #else
- fprintf(stderr, "(-m not supported here)\n");
- #endif
- break;
- case 'n':
- noisy = 1;
- break;
- case 'p':
- port = atoi(optarg);
- break;
- case 't':
- timing = 1;
- break;
- case 'L':
- logfile = optarg;
- break;
- case 'N':
- name = optarg;
- break;
- case 'P':
- programfile = optarg;
- break;
- }
- }
-
- user = whoami();
- home = whereami();
-
- if (logfile == 0) {
- static char logbuf[100];
- sprintf(logbuf, "%s/.CDlog", home);
- logfile = logbuf;
- }
- if (name == 0)
- name = user;
- if (programfile == 0) {
- static char programbuf[100];
- sprintf(programbuf, "%s/.CD", home);
- programfile = programbuf;
- }
-
- s = opensock("data", (char *)NULL, SENDPORT, (char *)NULL, 0, 1);
-
- if (nbcaddr == 0) {
- #if defined(HAVE_MCAST) && defined (DEFMCAST)
- if (setipaddr(DEFMCAST, &bcaddr[nbcaddr]) < 0) {
- fprintf(stderr,
- "%s: bad broadcast address '%s'\n",
- progname, broadcastaddr);
- exit(2);
- }
- #else
- configure(s, &bcaddr[0]);
- #endif
- nbcaddr = 1;
- }
-
- for (i = 0; i < nbcaddr; i++) {
- bcaddr[i].sin_port = htons(port);
- bcaddr[i].sin_family = AF_INET;
- infoaddr[i] = bcaddr[i];
- infoaddr[i].sin_port = htons(INFOPORT);
- }
-
- #ifdef HAVE_MCAST
- if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
- perror("mcast ttl");
- #endif
-
- ctls = opensock("control", (char *)NULL, ctlport, (char *)NULL, 0, 0);
-
- if(timing) {
- if (!linear) {
- #ifdef REMHDR
- Audio_hdr hp;
- (void) audio_read_filehdr(0, &hp, NULL, NULL);
- #endif
- #ifdef NeXT
- SNDSoundStruct s;
- (void) fread((void *)&s, sizeof(SNDSoundStruct), 1,
- stdin);
- #endif
- }
- gettimeofday(&tstart, 0);
- }
-
- real_buf[0] = AUDIO_TYPE;
- real_buf[1] = encoding;
-
- state.valprev = 0;
- state.index = 0;
-
- for (;;) {
- if (linear) {
- n = fread(lin_buf, sizeof(short), BUFFERSIZE, stdin);
- buf = real_buf + HEADERSIZE;
- }
- else {
- if (encoding == PCM_64)
- buf = real_buf + HEADERSIZE;
- else
- buf = tmp_buf;
- n = fread(buf, 1, BUFFERSIZE, stdin);
- }
- if (n <= 0) {
- if (n < 0)
- perror("fread");
- break;
- }
- if(timing)
- waiting(SAMPLINGRATE, BUFFERSIZE);
- if (!linear && !noisy && silent(buf, n)) {
- if (transmitting) {
- if (pdebug)
- fprintf(stderr, "start silence\n");
- transmitting = 0;
- }
- }
- else {
- if (!transmitting) {
- if (pdebug)
- fprintf(stderr, "end silence\n");
- packetcount = 0;
- transmitting = 1;
- }
- switch (encoding) {
- case PCM_64:
- if (linear) {
- for (i = 0; i < n; i++) {
- buf[i] = st_linear_to_ulaw(
- lin_buf[i]);
- }
- }
- break;
- case ADPCM_32:
- buf = real_buf + HEADERSIZE;
- if (linear)
- adpcm_coder(lin_buf, buf, n,
- (struct adpcm_state *)0);
- else
- ulaw_adpcm_coder(tmp_buf, buf, n,
- (struct adpcm_state *)0);
- n = (n+1)/2;
- break;
- case ADPCM_32_W_STATE:
- buf = real_buf + HEADERSIZE;
- *buf++ = (state.valprev>>8) & 0xff;
- *buf++ = state.valprev & 0xff;
- *buf++ = state.index;
- if (linear)
- adpcm_coder(lin_buf, buf, n, &state);
- else
- ulaw_adpcm_coder(tmp_buf, buf, n,
- &state);
- n = (n+1)/2 + 3;
- break;
- }
- for (i = 0; i < nbcaddr; i++) {
- /* Send data packets to all bcast ports */
- if (sendto(s, real_buf, HEADERSIZE+n, 0,
- &bcaddr[i], sizeof bcaddr[i]) !=
- HEADERSIZE+n) {
- perror("sendto");
- }
- }
- if (packetcount % INFOFREQ == 0) {
- /* Send info packets to all info ports
- and to all bcast ports */
- if (pdebug)
- fprintf(stderr, "sending info\n");
- for (i = 0; i < nbcaddr; i++) {
- sendinfo(s, &infoaddr[i],
- sizeof infoaddr[i]);
- sendinfo(s, &bcaddr[i],
- sizeof bcaddr[i]);
- }
- }
- if (pdebug) {
- if(packetcount % 8 == 0) {
- fprintf(stderr, "%ld packets sent\n",
- packetcount);
- }
- }
- packetcount++;
- }
- if (ctls >= 0) {
- FD_ZERO(&inputav);
- FD_SET(ctls, &inputav);
- if (select(ctls+1, &inputav, 0, 0, &zerotime) == 1) {
- ctlsinsize = sizeof(ctlsin);
- n = recvfrom(ctls, buf, BUFFERSIZE, 0,
- &ctlsin, &ctlsinsize);
- if (n < 0) {
- perror("recvfrom");
- exit(1);
- }
- if (n >= 7 &&
- strncmp(buf, "radio:s", 7) == 0) {
- sendinfo(ctls, &ctlsin, ctlsinsize);
- }
- else {
- fprintf(stderr,
- "%s: Funny ctl message\n",
- progname);
- }
- }
- }
- }
-
- exit(0);
- }
-
- configure(s, addr_ret)
- int s;
- struct sockaddr_in *addr_ret;
- {
- #ifdef SUNHACKS
- char buf[BUFSIZ];
- struct ifconf ifc;
- struct ifreq ifreq;
-
- ifc.ifc_len = sizeof(buf);
- ifc.ifc_buf = buf;
- if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
- perror("ioctl SIOCGIFCONF");
- exit(1);
- }
- ifreq = *ifc.ifc_req;
- if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
- perror("ioctl SIOCGIFBRDADDR");
- exit(1);
- }
- * (struct sockaddr *) addr_ret = ifreq.ifr_broadaddr;
- #else
- addr_ret->sin_addr.s_addr = INADDR_BROADCAST;
- #endif
- }
-
- /*
- * routine to sleep between consecutive packets
- */
-
- waiting(rate, data)
- int rate;
- int data;
- {
- static int bytes = 0; /* packets already sent */
-
- struct timeval tnow;
- int tsleep;
-
- bytes += data;
- gettimeofday(&tnow, 0);
-
- tsleep = ((double) bytes/(double) rate) * 1000000
- - ((tnow.tv_sec - tstart.tv_sec) * 1000000
- + tnow.tv_usec - tstart.tv_usec);
- if (tsleep > 0) {
- struct timeval t;
-
- t.tv_sec = tsleep / 1000000;
- t.tv_usec = tsleep % 1000000;
- (void) select(0, NULL, NULL, NULL, &t);
- }
- }
-
- /*
- * Silence detection.
- * You may have to play with these parameters.
- * Our input is rather noisy, hence we have a rather high threshold.
- */
-
- #define DEADTIME (20*SAMPLINGRATE) /* After this much silence we cut off */
- #define THRESHOLD 75 /* Max silent U-LAW value (after normalization) */
-
- silent(buf, n)
- register char *buf;
- register int n;
- {
- static int dead = DEADTIME; /* State */
- register int abs;
-
- dead += n;
- while (--n >= 0) {
- abs = 127 - ((*buf++) & 127);
- if (abs > THRESHOLD) {
- dead = 0;
- return 0;
- }
- }
- return (dead > DEADTIME);
- }
-