Listing 4. Jcd_Drive_ix86-Linux.c


#include <sys/types.h>                   /*   1 */
#include <sys/stat.h>                    /*   2 */
#include <fcntl.h>                       /*   3 */
#include <linux/cdrom.h>                 /*   4 */
#include <sys/ioctl.h>                   /*   5 */
#include <unistd.h>                      /*   6 */
#include <stdlib.h>                      /*   7 */
#include <stdio.h>                       /*   8 */
#include <time.h>                        /*   9 */
#include "Jcd_Drive.h"                   /*  10 */
/**                                          12
  Jcd - Java CD Audio Player                 13
  Michael Hamilton (michael@actrix.gen.nz).  14
  All rights reserved.                       15
 */                                      /*  16 */
 * This code could be far more integrated into 
 * the Java code, but I may want to used it
 * with python (my prefered langauge), so I'm 
 * avoiding this for now.  Ignoring supporting 
 * multi-disc players for now, but the java
 * class allows for it in the future.        22
 * If using kaffe generate .h with 
 * "kaffeh Jcd/Drive"                        24
 */                                      /*  26 */
#ifdef TRUE                              /*  28 */
#undef TRUE                              /*  29 */
#undef FALSE                             /*  30 */
#endif                                   /*  31 */
#define TRUE  1                          /*  33 */
#define FALSE 0                          /*  34 */
/*                                           36
 * Javah and Kaffeh differ over the type of long
 * in Java-1.1.1 this is int32_t             38 
 */
#ifndef KAFFE                            /*  39 */
#  define Java_Int long  /* Java 1.0 */  /*  40 */  
#else                                    /*  41 */
#  define Java_Int jint  /* kaffeh */    /*  42 */
#endif                                   /*  43 */
#define FRAMES_PER_SECOND \
        Jcd_Drive_FRAMES_PER_SECOND      /*  46 */
#define MAX_DEVICE_LEN 512               /*  47 */
#define MAX_ERROR_LEN 512                /*  48 */
#define FRAME_ADDRESS(mins, secs, frames) \
  (((mins) * FRAMES_PER_SECOND * 60) +    \
        ((secs) * FRAMES_PER_SECOND) + (frames))
static int debug;                        /*  53 */
static void 
  yield_player(struct HJcd_Drive *drive);/*  55 */
static void 
  take_player(struct HJcd_Drive *drive); /*  56 */
