This is radio.c in view mode; [Download] [Up]
/*********************************************************** Copyright 1991 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. ******************************************************************/ /* Receive audio UDP packets transmitted by broadcast. Command line options: -p port tune to this port number (default 54321) (port numbers 1..99 are shorthands for 54321 and up) -v volume output volume (range 0-100; default unchanged) -c port use this control port (default 54320) -s 'secure' mode: don't listen to the control port -f work as a filter: send output to stdout instead of directly to the audio hardware -l addr listen only for packets to <arg> ip address -r addr listen only for packets from <arg> -d debug packets -n noninterruptable -- by default radio will be interruptable by other sound outputting programs, hoping they do not take too long. This option turns off that feature. */ #define BCASTCTLPORT 54319 #define RADIOCTLPORT 54320 #define RCVPORT 54321 #define SENDPORT 54318 #define BUFFERSIZE 1400 #define CTLPKTSIZE 100 #ifdef sgi #define USE_AL #endif #ifdef sun #define USE_SUN #endif #ifdef NeXT #define USE_NX #endif #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <fcntl.h> #include <signal.h> #include <netdb.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <netinet/in.h> #ifdef USE_AL #include <audio.h> #include "libst.h" long savestate[] = { AL_OUTPUT_RATE, 0, AL_LEFT_SPEAKER_GAIN, 0, AL_RIGHT_SPEAKER_GAIN, 0, }; #endif #ifdef USE_SUN #include <stropts.h> #include <sun/audioio.h> #define AUDIO_IODEV "/dev/audio" #define AUDIO_CTLDEV "/dev/audioctl" int interruptable = 1; int actlfd = -1; #endif #ifdef USE_NX #include <sound/sound.h> #define NUM_BUFFER 10 #endif /* getopt() interface */ extern int optind; extern char * optarg; /* Forward */ void sigpoll_handler(); void cleanup_handler(); /* Globals */ int ofd; /* Output file descriptor */ main(argc, argv) int argc; char **argv; { int receiveport = RCVPORT; int ctlport = RADIOCTLPORT; char buf[BUFFERSIZE]; int s, ctls, curs; struct sockaddr from; int fromlen; int c; int filter = 0; int nfds; fd_set inputset; int n; int pdebug = 0; char *localname = (char *) NULL; char *remotename = (char *) NULL; int volume = -1; #ifdef USE_SUN audio_info_t info; #endif #ifdef USE_AL short obuf[BUFFERSIZE]; ALport aport; ALconfig config; int i; long pvbuf[6]; #endif #ifdef USE_NX int err; SNDSoundStruct *snd[NUM_BUFFER]; int akt_buf; #endif /* Always change these two macros together! */ #define OPTIONS "c:dfl:np:r:sv:" #define USAGE "usage: %s [-d] [-f] [-n] [-s] [-p port] [-v volume(0-100)] [-c ctlport] [-l localhost] [-r remotehost]\n" while ((c = getopt(argc, argv, OPTIONS)) != EOF) { switch (c) { case '?': fprintf(stderr, USAGE, argv[0]); exit(2); case 'p': receiveport = atoi(optarg); if (0 < receiveport && receiveport < 100) receiveport += RCVPORT-1; break; case 'c': ctlport = atoi(optarg); break; case 'l': localname = optarg; break; case 'r': remotename = optarg; break; case 'd': pdebug = 1; break; #ifdef USE_SUN case 'n': interruptable = 0; break; #endif case 's': ctlport = -1; break; case 'f': filter = 1; break; case 'v': volume = atoi(optarg); break; } } if (filter) { ofd = fileno(stdout); } else { #ifdef USE_AL /* Fetch the original state */ ALgetparams(AL_DEFAULT_DEVICE, savestate, sizeof(savestate) / sizeof(long)); /* Set signal handlers */ signal(SIGINT, cleanup_handler); signal(SIGTERM, cleanup_handler); /* Set the device to 8000 Hz */ pvbuf[0] = AL_OUTPUT_RATE; pvbuf[1] = AL_RATE_8000; /* Maybe also set the volume */ if (volume >= 0) { pvbuf[2] = AL_LEFT_SPEAKER_GAIN; pvbuf[3] = volume*255/100; pvbuf[4] = AL_RIGHT_SPEAKER_GAIN; pvbuf[5] = volume*255/100; ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 6L); } else ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 2L); /* Configure and open an SGI audio port */ config = ALnewconfig(); ALsetchannels(config, AL_MONO); ALsetwidth(config, AL_SAMPLE_16); ALsetqueuesize(config, 16000); /* 2 seconds slop */ aport = ALopenport("radio", "w", config); if (aport == NULL) { perror("ALopenport"); exit(1); } #endif #ifdef USE_SUN /* Write to AUDIO_IODEV */ if ((ofd = open(AUDIO_IODEV, O_WRONLY)) < 0) { perror(AUDIO_IODEV); exit(1); } /* Set the volume */ if (volume >= 0) { AUDIO_INITINFO(&info); info.play.gain = (AUDIO_MAX_GAIN * volume) / 100; if (ioctl(ofd, AUDIO_SETINFO, &info)) perror("volume setting"); } /* We need to open the audio control port to detect if someone else wants to output to /dev/audio. If this fails (e.g., in SunOS 4.0), print a message but don't exit. */ if (interruptable) { if ((actlfd = open(AUDIO_CTLDEV, O_RDWR)) < 0) { perror(AUDIO_CTLDEV); } else if (ioctl(actlfd, I_SETSIG, S_MSG) < 0) { perror("I_SETSIG"); } else if (signal(SIGPOLL, sigpoll_handler) < 0) { perror("signal(SIGPOLL)"); exit(1); } } #endif #ifdef USE_NX /* Alloc NUM_BUFFER Sounds */ for( akt_buf = NUM_BUFFER; akt_buf > 0; akt_buf--) { if (err = SNDAlloc(&snd[akt_buf-1], BUFFERSIZE, SND_FORMAT_MULAW_8, SND_RATE_CODEC, 1, 4)) { fprintf(stderr, "init: %s\n", SNDSoundError(err)); } } akt_buf = 0; #endif } if (ctlport >= 0) ctls = opensock("control", (char *)NULL, ctlport, (char *)NULL, 0, 0); else ctls = -1; s = opensock("data", localname, receiveport, remotename, SENDPORT, 0); for (;;) { /* ** Wait until one of the sockets becomes ready */ nfds = (s > ctls ? s : ctls) + 1; FD_ZERO(&inputset); FD_SET(s, &inputset); if (ctls >= 0) FD_SET(ctls, &inputset); while (select(nfds, &inputset, 0, 0, 0) < 1) { if(errno != EINTR) { perror("select"); exit(1); } } if (ctls >= 0 && FD_ISSET(ctls, &inputset)) curs = ctls; else if (FD_ISSET(s, &inputset)) curs = s; /* ** Read, and check for control packet */ fromlen = sizeof(from); n = recvfrom(curs, buf, BUFFERSIZE, 0, &from, &fromlen); if (n <= 0) { if (n == 0) continue; /* Ignore empty packets */ perror("read"); break; } if (pdebug) { if(pdebug == 8) { fprintf(stderr, "8 packets received\n"); pdebug = 1; } else pdebug++; } if ( n <= CTLPKTSIZE ) { /* ** It looks like a control packet. Check it. */ if (strncmp(buf, "radio:", 6) == 0) { if (pdebug) fprintf(stderr, "control packet\n"); switch(buf[6]) { case 'e': /* Echo */ buf[6] = 'E'; sendto(curs, buf, n, 0, &from, fromlen); break; case 't': /* Tune */ if (curs != ctls) { if (pdebug) fprintf(stderr, "radio: illegal tune\n"); break; } #ifdef USE_SUN if (!filter) { (void) ioctl(ofd, I_FLUSH, FLUSHW); } #endif buf[n] = '\0'; receiveport = atoi(buf+8); close(s); s = opensock("new data", localname, receiveport, remotename, SENDPORT, 0); break; case 'i': /* Info */ sprintf(buf, "radio:I:%d", receiveport); sendto(curs, buf, strlen(buf), 0, &from, fromlen); break; default: if (pdebug) fprintf(stderr, "radio: illegal cmd 0x%x\n", buf[6]); } } else if (pdebug) { fprintf(stderr, "radio: ill-formatted command\n"); } } else { #ifdef USE_AL if (!filter) { for (i = 0; i < n; i++) obuf[i] = st_ulaw_to_linear(buf[i]); ALwritesamps(aport, obuf, (long)n); } else #endif #ifdef USE_NX if (!filter) { int dummy; char *ptr; (void) SNDGetDataPointer(snd[akt_buf], &ptr, &dummy, &dummy); SNDWait( akt_buf+1); memcpy( ptr, buf, n); snd[akt_buf] -> dataSize = n; SNDStartPlaying(snd[akt_buf],akt_buf+1,5,0,0,0 ); akt_buf = ( akt_buf + 1) % NUM_BUFFER; } else #endif if (write(ofd, buf, n) != n) { perror("write"); break; } } } exit(0); } #ifdef USE_SUN void sigpoll_handler() { audio_info_t ap; if (ioctl(actlfd, AUDIO_GETINFO, &ap) < 0) { perror("AUDIO_GETINFO"); } if (ap.play.waiting) { close(ofd); if ((ofd = open(AUDIO_IODEV, O_WRONLY)) < 0) { perror(AUDIO_IODEV); exit(1); } ap.play.waiting = 0; if (ioctl(actlfd, AUDIO_SETINFO, &ap) < 0) { perror("AUDIO_SETINFO"); } } } #endif /*USE_SUN*/ #ifdef USE_AL void cleanup_handler(sig) int sig; { signal(sig, SIG_DFL); ALsetparams(AL_DEFAULT_DEVICE, savestate, sizeof(savestate) / sizeof(long)); kill(getpid(), sig); } #endif /* USE_AL */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.