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.
-
- ******************************************************************/
-
- /* $Id: cdsend.c,v 1.2 1993/01/18 10:02:47 sjoerd Exp $ */
-
- /*
- * cdsend reads audio CD's over the SCSI bus, converts it to a format
- * suitable for broadcast, and writes this converted data to standard
- * output. Optionally, the msuic is also played over the system's own
- * speakers.
- *
- * Options.
- * -n use non-degradable priority for the program (works
- * only if installed set-uid root). The default is to
- * not change the priority.
- * -d daemon mode. When a CD finishes, hang around until
- * the next CD is put in the CD player and play it. The
- * default is to exit after playing one CD.
- * -p play the music over the system's speakers. Default is
- * to not play the music.
- * -l convert the data to 2-byte-per-sample linear format.
- * Default is to convert to 1-byte-per-sample U-law.
- * -c file use the specified file to write the CD's
- * identification to. Default is to write to the file
- * $HOME/.CDcatalognumber.
- */
-
- #include "cdsend.h"
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <signal.h>
- #include <limits.h>
- #include <sys/prctl.h>
- #include <sys/schedctl.h>
- #include <audio.h>
- #include <fcntl.h>
-
- static ALport port; /* audio output port */
- static int playaudio; /* 1 iff we changed output rate */
- static volatile int silent = 1; /* 1 iff we must be quiet */
- static volatile int stop_playing; /* 1 if we must stop playing */
- static int linear = 0; /* 1 iff we produce linear (2-byte) output */
- static long oldparams[2] = {AL_OUTPUT_RATE, 0};
- static long newparams[2] = {AL_OUTPUT_RATE, AL_RATE_44100};
- static char *cdtoc, *cdid;
- static char cdcatnamebuf[1024];
- static char *cdcatname = cdcatnamebuf;
- extern char *db_get_TOC(CDPLAYER *, CDSTATUS *);
- extern char *db_get_id(CDPLAYER *, CDSTATUS *);
- extern char *optarg;
-
- /* newer libraries use CDaddcallback and have a backward compatibility */
- /* define for CDsetcallback, we do it the other way round */
- #ifndef CDsetcallback
- #define CDaddcallback CDsetcallback
- #endif
-
- #define DEFCDCATNAME ".CDcatalognumber"
-
- /*
- * Called when the program is interrupted. This means that the audio
- * params have to be reset, but only if we've changed them.
- */
- static void
- die(int sig)
- {
- if (playaudio)
- ALsetparams(AL_DEFAULT_DEVICE, oldparams, 2L);
- exit(sig);
- }
-
- /*
- * Called when we get a SIGHUP. This means that we must switch from
- * playing the audio to being silent or vv.
- */
- static void
- toggle(void)
- {
- silent = !silent;
- }
-
- /*
- * Called when we get a SIGUSR1. This means we have to stop reading
- * the CD (and eject it). This is useful if the CD player is needed
- * for official business.
- */
- static void
- eject(void)
- {
- stop_playing = 1;
- }
-
- /*
- * Callback routine, called to do something to the audio data.
- */
- static void
- handleaudio(void *arg, CDDATATYPES type, short *audio)
- {
- if (!playaudio && !silent) {
- /* we were silent but want to start playing, so set */
- /* audio params */
- ALgetparams(AL_DEFAULT_DEVICE, oldparams, 2L);
- ALsetparams(AL_DEFAULT_DEVICE, newparams, 2L);
- playaudio = 1;
- }
- /* play the audio, but only if enough space in output port */
- if (playaudio && ALgetfillable(port) >= CDDA_NUMSAMPLES)
- ALwritesamps(port, audio, CDDA_NUMSAMPLES);
- if (playaudio && silent) {
- /* we were playing but want to be silent now, so reset */
- /* audio params */
- ALsetparams(AL_DEFAULT_DEVICE, oldparams, 2L);
- playaudio = 0;
- }
-
- /* actually do the work we're being paid for */
- convert_audio_and_print(audio, CDDA_NUMSAMPLES / 2, linear);
- }
-
- /*
- * Callback routine, called when the CD contains a catalog number.
- * This routine writes the catalog number and the table of contents to
- * a file. Other programs can use this information to display the
- * title of the CD being played.
- */
- static void
- handlecatalog(void *arg, CDDATATYPES type, char *data)
- {
- int i;
- FILE *fp;
-
- for (i = 0; i < 13; i++)
- if (data[i] != 0)
- break;
- if (i == 13) /* catalog # is null, so ignore it */
- return;
-
- if ((fp = fopen(cdcatname, "w")) == NULL)
- return;
- fprintf(fp, "hash=%s\n", cdid);
- fprintf(fp, "toc=%s\n", cdtoc);
- fprintf(fp, "catalog=");
- for (i = 0; i < 13; i++)
- fprintf(fp, "%c", *data++ + '0');
- fprintf(fp, "\n");
- fclose(fp);
- }
-
- /*
- * This routine is called to write identification information in the
- * .CDcatalognumber file. If there is a catalog number on the CD,
- * this information is overwritten, but if there is no catalog number
- * on the CD, the information written here can be used.
- */
- static void
- nocatalog(CDSTATUS *cdstatus)
- {
- FILE *fp;
-
- if ((fp = fopen(cdcatname, "w")) == NULL)
- return;
- fprintf(fp, "hash=%s\n", cdid);
- fprintf(fp, "toc=%s\n", cdtoc);
- fprintf(fp, "tmsf=%d.%d.%d.%d\n", cdstatus->last, cdstatus->total_min,
- cdstatus->total_sec, cdstatus->total_frame);
- fclose(fp);
- }
-
- /*
- * Wait for an audio CD to be inserted into the player.
- */
- static void
- waitforcd(void)
- {
- CDPLAYER *cdp;
- CDSTATUS status;
-
- for (;;) {
- for (;;) {
- if ((cdp = CDopen(0, 0)) != 0)
- break;
- /* opening the CD player failed; wait a while */
- /* and try again */
- sginap(60);
- }
-
- /* opening the CD player succeeded; now wait until the */
- /* player is ready */
- for (;;) {
- if (!CDgetstatus(cdp, &status)) {
- CDclose(cdp);
- break;
- }
- if (status.state == CD_READY) {
- if (!status.scsi_audio) {
- fprintf(stderr, "cdsend: CD-ROM player does not support audio CD's\n");
- CDclose(cdp);
- exit(1);
- }
- CDclose(cdp);
- return;
- }
- sginap(60);
- }
- sginap(60);
- }
- }
-
- /*
- * This routine reads one whole CD and when it is finished, it ejects
- * the CD.
- */
- static void
- play(void)
- {
- CDPLAYER *cdp;
- CDPARSER *parser;
- CDFRAME buf[12];
- CDSTATUS cdstatus;
- FILE *fd;
- int i, n, first = 1;
- ALconfig c;
-
- waitforcd();
-
- stop_playing = 0;
-
- cdp = CDopen(0, 0);
- if (cdp == 0)
- return;
-
- CDgetstatus(cdp, &cdstatus);
- if (cdtoc)
- free(cdtoc);
- if (cdid)
- free(cdid);
- cdtoc = db_get_TOC(cdp, &cdstatus);
- cdid = db_get_id(cdp, &cdstatus);
-
- nocatalog(&cdstatus);
-
- if ((parser = CDcreateparser()) == 0) {
- perror("CDcreateparser");
- exit(1);
- }
-
- ALgetparams(AL_DEFAULT_DEVICE, oldparams, 2L);
- c = ALnewconfig();
- ALsetwidth(c, AL_SAMPLE_16);
- ALsetchannels(c, AL_STEREO);
- port = ALopenport("cd", "w", c);
-
- CDaddcallback(parser, cd_audio, (CDCALLBACKFUNC) handleaudio, 0);
- CDaddcallback(parser, cd_catalog, (CDCALLBACKFUNC) handlecatalog, 0);
-
- init_convert();
-
- while (!stop_playing) {
- n = CDreadda(cdp, buf, 12);
- if (first && n == 0) {
- /* apparantly not an audio CD */
- CDclose(cdp);
- ALcloseport(port);
- ALfreeconfig(c);
- close(creat(cdcatname, 0666));
- sginap(300);
- return;
- }
- first = 0;
- if (n < 0) {
- perror("CDreadda");
- exit(1);
- }
- if (n == 0)
- break;
-
- for (i = 0; i < n && !stop_playing; i++)
- CDparseframe(parser, &buf[i]);
- }
-
- if (playaudio) {
- ALsetparams(AL_DEFAULT_DEVICE, oldparams, 2L);
- playaudio = 0;
- }
-
- CDeject(cdp);
- CDdeleteparser(parser);
- CDclose(cdp);
- ALcloseport(port);
- ALfreeconfig(c);
- close(creat(cdcatname, 0666));
- }
-
- main(int argc, char **argv)
- {
- int c;
- int daemon = 0;
-
- sprintf(cdcatname, "%s/%s", getenv("HOME"), DEFCDCATNAME);
-
- while ((c = getopt(argc, argv, "c:npdl")) != EOF) {
- switch (c) {
- case 'c':
- cdcatname = optarg;
- break;
- case 'n':
- schedctl(NDPRI, 0, NDPNORMMAX);
- break;
- case 'd':
- daemon = 1;
- break;
- case 'p':
- silent = 0;
- break;
- case 'l':
- linear = 1;
- break;
- }
- }
-
- setuid(getuid());
-
- if (sigset(SIGINT, SIG_IGN) != SIG_IGN)
- sigset(SIGINT, die);
- sigset(SIGTERM, die);
- sigset(SIGHUP, toggle);
- sigset(SIGUSR1, eject);
-
- if (daemon)
- for (;;)
- play();
- else
- play();
- die(0);
- }
-