static void take_player(struct HJcd_Drive *drive)
{                                        /*  59 */
  /*                                         60
   * If not already open, open the device.   61
   */                                    /*  62 */
  if (unhand(drive)->fd == -1) {         /*  63 */
    char device_name[MAX_DEVICE_LEN + 1];/*  64 */
    javaString2CString(
      unhand(drive)->device_name,device_name,
      MAX_DEVICE_LEN);                   /*  65 */
    if (device_name == '\0') {           /*  66 */
      char *device = getenv("CDROM");    /*  67 */
      if (device == NULL)                /*  68 */
        strcpy(device_name, "/dev/cdrom");
    }                                    /*  70 */
    unhand(drive)->device_flags |= 
      (getenv("SBPCD") != NULL) ?        /*  71 */
      Jcd_Drive_FLAG_STOP_PLAY :         /*  72 */
      Jcd_Drive_FLAG_NONE;               /*  73 */
    unhand(drive)->fd =open(device_name,O_RDONLY);
    if (debug)                           /*  77 */
      fprintf(stderr, 
              "Openned %s flags=%d fd=%d\n ",  
              device_name,               /*  79 */
              unhand(drive)->device_flags,  
              unhand(drive)->fd);        /*  81 */
  }                                      /*  82 */
}                                        /*  83 */
static void yield_player(struct HJcd_Drive *drive)
{                                        /*  87 */
 /*                                          88
  * Close the device, make it available to others.
  */                                     /*  90 */
  if (unhand(drive)->fd != -1) {         /*  91 */
    close(unhand(drive)->fd);            /*  92 */
  }                                      /*  93 */
  unhand(drive)->fd               = -1;  /*  95 */
  unhand(drive)->current_track    = 1;   /*  96 */
  unhand(drive)->current_index    = 1;   /*  97 */
  unhand(drive)->number_of_tracks = 0;   /*  98 */
  unhand(drive)->audio_status     = 
    Jcd_Drive_STATUS_INVALID;            /*  99 */
  if (debug)                             /* 101 */
    fprintf(stderr, "closed cd device\n"); 
}                                        /* 103 */
static Java_Int 
new_status(struct HJcd_Drive *drive)     /* 105 */
{                                        /* 106 */
  * Try to obtain the device and query its status.
  * May cause the tray to close with some drivers.
  */                                     /* 110 */
  struct cdrom_subchnl ch;               /* 111 */
  long stat;                             /* 112 */
  unhand(drive)->current_track   = 1;    /* 114 */
  unhand(drive)->current_index   = 1;    /* 115 */
  unhand(drive)->current_address = 0;    /* 116 */
  if (unhand(drive)->fd == -1) { 
                     /* See if there's a new CD */
    take_player(drive);                  /* 120 */
    if (unhand(drive)->fd != -1) {       /* 121 */
      struct cdrom_tochdr tinfo;         /* 122 */
      stat = ioctl(unhand(drive)->fd, 
                   CDROMREADTOCHDR, 
                   &tinfo);              /* 123 */
      if (stat == -1) {                  /* 124 */
        yield_player(drive);             /* 125 */
        unhand(drive)->audio_status = 
          Jcd_Drive_STATUS_INVALID;      /* 126 */
        return (Java_Int) 
          unhand(drive)->audio_status;   /* 127 */
      }                                  /* 128 */
      unhand(drive)->number_of_tracks = 
        tinfo.cdth_trk1;                 /* 129 */
      if (debug)                         /* 130 */
        fprintf(stderr,                  /* 131 */
                "number_of_tracks=%d\n",
                unhand(drive)->number_of_tracks);  
    }                                    /* 134 */
  }                                      /* 135 */
  ch.cdsc_format = CDROM_MSF;            /* 137 */
  stat = ioctl(unhand(drive)->fd, 
               CDROMSUBCHNL, 
               &ch);                     /* 139 */
  if (stat == -1) { /* Assume no CD in drive */
    yield_player(drive);                 /* 141 */
    unhand(drive)->audio_status = 
      Jcd_Drive_STATUS_INVALID;          /* 142 */
    return (Java_Int) unhand(drive)->audio_status; 
  }                                      /* 144 */
  unhand(drive)->current_track = ch.cdsc_trk;
  unhand(drive)->current_index = ch.cdsc_ind;
  unhand(drive)->current_address = 
    FRAME_ADDRESS(ch.cdsc_absaddr.msf.minute,
                  ch.cdsc_absaddr.msf.second,
                  ch.cdsc_absaddr.msf.frame);
  unhand(drive)->audio_status =          /* 153 */
    ch.cdsc_audiostatus;                 /* 154 */
  return (Java_Int) unhand(drive)->audio_status;
}                                        /* 157 */
static int is_open(struct HJcd_Drive *drive)
{                                        /* 160 */
  if (unhand(drive)->fd == -1) {         /* 161 */
    return FALSE;                        /* 163 */
  }                                      /* 164 */
  return TRUE;                           /* 165 */
}                                        /* 166 */
static int                               /* 168 */  
is_available_now(struct HJcd_Drive *drive)
{                                        /* 169 */
  new_status(drive);                     /* 170 */
  return is_open(drive);                 /* 171 */
}                                        /* 172 */
void Jcd_Drive_initDrive(struct HJcd_Drive *drive)
{                                        /* 175 */
  fprintf(stderr, "Initializing cd drive...\n");
  debug = getenv("JCD_DEBUG") != NULL;   /* 177 */
  new_status(drive);                     /* 178 */
}                                        /* 179 */
Java_Int                                 /* 181 */
Jcd_Drive_status(struct HJcd_Drive *drive) 
{                                        /* 182 */
  if (unhand(drive)->fd == -1) {         /* 183 */
    return unhand(drive)->audio_status;  /* 184 */
  }                                      /* 185 */
  else {                                 /* 186 */
    return new_status(drive);            /* 187 */
  }                                      /* 188 */
}                                        /* 189 */
Java_Int                                 /* 191 */
Jcd_Drive_currentTrack(struct HJcd_Drive *drive)
{                                        /* 192 */
  if (!is_available_now(drive)) { return 1; }
  return unhand(drive)->current_track;   /* 194 */
}                                        /* 195 */
Java_Int                                 /* 197 */
Jcd_Drive_currentIndex(struct HJcd_Drive *drive)
{   /* Must call current track first */  /* 198 */
  if (!is_available_now(drive)) { return 1; } 
  return unhand(drive)->current_index;   /* 200 */
}                                        /* 201 */
Java_Int                                 /* 204 */
Jcd_Drive_currentAddress(struct HJcd_Drive *drive)
{                                        /* 205 */
  if (!is_available_now(drive)) { return 0; }
  return unhand(drive)->current_address; /* 207 */
}                                        /* 208 */
Java_Int 
Jcd_Drive_numberOfTracks(struct HJcd_Drive *drive)
{                                        /* 212 */
  if (!is_open(drive)) { return 0; }     /* 213 */
  return unhand(drive)->number_of_tracks;/* 214 */
}                                        /* 215 */
Java_Int                                 /* 218 */
Jcd_Drive_trackAddress(struct HJcd_Drive *drive, 
                       Java_Int track)
{                                        /* 219 */
  struct cdrom_tocentry tocentry;        /* 220 */
  if (!is_open(drive)) { return 0; }     /* 222 */
  tocentry.cdte_track = track;           /* 223 */
  tocentry.cdte_format = CDROM_MSF;      /* 224 */
  if ((ioctl(unhand(drive)->fd, 
             CDROMREADTOCENTRY, 
             &tocentry)) == -1) {
    if (debug)                           /* 226 */
      fprintf(stderr, "tae=%d\n", track);/* 227 */
    SignalError(0, 
                "Jcd/TrackAddressException", 
                strerror(errno));        /* 228 */
    return 0;                            /* 229 */
  }                                      /* 230 */
  return                                 /* 231 */  
    FRAME_ADDRESS(tocentry.cdte_addr.msf.minute, 
                  tocentry.cdte_addr.msf.second, 
                  tocentry.cdte_addr.msf.frame);
}                                        /* 234 */
Java_Int 
Jcd_Drive_trackLength(struct HJcd_Drive *drive, 
                      Java_Int n)        /* 236 */
{                                        /* 237 */
  int starts_at =Jcd_Drive_trackAddress(drive, n);
  int start_of_next =                    /* 239 */
    (n >= unhand(drive)->number_of_tracks) 
    ? Jcd_Drive_cdEndAddress(drive)      /* 241 */
    : Jcd_Drive_trackAddress(drive, n + 1);  
  return start_of_next - starts_at;      /* 243 */
}                                        /* 244 */
Java_Int                                 /* 247 */
Jcd_Drive_cdEndAddress(struct HJcd_Drive *drive)
{                                        /* 248 */
  if (!is_open(drive)) { return 0; }     /* 249 */
  return                                 /* 250 */
    Jcd_Drive_trackAddress(drive, CDROM_LEADOUT); 
}                                        /* 251 */
static int cddbSum(int n)                /* 253 */
{   /* Sum the digits */                 /* 254 */
  int s = 0;                             /* 255 */
  while (n != 0) {                       /* 256 */
    s += n % 10;                         /* 257 */
    n = n / 10;                          /* 258 */
  }                                      /* 259 */
  return s;                              /* 260 */
}                                        /* 261 */
struct Hjava_lang_String *Jcd_Drive_cddbID(
  struct HJcd_Drive *drive)              /* 263 */
{                                        /* 264 */
  /* see http://sunsite.unc.edu~/cddb/xjcd/ */
  char id[10] = "00000000";              /* 266 */
  int i;                                 /* 267 */
  int t = 0;                             /* 268 */
  int n = 0;                             /* 269 */
  if (!is_open(drive)) 
    { return makeJavaString(id, 8); }    /* 271 */
  for (i = 1; 
       i 
       i++) {                            /* 272 */
    n += cddbSum(Jcd_Drive_trackAddress(drive, i) 
                 / FRAMES_PER_SECOND);
    t += (Jcd_Drive_trackLength(drive, i) /
          FRAMES_PER_SECOND) ;           /* 274 */
  }                                      /* 275 */
  i = ((n % 0xff) 
       << 24 | t
       << 8 | (unhand(drive)->number_of_tracks));
  sprintf(id, "%08x", i);                /* 277 */
  return makeJavaString(id, 8);          /* 278 */
}                                        /* 279 */
void Jcd_Drive_play(struct HJcd_Drive *drive,
                        Java_Int start_track,
                        Java_Int start_index,
                        Java_Int end_track,  
                        Java_Int end_index)  
{                                        /* 286 */
  struct cdrom_ti ti;                    /* 287 */
  long stat;                             /* 288 */
  unhand(drive)->current_track = 1;      /* 290 */
  if (!is_available_now(drive)) { return; }
  if (debug)                             /* 294 */
    fprintf(stderr,                      /* 295 */
            "play %d %d %d\n",           /* 296 */
            start_track, 
            end_track, 
            unhand(drive)->number_of_tracks); 
  if (end_track == 0) { 
    /* Kludge for first call to play. */ /* 299 */
    end_track = unhand(drive)->number_of_tracks;
  }                                      /* 301 */
  if (start_track 
    start_track > unhand(drive)->number_of_tracks) 
    {
      SignalError(0,
         "Jcd/DriveException", 
         "Play: start track out of range.");
      return;                            /* 305 */
  }                                      /* 306 */
  if (end_track 
      end_track > unhand(drive)->number_of_tracks)
    {
      SignalError(0, 
                  "Jcd/DriveException", 
                  "Play: end track out of range.");
      return;                            /* 310 */
    }                                    /* 311 */
  if (!is_open(drive)) {                 /* 313 */
    return;                              /* 314 */
  }                                      /* 315 */
  if ((unhand(drive)->device_flags & 
       Jcd_Drive_FLAG_STOP_PLAY)) {      /* 317 */
       /* Must issue stop before play. */
    Jcd_Drive_stop(drive);               /* 318 */
  }                                      /* 319 */
  if (debug)                             /* 321 */
    fprintf(stderr, "try play %d\n", start_track);  
  ti.cdti_trk0 = start_track;            /* 324 */
  ti.cdti_ind0 = start_index;            /* 325 */
  ti.cdti_trk1 = end_track;              /* 326 */
  ti.cdti_ind1 = end_index;              /* 327 */
  if (ti.cdti_ind1 == 0) {               /* 329 */
    /* Doesn't seem to be a way of specifying end 
     * index.  But this seems to work.      331
     */                                  /* 332 */
    ti.cdti_ind1 =unhand(drive)->number_of_tracks;
  }                                      /* 334 */
  stat = ioctl(unhand(drive)->fd, 
               CDROMPLAYTRKIND,
               &ti);                     /* 336 */
  if (stat 
    SignalError(0, "Jcd/PlayException",
                strerror(errno));        /* 338 */
    return;                              /* 339 */
  }                                      /* 340 */
  unhand(drive)->current_track = start_track;
  if (debug)                             /* 344 */
    fprintf(stderr, "playing %d\n",      /* 346 */
            unhand(drive)->current_track);
}                                        /* 346 */
void Jcd_Drive_stop(struct HJcd_Drive *drive)
{                                        /* 350 */
  if (!is_available_now(drive)) { return; } 
  if (ioctl(unhand(drive)->fd, CDROMSTOP) == -1) {
    SignalError(0, "Jcd/StopException", 
                strerror(errno));        /* 354 */
  }                                      /* 355 */
}                                        /* 356 */
void Jcd_Drive_pause(struct HJcd_Drive *drive)
{                                        /* 360 */
  if (!is_available_now(drive)) { return; }
  if (unhand(drive)->audio_status != 
      Jcd_Drive_STATUS_PLAY) {           /* 363 */
    SignalError(0, "Jcd/PauseException",
                "Pause: drive isn't playing.");
    return;                              /* 365 */
  }                                      /* 366 */
  if (ioctl(unhand(drive)->fd,CDROMPAUSE) == -1) {
    SignalError(0, "Jcd/PauseException", 
                strerror(errno));        /* 369 */
  }                                      /* 370 */
}                                        /* 371 */
void Jcd_Drive_resume(struct HJcd_Drive *drive) 
{                                        /* 375 */
  if (!is_available_now(drive)) { return; }
  if (unhand(drive)->audio_status != 
      Jcd_Drive_STATUS_PAUSED) {         /* 378 */
    SignalError(0, "Jcd/ResumeException",
                "Resume: drive isn't paused.");
    return;                              /* 380 */
  }                                      /* 381 */
  if (ioctl(unhand(drive)->fd,CDROMRESUME) == -1){
    SignalError(0, "Jcd/ResumeException",
                strerror(errno));        /* 384 */
  }                                      /* 385 */
}                                        /* 386 */
void Jcd_Drive_eject(struct HJcd_Drive *drive)
{                                        /* 390 */
  long retract = unhand(drive)->fd == -1; 
  if (!is_available_now(drive)) { return; }
  if (retract) { return; }               /* 396 */
  Jcd_Drive_stop(drive);                 /* 399 */
  if (ioctl(unhand(drive)->fd,CDROMEJECT) == -1) {
    SignalError(0, "Jcd/EjectException", 
                strerror(errno));        /* 402 */
  }                                      /* 403 */
  yield_player(drive);                   /* 405 */
}                                        /* 406 */
Java_Int                                 /* 409 */
Jcd_Drive_volume(struct HJcd_Drive *drive)
{                                        /* 410 */
  struct cdrom_volctrl vol;              /* 411 */
  if (!is_available_now(drive)) { return; }
  if (ioctl(unhand(drive)->fd, CDROMVOLREAD,
            &vol) == -1) {               /* 415 */
    SignalError(0, "Jcd/VolumeException", 
                strerror(errno));        /* 416 */
    return 0;                            /* 417 */
  }                                      /* 418 */
  return vol.channel0;                   /* 419 */
}                                        /* 420 */
void Jcd_Drive_setVolume(struct HJcd_Drive *drive, 
                         Java_Int volume)
{                                        /* 423 */
  struct cdrom_volctrl vol;              /* 424 */
  if (!is_available_now(drive)) { return; } 
  if (volume 
    SignalError(0, "Jcd/SetVolumeException", 
                "Volume out of range."); /* 429 */
    return;                              /* 430 */
  }                                      /* 431 */
  vol.channel0 = volume;                 /* 433 */
  vol.channel1 = volume;                 /* 434 */
  vol.channel2 = volume;                 /* 435 */
  vol.channel3 = volume;                 /* 436 */
  if (ioctl(unhand(drive)->fd, CDROMVOLCTRL, 
            &vol) == -1) {               /* 438 */
    SignalError(0, "Jcd/SetVolumeException",
                strerror(errno));        /* 439 */
  }                                      /* 440 */
}                                        /* 441 */
struct Hjava_lang_String *               /* 444 */
Jcd_Drive_productCode(struct HJcd_Drive *drive)
{                                        /* 445 */
  char upc[9] = "00000000";              /* 446 */
  if (!is_available_now(drive)) { 
    return makeJavaString(upc, 8);       /* 448 */
  }                                      /* 449 */
  if (ioctl(unhand(drive)->fd, CDROM_GET_UPC, upc)
      == -1) {                           /* 450 */
    SignalError(0, "Jcd/ProductCodeException",
                strerror(errno));        /* 451 */
  }                                      /* 452 */
  return makeJavaString(upc, 8);         /* 453 */
}                                        /* 454 */