diff --git a/example/audio.c b/example/audio.c new file mode 100644 index 00000000..cfc8ffb2 --- /dev/null +++ b/example/audio.c @@ -0,0 +1,426 @@ +/* + $Id: audio.c,v 1.1 2005/03/15 04:18:05 rocky Exp $ + + Copyright (C) 2005 Rocky Bernstein + + Adapted from Gerd Knorr's player.c program + Copyright (C) 1997, 1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDIO_H +#include +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#include + +#include + +#ifdef HAVE_GETOPT_H +#include +#endif + +#ifdef HAVE_ERRNO_H +#include +#endif + +#include +#include +#include +#include + +static void play_track(track_t t1, track_t t2); + +typedef enum { + PLAY_CD=1, + PLAY_TRACK=2, + STOP_PLAYING=3, + EJECT_CD=4, + CLOSE_CD=5, +} cd_operation_t; + +CdIo_t *p_cdio; /* libcdio handle */ +driver_id_t driver_id = DRIVER_DEVICE; + +/* cdrom data */ +track_t i_first_track; +track_t i_last_track; +track_t i_first_audio_track; +track_t i_last_audio_track; +track_t i_tracks; +msf_t toc[CDIO_CDROM_LEADOUT_TRACK+1]; +cd_operation_t todo; /* operation to do in non-interactive mode */ +cdio_subchannel_t sub; /* subchannel last time read */ +int i_data; /* # of data tracks present ? */ +int start_track = 0; +int stop_track = 0; +int one_track = 0; + +bool b_cd = false; +bool auto_mode = false; +bool b_verbose = false; +bool debug = false; +bool b_record = false; /* we have a record for + the inserted CD */ + +char *psz_device=NULL; +char *psz_program; + +static void inline +xperror(const char *psz_msg) +{ + if (b_verbose) { + fprintf(stderr, "error: "); + perror(psz_msg); + } + return; +} + + +static void +oops(const char *psz_msg, int rc) +{ + cdio_destroy (p_cdio); + free (psz_device); + exit (rc); +} + +/* ---------------------------------------------------------------------- */ + +/*! Stop playing audio CD */ +static void +cd_stop(CdIo_t *p_cdio) +{ + if (b_cd && p_cdio) { + i_last_audio_track = CDIO_INVALID_TRACK; + if (DRIVER_OP_SUCCESS != cdio_audio_stop(p_cdio)) + xperror("stop"); + } +} + +/*! Eject CD */ +static void +cd_eject(void) +{ + if (p_cdio) { + cd_stop(p_cdio); + if (DRIVER_OP_SUCCESS != cdio_eject_media(&p_cdio)) + xperror("eject"); + b_cd = 0; + p_cdio = NULL; + } +} + +/*! Close CD tray */ +static void +cd_close(const char *psz_device) +{ + if (!b_cd) { + if (DRIVER_OP_SUCCESS != cdio_close_tray(psz_device, &driver_id)) + xperror("close"); + } +} + +/*! Pause playing audio CD */ +static void +cd_pause(CdIo_t *p_cdio) +{ + if (sub.audio_status == CDIO_MMC_READ_SUB_ST_PLAY) + if (DRIVER_OP_SUCCESS != cdio_audio_pause(p_cdio)) + xperror("pause"); +} + +/*! Get status/track/position info of an audio CD */ +static void +read_subchannel(CdIo_t *p_cdio) +{ + if (!b_cd) return; + + sub.format = CDIO_CDROM_MSF; + if (DRIVER_OP_SUCCESS != cdio_audio_read_subchannel(p_cdio, &sub)) { + xperror("read subchannel"); + b_cd = 0; + } + if (auto_mode && sub.audio_status == CDIO_MMC_READ_SUB_ST_COMPLETED) + cd_eject(); +} + +/*! Read CD TOC and set CD information. */ +static void +read_toc(CdIo_t *p_cdio) +{ + track_t i; + + i_first_track = cdio_get_first_track_num(p_cdio); + i_last_track = cdio_get_last_track_num(p_cdio); + i_tracks = cdio_get_num_tracks(p_cdio); + i_first_audio_track = i_first_track; + i_last_audio_track = i_last_track; + + + if ( CDIO_INVALID_TRACK == i_first_track || + CDIO_INVALID_TRACK == i_last_track ) { + xperror("read toc header"); + b_cd = false; + b_record = false; + } else { + b_cd = true; + i_data = 0; + for (i = i_first_track; i <= i_last_track+1; i++) { + if ( !cdio_get_track_msf(p_cdio, i, &(toc[i])) ) + { + xperror("read toc entry"); + b_cd = false; + return; + } + if ( TRACK_FORMAT_AUDIO != cdio_get_track_format(p_cdio, i) ) { + if ((i != i_last_track+1) ) { + i_data++; + if (i == i_first_track) { + if (i == i_last_track) + i_first_audio_track = CDIO_CDROM_LEADOUT_TRACK; + else + i_first_audio_track++; + } + } + } + } + b_record = true; + read_subchannel(p_cdio); + if (auto_mode && sub.audio_status != CDIO_MMC_READ_SUB_ST_PLAY) + play_track(1, CDIO_CDROM_LEADOUT_TRACK); + } +} + +/*! Play an audio track. */ +static void +play_track(track_t i_start_track, track_t i_end_track) +{ + if (!b_cd) { + cd_close(psz_device); + read_toc(p_cdio); + } + + read_subchannel(p_cdio); + if (!b_cd || i_first_track == CDIO_CDROM_LEADOUT_TRACK) + return; + + if (debug) + fprintf(stderr,"play tracks: %d-%d => ", i_start_track, i_end_track); + if (i_start_track < i_first_track) i_start_track = i_first_track; + if (i_start_track > i_last_audio_track) i_start_track = i_last_audio_track; + if (i_end_track < i_first_track) i_end_track = i_first_track; + if (i_end_track > i_last_audio_track) i_end_track = i_last_audio_track; + if (debug) + fprintf(stderr,"%d-%d\n",i_start_track, i_end_track); + + cd_pause(p_cdio); + if ( DRIVER_OP_SUCCESS != cdio_audio_play_msf(p_cdio, &(toc[i_start_track]), + &(toc[i_end_track])) ) + xperror("play"); +} + +static void +usage(char *prog) +{ + fprintf(stderr, + "%s is a simple interface to issuing CD audio comamnds\n" + "\n" + "usage: %s [options] [device]\n" + "\n" + "default for to search for a CD-ROM device with a CD-DA loaded\n" + "\n" + "These command line options available:\n" + " -h print this help\n" + " -a start up in auto-mode\n" + " -v verbose\n" + "\n" + " Use only one of these:\n" + " -C close CD-ROM tray. If you use this option,\n" + " a CD-ROM device name must be specified.\n" + " -p play the whole CD\n" + " -t n play track >n<\n" + " -t a-b play all tracks between a and b (inclusive)\n" + " -s stop playing\n" + " -e eject cdrom\n" + "\n" + "Thats all. Oh, maybe a few words more about the auto-mode. This\n" + "is the 'dont-touch-any-key' feature. You load a CD, player starts\n" + "to play it, and when it is done it ejects the CD. Start it that\n" + "way on a spare console and forget about it...\n" + "\n" + "(c) 1997,98 Gerd Knorr \n" + "(c) 2005 Rocky Bernstein \n" + , prog, prog); +} + +int +main(int argc, char *argv[]) +{ + int c, nostop=0; + char *h; + + psz_program = strrchr(argv[0],'/'); + psz_program = psz_program ? psz_program+1 : argv[0]; + + /* parse options */ + while ( 1 ) { + if (-1 == (c = getopt(argc, argv, "xdhkvcCpset:la"))) + break; + switch (c) { + case 'v': + b_verbose = true; + break; + case 'd': + debug = 1; + break; + case 'a': + auto_mode = 1; + break; + case 't': + if (NULL != (h = strchr(optarg,'-'))) { + *h = 0; + start_track = atoi(optarg); + stop_track = atoi(h+1)+1; + if (0 == start_track) start_track = 1; + if (1 == stop_track) stop_track = CDIO_CDROM_LEADOUT_TRACK; + } else { + start_track = atoi(optarg); + stop_track = start_track+1; + one_track = 1; + } + todo = PLAY_TRACK; + break; + case 'p': + todo = PLAY_CD; + break; + case 'C': + todo = CLOSE_CD; + break; + break; + case 's': + todo = STOP_PLAYING; + break; + case 'e': + todo = EJECT_CD; + break; + case 'h': + usage(psz_program); + exit(1); + default: + usage(psz_program); + exit(1); + } + } + + if (argc > optind) { + psz_device = strdup(argv[optind]); + } else { + char **ppsz_cdda_drives=NULL; + char **ppsz_all_cd_drives = cdio_get_devices_ret(&driver_id); + + if (!ppsz_all_cd_drives) { + fprintf(stderr, "Can't find a CD-ROM drive\n"); + exit(2); + } + ppsz_cdda_drives = cdio_get_devices_with_cap(ppsz_all_cd_drives, + CDIO_FS_AUDIO, false); + if (!ppsz_cdda_drives || !ppsz_cdda_drives[0]) { + fprintf(stderr, "Can't find a CD-ROM drive with a CD-DA in it\n"); + exit(3); + } + psz_device = strdup(ppsz_cdda_drives[0]); + cdio_free_device_list(ppsz_all_cd_drives); + cdio_free_device_list(ppsz_cdda_drives); + } + + if (!b_cd && todo != EJECT_CD) { + cd_close(psz_device); + } + + /* open device */ + if (b_verbose) + fprintf(stderr,"open %s... ", psz_device); + + p_cdio = cdio_open (psz_device, driver_id); + + if (!p_cdio) { + if (b_verbose) + fprintf(stderr, "error: %s\n", strerror(errno)); + else + fprintf(stderr, "open %s: %s\n", psz_device, strerror(errno)); + exit(1); + } else + if (b_verbose) + fprintf(stderr,"ok\n"); + + { + nostop=1; + if (EJECT_CD == todo) { + cd_eject(); + } else { + read_toc(p_cdio); + if (!b_cd) { + cd_close(psz_device); + read_toc(p_cdio); + } + if (b_cd) + switch (todo) { + case STOP_PLAYING: + cd_stop(p_cdio); + break; + case EJECT_CD: + /* Should have been handled above. */ + cd_eject(); + break; + case PLAY_TRACK: + /* play just this one track */ + play_track(start_track, stop_track); + break; + case PLAY_CD: + play_track(1,CDIO_CDROM_LEADOUT_TRACK); + break; + case CLOSE_CD: + cdio_close_tray(psz_device, NULL); + break; + } + else { + fprintf(stderr,"no CD in drive (%s)\n", psz_device); + } + } + } + + if (!nostop) cd_stop(p_cdio); + oops("bye", 0); + + return 0; /* keep compiler happy */ +}