Exemple #1
0
/*! Play an audio track. */
static bool
play_track(track_t i_start_track, track_t i_end_track)
{
  bool b_ok = true;

  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 false;

  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);
  b_ok = (DRIVER_OP_SUCCESS == cdio_audio_play_msf(p_cdio,
						   &(toc[i_start_track]),
						   &(toc[i_end_track])) );
  if (!b_ok) xperror("play");
  return b_ok;
}
Exemple #2
0
/*
 * Description: Pause or Resume the Current Track.
 */
static void pause_resume ()
{
  if	( cd_is_paused ())
	{
          cd_eject() ;
	}
  else
  if	( cd_current_track ())
	{
          cd_close() ;
	}
}
Exemple #3
0
int
main(int argc, char *argv[])
{
  int  c;
  char *h;
  int  i_rc = 0;
  int  i_volume_level = -1;
  cd_operation_t todo = NO_OP; /* operation to do in non-interactive mode */

  psz_program = strrchr(argv[0],'/');
  psz_program = psz_program ? psz_program+1 : argv[0];

  /* parse options */
  while ( 1 ) {
    if (-1 == (c = getopt(argc, argv, "aCdehkpL:sSt:vx")))
      break;
    switch (c) {
    case 'v':
      b_verbose = true;
      break;
    case 'd':
      debug = 1;
      break;
    case 'a':
      auto_mode = 1;
      break;
    case 'L':
      if (NULL != strchr(optarg,'-')) {
	i_volume_level = atoi(optarg);
	todo = SET_VOLUME;
      }
      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 'S':
      todo = LIST_SUBCHANNEL;
      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");

  if (EJECT_CD == todo) {
    i_rc = cd_eject() ? 0 : 1;
  } else {
    read_toc(p_cdio);
    if (!b_cd) {
      cd_close(psz_device);
      read_toc(p_cdio);
    }
    if (b_cd)
      switch (todo) {
      case NO_OP:
	break;
      case STOP_PLAYING:
	i_rc = cd_stop(p_cdio) ? 0 : 1;
	break;
      case EJECT_CD:
	/* Should have been handled above before case statement. gcc
	   warns if we don't include this. And with this Coverty
	   complains when we do - we can't win, so go with gcc. */
	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:
	  i_rc = cdio_close_tray(psz_device, NULL) ? 0 : 1;
	  break;
	case SET_VOLUME:
	  {
	    cdio_audio_volume_t volume;
	    volume.level[0] = i_volume_level;
	    i_rc = (DRIVER_OP_SUCCESS == cdio_audio_set_volume(p_cdio,
							       &volume))
	      ? 0 : 1;
	    break;
	  }
	case LIST_SUBCHANNEL:
	  if (read_subchannel(p_cdio)) {
	    if (sub.audio_status == CDIO_MMC_READ_SUB_ST_PAUSED ||
		sub.audio_status == CDIO_MMC_READ_SUB_ST_PLAY) {
	      {
		printf("track %2d - %02x:%02x (%02x:%02x abs) ",
		       sub.track, sub.rel_addr.m, sub.rel_addr.s,
		       sub.abs_addr.m, sub.abs_addr.s);
	      }
	    }
	    printf("drive state: %s\n",
		   mmc_audio_state2str(sub.audio_status));
	  } else {
	    i_rc = 1;
	  }
	  break;
      }
      else {
	fprintf(stderr,"no CD in drive (%s)\n", psz_device);
      }
  }

  oops("bye", i_rc);

  return 0; /* keep compiler happy */
}
static GstStateChangeReturn
cdplayer_change_state (GstElement * element, GstStateChange transition)
{
  CDPlayer *cdp;
  GstState state = GST_STATE (element);
  GstState pending = GST_STATE_PENDING (element);

  g_return_val_if_fail (GST_IS_CDPLAYER (element), GST_STATE_CHANGE_FAILURE);

  cdp = CDPLAYER (element);

  switch (pending) {
    case GST_STATE_READY:
      if (state != GST_STATE_PAUSED) {
        if (cd_init (CDPLAYER_CD (cdp), cdp->device) == FALSE) {
          return GST_STATE_CHANGE_FAILURE;
        }
        cdp->num_tracks = cdp->cd.num_tracks;
        cdp->cddb_discid = cd_cddb_discid (CDPLAYER_CD (cdp));
      }
      break;
    case GST_STATE_PAUSED:
      /* ready->paused is not useful */
      if (state != GST_STATE_READY) {
        if (cd_pause (CDPLAYER_CD (cdp)) == FALSE) {
          return GST_STATE_CHANGE_FAILURE;
        }

        cdp->paused = TRUE;
      }

      break;
    case GST_STATE_PLAYING:
      if (cdp->paused == TRUE) {
        if (cd_resume (CDPLAYER_CD (cdp)) == FALSE) {
          return GST_STATE_CHANGE_FAILURE;
        }

        cdp->paused = FALSE;
      } else {
        if (cd_start (CDPLAYER_CD (cdp), cdp->start_track,
                cdp->end_track) == FALSE) {
          return GST_STATE_CHANGE_FAILURE;
        }
      }

      break;
    case GST_STATE_NULL:
      /* stop & close fd */
      if (cd_stop (CDPLAYER_CD (cdp)) == FALSE
          || cd_close (CDPLAYER_CD (cdp)) == FALSE) {
        return GST_STATE_CHANGE_FAILURE;
      }

      break;
    default:
      break;
  }

  if (GST_ELEMENT_CLASS (parent_class)->change_state) {
    GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
  }

  return GST_STATE_CHANGE_SUCCESS;
}
Exemple #5
0
static GstStateChangeReturn
gst_cdaudio_change_state (GstElement * element, GstStateChange transition)
{
  GstCDAudio *cdaudio;
  GstStateChangeReturn ret;
  gint res;

  cdaudio = GST_CDAUDIO (element);

  switch (transition) {
    case GST_STATE_CHANGE_NULL_TO_READY:
      break;
    case GST_STATE_CHANGE_READY_TO_PAUSED:
      if ((res = cd_init_device (cdaudio->device)) < 0)
        goto init_failed;

      cdaudio->cd_desc = res;

      /* close tray */
      if ((res = cd_close (cdaudio->cd_desc)) < 0)
        goto close_failed;

      if ((res = cd_stat (cdaudio->cd_desc, &cdaudio->info)) < 0) {
        /* we just give a warning here */
        GST_ELEMENT_WARNING (cdaudio, LIBRARY, INIT,
            ("Could not retrieve CD track info."), (NULL));
      } else {
        debug_track_info (cdaudio);
        cdaudio->discid = cddb_discid (cdaudio->cd_desc);
        /* FIXME, post message with discid */
      }
      cdaudio->was_playing = FALSE;
      break;
    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
    {
      if (cdaudio->was_playing)
        res = cd_resume (cdaudio->cd_desc);
      else
        res = cd_play (cdaudio->cd_desc, 1);

      if (res < 0)
        goto play_failed;

      cdaudio->was_playing = TRUE;
      g_timer_start (cdaudio->timer);
      break;
    }
    default:
      break;
  }

  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);

  switch (transition) {
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
      if ((res = cd_pause (cdaudio->cd_desc)) < 0)
        goto pause_failed;
      g_timer_stop (cdaudio->timer);
      break;
    case GST_STATE_CHANGE_PAUSED_TO_READY:
      if ((res = cd_stop (cdaudio->cd_desc)) < 0)
        goto stop_failed;
      if ((res = cd_finish (cdaudio->cd_desc)) < 0)
        goto finish_failed;
      cdaudio->cd_desc = -1;
      break;
    case GST_STATE_CHANGE_READY_TO_NULL:
      break;
    default:
      break;
  }
  return ret;

  /* ERRORS */
init_failed:
  {
    GST_ELEMENT_ERROR (cdaudio, LIBRARY, INIT,
        ("Could not init CD device %s. (%d)", cdaudio->device, res), (NULL));
    cdaudio->cd_desc = -1;
    return GST_STATE_CHANGE_FAILURE;
  }
close_failed:
  {
    GST_ELEMENT_ERROR (cdaudio, LIBRARY, INIT,
        ("Could not close CD tray for device %s. (%d)", cdaudio->device, res),
        (NULL));
    return GST_STATE_CHANGE_FAILURE;
  }
play_failed:
  {
    GST_ELEMENT_ERROR (cdaudio, LIBRARY, INIT,
        ("Could not play CD device %s. (%d)", cdaudio->device, res), (NULL));
    return GST_STATE_CHANGE_FAILURE;
  }
pause_failed:
  {
    GST_ELEMENT_ERROR (cdaudio, LIBRARY, INIT,
        ("Could not pause CD device %s. (%d)", cdaudio->device, res), (NULL));
    return GST_STATE_CHANGE_FAILURE;
  }
stop_failed:
  {
    GST_ELEMENT_ERROR (cdaudio, LIBRARY, INIT,
        ("Could not stop CD device %s. (%d)", cdaudio->device, res), (NULL));
    return GST_STATE_CHANGE_FAILURE;
  }
finish_failed:
  {
    GST_ELEMENT_ERROR (cdaudio, LIBRARY, INIT,
        ("Could not finish CD device %s. (%d)", cdaudio->device, res), (NULL));
    return GST_STATE_CHANGE_FAILURE;
  }
}
int
main(int argc, char *argv[])
{    
  int  c, nostop=0;
  char *h;
  int  i_rc = 0;
  cd_operation_t cd_op = NO_OP; /* operation to do in non-interactive mode */
  
  
  psz_program = strrchr(argv[0],'/');
  psz_program = psz_program ? psz_program+1 : argv[0];

  memset(&cddb_opts, 0, sizeof(cddb_opts));
  
  cdio_loglevel_default = CDIO_LOG_WARN;
  /* parse options */
  while ( 1 ) {
    if (-1 == (c = getopt(argc, argv, "acCdehkplL:sSt:vx")))
      break;
    switch (c) {
    case 'v':
      b_verbose = true;
      if (cdio_loglevel_default > CDIO_LOG_INFO) 
        cdio_loglevel_default = CDIO_LOG_INFO;
      break;
    case 'd':
      debug = 1;
      if (cdio_loglevel_default > CDIO_LOG_DEBUG) 
      cdio_loglevel_default = CDIO_LOG_DEBUG;
      break;
    case 'a':
      auto_mode = 1;
      break;

    case 'L':
      i_volume_level = atoi(optarg);
      cd_op = SET_VOLUME;
      b_interactive = false;
      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;
      }
      b_interactive = false;
      cd_op = PLAY_TRACK;
      break;
    case 'p':
      b_interactive = false;
      cd_op = PLAY_CD;
      break;
    case 'l':
      b_interactive = false;
      cd_op = LIST_TRACKS;
      break;
    case 'C':
      b_interactive = false;
      cd_op = CLOSE_CD;
      break;
    case 'c':
      b_interactive = false;
      cd_op = PS_LIST_TRACKS;
      break;
    case 's':
      b_interactive = false;
      cd_op = STOP_PLAYING;
      break;
    case 'S':
      b_interactive = false;
      cd_op = LIST_SUBCHANNEL;
      break;
    case 'e':
      b_interactive = false;
      cd_op = EJECT_CD;
      break;
    case 'k':
      print_keys();
      exit(1);
    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_interactive) {
    b_sig = true;
    nostop=1;
  }

  tty_raw();
  signal(SIGINT,ctrlc);
  signal(SIGQUIT,ctrlc);
  signal(SIGTERM,ctrlc);
  signal(SIGHUP,ctrlc);
  signal(SIGWINCH, sigwinch);

  if (CLOSE_CD != cd_op) {
    /* open device */
    if (b_verbose)
      fprintf(stderr, "open %s... ", psz_device);
    p_cdio = cdio_open (psz_device, driver_id);
    if (!p_cdio && cd_op != EJECT_CD) {
      cd_close(psz_device);
      p_cdio = cdio_open (psz_device, driver_id);
    }
    
    if (p_cdio && b_verbose)
      fprintf(stderr,"ok\n");
  }
  
  if (b_interactive) {
#ifdef HAVE_CDDB
    cddb_log_set_handler (cddb_log_handler);
#else
    ;
#endif
  }  else {
    b_sig = true;
    nostop=1;
    if (EJECT_CD == cd_op) {
      i_rc = cd_eject() ? 0 : 1;
    } else {
      switch (cd_op) {
      case PS_LIST_TRACKS:
      case LIST_TRACKS:
      case PLAY_TRACK:
        read_toc(p_cdio);
      default:
        break;
      }
      if (p_cdio)
        switch (cd_op) {
        case STOP_PLAYING:
          b_cd = true;
          i_rc = cd_stop(p_cdio) ? 0 : 1;
          break;
        case EJECT_CD:
          /* Should have been handled above. */
          cd_eject();
          break;
        case LIST_TRACKS:
          list_tracks();
          break;
        case PS_LIST_TRACKS:
          ps_list_tracks();
          break;

        case PLAY_TRACK:
          /* play just this one track */
          if (b_record) {
            printf("%s / %s\n", artist, title);
            if (one_track)
              printf("%s\n", cd_info[start_track].title);
          }
          i_rc = play_track(start_track, stop_track) ? 0 : 1;
          break;

        case PLAY_CD:
          if (b_record)
            printf("%s / %s\n", artist, title);
          play_track(1,CDIO_CDROM_LEADOUT_TRACK);
          break;

        case SET_VOLUME:
          i_rc = set_volume_level(p_cdio, i_volume_level);
          break;

        case LIST_SUBCHANNEL: 
          if (read_subchannel(p_cdio)) {
            if (sub.audio_status == CDIO_MMC_READ_SUB_ST_PAUSED ||
                sub.audio_status == CDIO_MMC_READ_SUB_ST_PLAY) {
              {
                printf("track %2d - %02x:%02x (%02x:%02x abs) ",
                       sub.track, sub.rel_addr.m, sub.rel_addr.s,
                       sub.abs_addr.m, sub.abs_addr.s);
              }
            }
            printf("drive state: %s\n", 
                   mmc_audio_state2str(sub.audio_status));
          } else {
            i_rc = 1;
          }
          break;
        case CLOSE_CD: /* Handled below */
        case LIST_KEYS:
        case TOGGLE_PAUSE:
        case EXIT_PROGRAM:
        case NO_OP:
          break;
        }
      else if (CLOSE_CD == cd_op) {
        i_rc = (DRIVER_OP_SUCCESS == cdio_close_tray(psz_device, NULL))
                ? 0 : 1;
      } else {
        fprintf(stderr,"no CD in drive (%s)\n", psz_device);
      }
    }
  }

  /* Play all tracks *unless* we have a play or paused status
     already. */

  read_subchannel(p_cdio);
  if (sub.audio_status != CDIO_MMC_READ_SUB_ST_PAUSED &&
      sub.audio_status != CDIO_MMC_READ_SUB_ST_PLAY)
    play_track(1, CDIO_CDROM_LEADOUT_TRACK);

  while ( !b_sig ) {
    int key;
    if (!b_cd) read_toc(p_cdio);
    read_subchannel(p_cdio);
    display_status(false);
    
    if (1 == select_wait(b_cd ? 1 : 5)) {
      switch (key = getch()) {
      case '-':
        decrease_volume_level(p_cdio);
        break;
      case '+':
        increase_volume_level(p_cdio);
        break;
      case 'A':
      case 'a':
        auto_mode = !auto_mode;
        break;
      case 'X':
      case 'x':
        nostop=1;
        /* fall through */
      case 'Q':
      case 'q':
        b_sig = true;
        break;
      case 'E':
      case 'e':
        cd_eject();
        break;
      case 's':
        cd_stop(p_cdio);
        break;
      case 'C':
      case 'c':
        cd_close(psz_device);
        break;
      case 'L':
      case 'l':
        b_all_tracks = !b_all_tracks;
        if (b_all_tracks)
          display_tracks();
        else {
          i_last_display_track = CDIO_INVALID_TRACK;
          display_cdinfo(p_cdio, i_tracks, i_first_track);
        }
        
        break;
      case 'K':
      case 'k':
      case 'h':
      case 'H':
      case '?':
        list_keys();
        break;
      case ' ':
      case 'P':
      case 'p':
        toggle_pause();
        break;
      case KEY_RIGHT:
        if (b_cd &&
            (sub.audio_status == CDIO_MMC_READ_SUB_ST_PAUSED ||
             sub.audio_status == CDIO_MMC_READ_SUB_ST_PLAY)) 
          play_track(sub.track+1, CDIO_CDROM_LEADOUT_TRACK);
        else
          play_track(1,CDIO_CDROM_LEADOUT_TRACK);
        break;
      case KEY_LEFT:
        if (b_cd &&
            (sub.audio_status == CDIO_MMC_READ_SUB_ST_PAUSED ||
             sub.audio_status == CDIO_MMC_READ_SUB_ST_PLAY))
          play_track(sub.track-1,CDIO_CDROM_LEADOUT_TRACK);
        break;
      case KEY_UP:
        if (b_cd && sub.audio_status == CDIO_MMC_READ_SUB_ST_PLAY)
          skip(10);
        break;
      case KEY_DOWN:
        if (b_cd && sub.audio_status == CDIO_MMC_READ_SUB_ST_PLAY)
          skip(-10);
        break;
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
        play_track(key - '0', CDIO_CDROM_LEADOUT_TRACK);
        break;
      case '0':
        play_track(10, CDIO_CDROM_LEADOUT_TRACK);
        break;
      case KEY_F(1):
      case KEY_F(2):
      case KEY_F(3):
      case KEY_F(4):
      case KEY_F(5):
      case KEY_F(6):
      case KEY_F(7):
      case KEY_F(8):
      case KEY_F(9):
      case KEY_F(10):
      case KEY_F(11):
      case KEY_F(12):
      case KEY_F(13):
      case KEY_F(14):
      case KEY_F(15):
      case KEY_F(16):
      case KEY_F(17):
      case KEY_F(18):
      case KEY_F(19):
      case KEY_F(20):
        play_track(key - KEY_F(1) + 11, CDIO_CDROM_LEADOUT_TRACK);
        break;
      }
    }
  }
  if (!nostop) cd_stop(p_cdio);
  tty_restore();
  finish("bye", i_rc);
  
  return 0; /* keep compiler happy */
}
Exemple #7
0
void close_release()
{  
   cd_close(cd_fd);
}
Exemple #8
0
int main()
{
    char cmd[20];
    int done = 0;
    int ret, trk, a, b;

    if (cd_init() < 0) {
	printf("Error initialising libcda (%s)\n", cd_error);
	return 1;
    }
	
    show_cmds();

    do {  
	printf(">>> ");
	fflush(stdout);
	scanf("%s", cmd);

	switch (cmd[0]) {
	    case '?':
		show_cmds();
		break;

	    case 'p':
		trk = input_int("Track");
		ret = cd_play(trk);
		if (ret != 0)
		    printf("Error occurred (%s)\n", cd_error);
		break;

	    case 'r':
		a = input_int("First track");
		b = input_int("Last track");
		ret = cd_play_range(a, b);
		if (ret != 0)
		    printf("Error occurred (%s)\n", cd_error);
		break;

	    case 'f':
		trk = input_int("Start track");
		ret = cd_play_from(trk);
		if (ret != 0)
		    printf("Error occurred (%s)\n", cd_error);
		break;

	    case 'P':
		trk = cd_current_track();
		if (trk)
		    printf("Playing track %d\n", trk);
		else
		    printf("Not playing\n");
		break;

	    case 'w':
		cd_pause();
		break;

	    case 'W':
		cd_resume();
		break;

	    case 'S':
		ret = cd_is_paused();
		if (ret)
		    printf("Paused\n");
		else
		    printf("Not paused\n");
		break;

	    case 's':
		cd_stop();
		break;

	    case 'i':
		ret = cd_get_tracks(&a, &b);
		if (ret != 0)
		    printf("Error occurred (%s)\n", cd_error);
		else
		    printf("First track: %d\nLast track: %d\n", a, b);
		break;

	    case 'a':
		trk = input_int("Track");
		ret = cd_is_audio(trk);
		if (ret < 0)
		    printf("Error occurred (%s)\n", cd_error);
		else
		    printf("Track %d is %s\n", trk, (ret ? "audio" : "data"));
		break;

	    case 'v':
		a = input_int("Left (0-255)");
		b = input_int("Right (0-255)");
		cd_set_volume(a, b);
		break;

	    case 'V':
		cd_get_volume(&a, &b);
		printf("Left volume: %d\nRight volume: %d\n", a, b);
		break;

	    case 'e':
		cd_eject();
		break;

	    case 'c':
		cd_close();
		break;

	    case 'q':
		done = 1;
		break;

	    default:
		printf("Unrecognised command: `%c'\n", cmd[0]);
	}
    } while (!done);

    cd_exit();
    
    return 0;
}