#include #include #include #include #include #include #include #include static const char *datafile = "cdda.raw"; /* * This number is 44100 * 2 * 2 / 75, that is, * bytes/frame = samples/sec * channels/sample * bytes/channel / frames/sec */ #define FRAMEBYTES 2352 #include "blocker.h" #include "stringgetter.h" static const char *cddir; static unsigned char *play_data; static unsigned int play_maplen; static unsigned int play_start; static unsigned int play_len; static int play_prep(const char *cdname, int start, int length, FILE *errf) { char *path; int fd; struct stat stb; int end; char *mmrv; end = start + length; if ( (start < 0) || (length < 0) || (end < 0) || (end > 0x7fffffff/FRAMEBYTES) ) { fprintf(errf,"start/length out of range\n"); return(-1); } asprintf(&path,"%s/%s/%s",cddir,cdname,datafile); fd = open(path,O_RDONLY,0); if (fd < 0) { fprintf(errf,"%s open: %s\n",cdname,strerror(errno)); return(-1); } if (fstat(fd,&stb) < 0) { fprintf(errf,"%s fstat: %s\n",cdname,strerror(errno)); close(fd); return(-1); } play_maplen = stb.st_size; if (play_maplen != stb.st_size) { fprintf(errf,"%s: data file too big\n",cdname); close(fd); return(-1); } mmrv = mmap(0,play_maplen,PROT_READ,MAP_FILE|MAP_SHARED,fd,0); if (mmrv == MAP_FAILED) { fprintf(errf,"%s mmap: %s\n",cdname,strerror(errno)); close(fd); return(-1); } play_data = mmrv; play_start = start * FRAMEBYTES; play_len = length * FRAMEBYTES; close(fd); return(0); } static void play_do(void) { int w; fflush(stdout); while (play_len > 0) { w = write(1,play_data+play_start,play_len); if (w <= 0) exit(1); play_len -= w; play_start += w; } munmap(play_data,play_maplen); } int main(int, char **); int main(int ac, char **av) { FILE *b; STRINGGETTER *g; STRINGGOT line; char *cdname; int start; int length; int get(void *arg __attribute__((__unused__))) { return(getc(b)); } if (ac != 2) exit(1); cddir = av[1]; g = sg_init_pull(&get,&sg_term_nul,0); cdname = 0; while (1) { free(cdname); b = fwrap_r_blocked(stdin); line = sg_get(g); if (line.len < 0) break; cdname = strdup(line.str); line = sg_get(g); if (line.len < 0) break; start = atoi(line.str); line = sg_get(g); if (line.len < 0) break; length = atoi(line.str); if (getc(b) != EOF) break; fclose(b); b = fwrap_w_blocked(stdout); if (play_prep(cdname,start,length,b) < 0) { fprintf(b,"CD play failed.\n"); fclose(b); continue; } fclose(b); play_do(); } sg_done(g); return(0); }