#include #include #include #include #include #include #include "../include/string.h" #include "../include/fio.h" #include "../include/prochandle.h" #include "audiocd.h" AudioCDContext *AudioCDInit(void); void AudioCDShutdown(AudioCDContext *ctx); AudioCDTrack **AudioCDListTracks(AudioCDContext *ctx, int *total); void AudioCDDeleteTracksList(AudioCDTrack **track, int total); int AudioCDLastTrack(AudioCDContext *ctx); void AudioCDPlayTrack(AudioCDContext *ctx, int track_number); void AudioCDStop(AudioCDContext *ctx); void AudioCDEject(AudioCDContext *ctx); #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define CLIP(a,l,h) (MIN(MAX((a),(l)),(h))) #define ABSOLUTE(x) (((x) < 0) ? ((x) * -1) : (x)) /* * Initializes the audio CD and creates a new context. This does * not need to be called between audio CD changes. */ AudioCDContext *AudioCDInit(void) { AudioCDContext *ctx = (AudioCDContext *)calloc( 1, sizeof(AudioCDContext) ); if(ctx == NULL) return(NULL); ctx->prog = strdup("/usr/bin/cdplay"); ctx->device = strdup("/dev/cdrom"); ctx->current_track_number = 0; return(ctx); } /* * Shutsdown the audio cd and deletes the context. */ void AudioCDShutdown(AudioCDContext *ctx) { if(ctx == NULL) return; free(ctx->prog); free(ctx->device); free(ctx); } /* * Returns a list of audio CD tracks. */ AudioCDTrack **AudioCDListTracks(AudioCDContext *ctx, int *total) { char *path; pid_t p; char cmd[PATH_MAX + NAME_MAX + 1024]; AudioCDTrack **track = NULL, *t; if(total == NULL) return(track); else *total = 0; if(ctx == NULL) return(track); if((ctx->prog == NULL) || (ctx->device == NULL)) return(track); /* format audio CD tracks command. */ sprintf( cmd, "%s -c \"%s\" -n table", ctx->prog, ctx->device ); /* Get tempory file path. */ path = tempnam(NULL, "stdo"); if(path == NULL) return(track); /* Execute command. */ p = ExecBO(cmd, path); if(p > 0) { /* Command executed successfully. */ int i, line_num = 0; char *buf = NULL; FILE *fp = FOpen(path, "rb"); /* Begin reading all lines from tempory output file. */ while(1) { /* Deallocate previous line and read next line. */ free(buf); buf = FGetStringLiteral(fp); if(buf == NULL) break; /* Skip header (first 4 lines). */ if(line_num > 4) { int hours, minutes, seconds; const char *s = buf; /* Seek s to first argument. */ while(ISBLANK(*s)) s++; /* Skip '*' character infront of current track. */ if(*s == '*') { s++; while(ISBLANK(*s)) s++; } /* Allocate a new track structure. */ i = *total; *total = i + 1; track = (AudioCDTrack **)realloc( track, (*total) * sizeof(AudioCDTrack *) ); if(track == NULL) { *total = 0; continue; } track[i] = t = (AudioCDTrack *)calloc( 1, sizeof(AudioCDTrack) ); if(t == NULL) continue; /* Begin parsing line. */ /* Track number. */ t->number = MAX(atoi(s), 1); /* Seek s to next argument. */ while(!ISBLANK(*s) && (*s != '\0')) s++; while(ISBLANK(*s)) s++; /* Track start. */ hours = atoi(s); while((*s != ':') && (*s != '\0')) s++; if(*s == ':') s++; minutes = atoi(s); while((*s != ':') && (*s != '\0')) s++; if(*s == ':') s++; seconds = atoi(s); t->start_time = (hours * 3600) + (minutes * 60) + seconds; /* Seek s to next argument. */ while(!ISBLANK(*s) && (*s != '\0')) s++; while(ISBLANK(*s)) s++; /* Track length. */ minutes = atoi(s); while((*s != ':') && (*s != '\0')) s++; if(*s == ':') s++; seconds = atoi(s); t->length = (minutes * 60) + seconds; /* Seek s to next argument. */ while(!ISBLANK(*s) && (*s != '\0')) s++; while(ISBLANK(*s)) s++; /* Name (last argument). */ t->name = strdup(s); } line_num++; } /* Close tempory output file. */ FClose(fp); } /* Delete tempory file path. */ if(path != NULL) { unlink(path); free(path); path = NULL; } return(track); } /* * Deletes the list of audio CD track list. */ void AudioCDDeleteTracksList(AudioCDTrack **track, int total) { int i; AudioCDTrack *t; for(i = 0; i < total; i++) { t = track[i]; if(t == NULL) continue; free(t->name); free(t); } free(track); } /* * Returns the track number that was last played or 0 if stop * or eject was called. */ int AudioCDLastTrack(AudioCDContext *ctx) { return((ctx != NULL) ? ctx->current_track_number : 0); } /* * Plays the track specified by track_number. */ void AudioCDPlayTrack(AudioCDContext *ctx, int track_number) { pid_t p; char cmd[PATH_MAX + NAME_MAX + 1024]; if((ctx == NULL) || (track_number < 1)) return; if((ctx->prog == NULL) || (ctx->device == NULL)) return; /* format audio CD tracks command. */ sprintf( cmd, "%s -c \"%s\" play %i", ctx->prog, ctx->device, track_number ); /* Execute command. */ p = Exec(cmd); if(p > 0) ctx->current_track_number = track_number; } /* * Stop playing. */ void AudioCDStop(AudioCDContext *ctx) { pid_t p; char cmd[PATH_MAX + NAME_MAX + 1024]; if(ctx == NULL) return; if((ctx->prog == NULL) || (ctx->device == NULL)) return; /* format audio CD tracks command. */ sprintf( cmd, "%s -c \"%s\" -n stop", ctx->prog, ctx->device ); /* Execute command. */ p = Exec(cmd); if(p > 0) ctx->current_track_number = 0; } /* * Ejects audio CD from the device. */ void AudioCDEject(AudioCDContext *ctx) { pid_t p; char cmd[PATH_MAX + NAME_MAX + 1024]; if(ctx == NULL) return; if((ctx->prog == NULL) || (ctx->device == NULL)) return; /* format audio CD tracks command. */ sprintf( cmd, "/usr/bin/eject -r \"%s\"", ctx->device ); /* Execute command. */ p = Exec(cmd); if(p > 0) ctx->current_track_number = 0; }