/* 2004.02.01 first released source code for IOMP */ #define load() /* nothing */ void strmcpy (char **t, char *s); #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef linux #include #else #include #endif /* linux */ #include "struct.h" #include //void *malloc(); //char *strchr(); extern struct play *playlist; extern struct cdinfo thiscd, *cd; static int start_play_time_tick = 0; /* 1/100 second */ static int start_playing_pos = 0; /* 1/75 second */ static int pause_status = 0; /* not pause */ static int pause_time_tick = 0; int cd_fd = -1; /* * The minimum volume setting for the Sun and DEC CD-ROMs is 128 but for other * machines this might not be the case. */ int min_volume = 128; int max_volume = 255; char *cd_device; int cur_track, cur_index, cur_lasttrack, cur_firsttrack, cur_pos_abs, cur_frame, cur_pos_rel, cur_tracklen, cur_cdlen, cur_ntracks, cur_nsections, cur_cdmode, cur_listno, cur_stopmode, exit_on_eject, cur_balance; char *cur_artist, *cur_cdname, *cur_trackname; char cur_contd, cur_avoid; /* * read_toc() * * Read the table of contents from the CD. Return a pointer to a cdinfo * struct containing the relevant information (minus artist/cdname/etc.) * This is a static struct. Returns NULL if there was an error. * * XXX allocates one trackinfo too many. */ struct cdinfo * read_toc() { struct playlist *l; struct cdrom_tochdr hdr; struct cdrom_tocentry entry; int i, pos; if (cd_fd < 0) return(NULL); if (ioctl(cd_fd, CDROMREADTOCHDR, &hdr)) { perror("readtochdr"); return (NULL); } thiscd.artist[0] = thiscd.cdname[0] = '\0'; thiscd.whichdb = thiscd.otherrc = thiscd.otherdb = NULL; thiscd.length = 0; thiscd.autoplay = thiscd.playmode = thiscd.volume = 0; thiscd.ntracks = hdr.cdth_trk1; if (thiscd.lists != NULL) { for (l = thiscd.lists; l->name != NULL; l++) { free(l->name); free(l->list); } free(thiscd.lists); thiscd.lists = NULL; } if (thiscd.trk != NULL) free(thiscd.trk); thiscd.trk = malloc((thiscd.ntracks + 1) * sizeof(struct trackinfo)); if (thiscd.trk == NULL) { perror("malloc"); return (NULL); } for (i = 0; i <= thiscd.ntracks; i++) { if (i == thiscd.ntracks) entry.cdte_track = CDROM_LEADOUT; else entry.cdte_track = i + 1; entry.cdte_format = CDROM_MSF; if (ioctl(cd_fd, CDROMREADTOCENTRY, &entry)) { perror("tocentry read"); return (NULL); } thiscd.trk[i].data = thiscd.trk[i].avoid = entry.cdte_ctrl & CDROM_DATA_TRACK ? 1 : 0; thiscd.trk[i].length = entry.cdte_addr.msf.minute * 60 + entry.cdte_addr.msf.second; thiscd.trk[i].start = thiscd.trk[i].length * 75 + entry.cdte_addr.msf.frame; thiscd.trk[i].songname = thiscd.trk[i].otherrc = thiscd.trk[i].otherdb = NULL; thiscd.trk[i].contd = 0; thiscd.trk[i].volume = 0; thiscd.trk[i].track = i + 1; thiscd.trk[i].section = 0; } /* Now compute actual track lengths. */ pos = thiscd.trk[0].length; for (i = 0; i < thiscd.ntracks; i++) { thiscd.trk[i].length = thiscd.trk[i+1].length - pos; pos = thiscd.trk[i+1].length; if (thiscd.trk[i].data) thiscd.trk[i].length = (thiscd.trk[i + 1].start - thiscd.trk[i].start) * 2; if (thiscd.trk[i].avoid) strmcpy(&thiscd.trk[i].songname, "DATA TRACK"); } thiscd.length = thiscd.trk[thiscd.ntracks].length; return (&thiscd); } /* * cd_status() * * Return values: * * 0 No CD in drive. * 1 CD in drive. * 2 CD has just been inserted (TOC has been read) * 3 CD has just been removed * * Updates cur_track, cur_pos_rel, cur_pos_abs and other variables. */ int cd_status() { char realname[MAXPATHLEN]; static int warned = 0; struct cdrom_subchnl sc; int ret = 1; if (cd_fd < 0) { if ((cd_fd = open(cd_device, 0)) < 0) { if (errno == EACCES) { if (!warned) { strcpy(realname, cd_device); fprintf(stderr, "As root, please run\n\nchmod 666 %s\n\n%s\n", realname, "to give yourself permission to access the CD-ROM device."); warned++; } } else if (errno != ENXIO) { perror(cd_device); if (thiscd.trk != NULL) free(thiscd.trk); exit(1); } return (0); } cur_cdmode = 5; } sc.cdsc_format = CDROM_MSF; if (ioctl(cd_fd, CDROMSUBCHNL, &sc)) { cur_cdmode = 5; cur_track = -1; cur_cdlen = cur_tracklen = 1; cur_pos_abs = cur_pos_rel = cur_frame = 0; if (exit_on_eject) exit(0); return (0); } if (cur_cdmode == 5) /* CD has been ejected */ { cur_pos_rel = cur_pos_abs = cur_frame = 0; if ((cd = read_toc()) == NULL) { close(cd_fd); cd_fd = -1; if (exit_on_eject) exit(0); else return (0); } cur_nsections = 0; cur_ntracks = cd->ntracks; cur_cdlen = cd->length; load(); cur_artist = cd->artist; cur_cdname = cd->cdname; cur_cdmode = 4; ret = 2; } switch (sc.cdsc_audiostatus) { case CDROM_AUDIO_PLAY: cur_cdmode = 1; dopos: cur_pos_abs = sc.cdsc_absaddr.msf.minute * 60 + sc.cdsc_absaddr.msf.second; cur_frame = cur_pos_abs * 75 + sc.cdsc_absaddr.msf.frame; /* Only look up the current track number if necessary. */ if (cur_track < 1 || cur_frame < cd->trk[cur_track-1].start || cur_frame >= (cur_track >= cur_ntracks ? (cur_cdlen + 1) * 75 : cd->trk[cur_track].start)) { cur_track = 0; while (cur_track < cur_ntracks && cur_frame >= cd->trk[cur_track].start) cur_track++; } if (cur_track >= 1 && sc.cdsc_trk > cd->trk[cur_track-1].track) cur_track++; cur_index = sc.cdsc_ind; doall: if (cur_track >= 1 && cur_track <= cur_ntracks) { cur_trackname = cd->trk[cur_track-1].songname; cur_avoid = cd->trk[cur_track-1].avoid; cur_contd = cd->trk[cur_track-1].contd; cur_pos_rel = (cur_frame - cd->trk[cur_track-1].start) / 75; if (cur_pos_rel < 0) cur_pos_rel = -cur_pos_rel; } /* note: workbone requires playlist == NULL always! */ if (playlist != NULL && playlist[0].start) { cur_pos_abs -= cd->trk[playlist[cur_listno-1]. start - 1].start / 75; cur_pos_abs += playlist[cur_listno-1].starttime; } if (cur_pos_abs < 0) cur_pos_abs = cur_frame = 0; if (cur_track < 1) cur_tracklen = cd->length; else cur_tracklen = cd->trk[cur_track-1].length; break; case CDROM_AUDIO_PAUSED: if (cur_cdmode == 1 || cur_cdmode == 3) { cur_cdmode = 3; goto dopos; } else cur_cdmode = 4; goto doall; case CDROM_AUDIO_COMPLETED: cur_cdmode = 0; /* waiting for next track. */ break; case CDROM_AUDIO_NO_STATUS: cur_cdmode = 4; cur_lasttrack = cur_firsttrack = -1; goto doall; } return (ret); } int cd_check(void) { struct cdrom_subchnl cs; if(ioctl(cd_fd,CDROMSUBCHNL,&cs)){return(-1);} return cs.cdsc_audiostatus; } /* * pause_cd() * * Pause the CD, if it's in play mode. If it's already paused, go back to * play mode. */ void pause_cd() { if (cd_fd < 0) /* do nothing if there's no CD! */ return; ioctl(cd_fd, CDROMPAUSE); if (pause_status==0) { pause_status = 1; pause_time_tick = times(NULL); } } void resume_cd() { if (cd_fd < 0) /* do nothing if there's no CD! */ return; ioctl(cd_fd, CDROMRESUME); if (pause_status==1) { start_play_time_tick += (times(NULL) - pause_time_tick); pause_status = 0; pause_time_tick = 0; } } /* * stop_cd() * * Stop the CD if it's not already stopped. */ void stop_cd() { if (cd_fd < 0) return; cur_lasttrack = cur_firsttrack = -1; cur_cdmode = 4; ioctl(cd_fd, CDROMSTOP); cur_track = 1; if(ioctl(cd_fd, CDROM_LOCKDOOR, 0) < 0) perror("cdrom tray unlock"); close(cd_fd); cd_fd = -1; #if 0 pause_status = 1; start_play_time_tick = 0; start_playing_pos = 0; pause_time_tick = 0; #endif } /* * play_chunk(start, end) * * Play the CD from one position to another (both in frames.) */ void play_chunk(start, end) int start, end; { struct cdrom_msf msf; struct cdrom_volctrl vol; if (cd == NULL || cd_fd < 0) return; end--; if (start >= end) start = end-1; msf.cdmsf_min0 = start / (60*75); msf.cdmsf_sec0 = (start % (60*75)) / 75; msf.cdmsf_frame0 = start % 75; msf.cdmsf_min1 = end / (60*75); msf.cdmsf_sec1 = (end % (60*75)) / 75; msf.cdmsf_frame1 = end % 75; vol.channel0 = 180; vol.channel1 = 180; vol.channel2 = 180; vol.channel3 = 180; if (ioctl(cd_fd, CDROMVOLCTRL, &vol)) { perror("CDROMVOLCTRL"); return; } if (ioctl(cd_fd, CDROMSTART)) { perror("CDROMSTART"); return; } if (ioctl(cd_fd, CDROMPLAYMSF, &msf)) { printf("play(%d,%d)\n",start,end); printf("msf = %d:%d:%d %d:%d:%d\n", msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0, msf.cdmsf_min1, msf.cdmsf_sec1, msf.cdmsf_frame1); perror("CDROMPLAYMSF"); return; } } /* * play_cd(starttrack, pos, endtrack) * * Start playing the CD or jump to a new position. "pos" is in seconds, * relative to start of track. */ void play_cd(start, pos, end) int start, pos, end; { cd_status(); if (cd == NULL || cd_fd < 0) return; cur_firsttrack = start; start--; end--; cur_lasttrack = end; play_chunk(cd->trk[start].start + pos * 75, end >= cur_ntracks ? cur_cdlen * 75 : cd->trk[end].start - 1); start_play_time_tick = times(NULL); start_playing_pos = cd->trk[start].start + pos * 75; pause_status = 0; pause_time_tick = 0; } static int get_current_playing_tick() { if (cur_cdmode == 1||cur_cdmode==3) { /* 1==>playing 3==>pause */ if (pause_status==1) { return pause_time_tick-start_play_time_tick; } else { return times(NULL)-start_play_time_tick; } } return 0; } static int get_current_playing_track() { int ticks = get_current_playing_tick(); int cd_pos = ticks * 3 / 4 + start_playing_pos; int i; for (i=1; i<= cur_ntracks; i++) { if (cd_pos<=cd->trk[i].start) { return i; } } return cur_ntracks; } static int update_track_info() { cur_track = get_current_playing_track(); //printf("check current track=%d\n", cur_track); return 0; } void play_to_next() { if (cur_cdmode == 1) { update_track_info(); if (cur_track >= cur_ntracks) return; cur_track++; play_cd(cur_track, 0, 9999);//cur_ntracks); } } #define SEEK_OFFSET 40 /* 10 seconds */ /* for seek */ void play_to_prev_seek() { int cd_pos, ticks; if (cur_cdmode == 1 ) { ticks = get_current_playing_tick(); cd_pos = ticks * 3 / 4 + start_playing_pos - SEEK_OFFSET*75; update_track_info(); if (cur_track<=1) { play_cd(cur_track, 0, 9999); return; } cur_track--; play_cd(cur_track, (cd_pos - cd->trk[cur_track-1].start)/75, 9999); } } void seek_backward() { int ticks, cd_pos; update_track_info(); ticks = get_current_playing_tick(); cd_pos = ticks * 3 / 4 + start_playing_pos - SEEK_OFFSET*75; if (cd_pos < cd->trk[cur_track-1].start) { //play_cd(cur_track, 0, 9999); play_to_prev_seek(); } else { play_cd(cur_track, (cd_pos - cd->trk[cur_track-1].start)/75, 9999); } } void seek_forward() { int ticks, cd_pos; update_track_info(); ticks = get_current_playing_tick(); cd_pos = ticks * 3 / 4 + start_playing_pos + SEEK_OFFSET*75; if (cur_track>=cur_ntracks) { if (cd_pos > cd->trk[cur_ntracks].start) { stop_cd(); exit(0); return; } play_cd(cur_ntracks, (cd_pos - cd->trk[cur_ntracks-1].start)/75, 9999); } else { if (cd_pos > cd->trk[cur_track].start) { if (cur_cdmode == 1) { update_track_info(); if (cur_track >= cur_ntracks) { stop_cd(); exit(0); /* terminate */ } cur_track++; play_cd(cur_track, 0, 9999);//cur_ntracks); } return; /* seek to the tail */ } play_cd(cur_track, (cd_pos - cd->trk[cur_track-1].start)/75, 9999); } } void play_to_prev() { if (cur_cdmode == 1) { update_track_info(); if (cur_track <= 1) return; cur_track--; play_cd(cur_track, 0, 9999);//cur_ntracks); } } /* * Eject the current CD, if there is one, and set the mode to 5. * * Returns 0 on success, 1 if the CD couldn't be ejected, or 2 if the * CD contains a mounted filesystem. */ int eject_cd() { struct stat stbuf; struct ustat ust; if (cur_cdmode == 5) /* Already ejected! */ return (0); if (fstat(cd_fd, &stbuf) != 0) { perror("fstat"); return (1); } /* Is this a mounted filesystem? */ if (ustat(stbuf.st_rdev, &ust) == 0) return (2); if (ioctl(cd_fd, CDROMEJECT)) { perror("CDEJECT"); return (1); } if (exit_on_eject) exit(0); cur_track = -1; cur_cdlen = cur_tracklen = 1; cur_pos_abs = cur_pos_rel = cur_frame = 0; cur_cdmode = 5; return (0); } #include #include #include typedef struct _info_msg_t { long msgtype; unsigned short code; char data[1024]; } info_msg_t; int read_info() { static int msg_id = -1; info_msg_t msg_t; int pos = 0; if (msg_id == -1) { msg_id = msgget(45160, O_WRONLY); } if (msg_id == -1) return -1; //printf("pause=%d\n", pause_status); memset(&msg_t,sizeof(msg_t),0); if (cur_cdmode == 1||cur_cdmode==3) { /* 1==>playing 3==>pause */ if (pause_status==1) { pos = pause_time_tick-start_play_time_tick; } else { pos = times(NULL)-start_play_time_tick; update_track_info(); //printf("cur_track = %d\n", cur_track); } //printf("time=%d = %d sec\n", pos,pos/75); sprintf(msg_t.data,"pause=%d cur_track=%d time=%d", pause_status,cur_track,pos/75); } msg_t.msgtype = 100; msg_t.code = 1; msgsnd(msg_id,&msg_t,sizeof(msg_t) - sizeof(long),0); return 0; }