📄 cdaudio.c
字号:
{ pthread_join(dae_data.thread, NULL); cdda_ip.output->close_audio(); } else ioctl(cdda_playing.fd, XMMS_PAUSE, 0); close(cdda_playing.fd); cdda_playing.fd = -1; if (!cdda_playing.drive.dae) { to_info = g_malloc(sizeof (*to_info)); to_info->device = g_strdup(cdda_playing.drive.device); to_info->id = gtk_timeout_add(STOP_DELAY * 100, stop_timeout, to_info); timeout_list = g_list_prepend(timeout_list, to_info); }}static void cdda_pause(short p){ if (cdda_playing.drive.dae) { cdda_ip.output->pause(p); return; } if (p) { pause_time = get_time(); ioctl(cdda_playing.fd, XMMS_PAUSE, 0); } else { ioctl(cdda_playing.fd, XMMS_RESUME, 0); pause_time = -1; } is_paused = p;}#ifdef XMMS_CDROM_SOLARIS/* * Lowlevel cdrom access, Solaris style (Solaris, Linux) */static void play_ioctl(struct cdda_msf *start, struct cdda_msf *end){ struct cdrom_msf msf; msf.cdmsf_min0 = start->minute; msf.cdmsf_sec0 = start->second; msf.cdmsf_frame0 = start->frame; msf.cdmsf_min1 = end->minute; msf.cdmsf_sec1 = end->second; msf.cdmsf_frame1 = end->frame; ioctl(cdda_playing.fd, CDROMPLAYMSF, &msf);}static int get_current_frame(void){ struct cdrom_subchnl subchnl; subchnl.cdsc_format = CDROM_MSF; if (ioctl(cdda_playing.fd, CDROMSUBCHNL, &subchnl) < 0) return -1; switch (subchnl.cdsc_audiostatus) { case CDROM_AUDIO_COMPLETED: case CDROM_AUDIO_ERROR: return -1; } return (LBA(subchnl.cdsc_absaddr.msf));}#if !defined(CDROMVOLREAD)static int volume_left = 100, volume_right = 100;#endifstatic void drive_get_volume(int *l, int *r){#if defined(CDROMVOLREAD) struct cdrom_volctrl vol; if (cdda_playing.fd!=-1 && !ioctl(cdda_playing.fd, CDROMVOLREAD, &vol)) { *l = (100 * vol.channel0) / 255; *r = (100 * vol.channel1) / 255; }#if 0 else if (cdda_playing.fd != -1) g_message("CDROMVOLREAD failed");#endif#else *l = volume_left; *r = volume_right;#endif}static void drive_set_volume(int l, int r){ struct cdrom_volctrl vol; if (cdda_playing.fd != -1) { vol.channel0 = vol.channel2 = (l * 255) / 100; vol.channel1 = vol.channel3 = (r * 255) / 100; ioctl(cdda_playing.fd, CDROMVOLCTRL, &vol); }#if !defined(CDROMVOLREAD) volume_left = l; volume_right = r;#endif}#ifdef CDROMREADAUDIOint read_audio_data(int fd, int pos, int num, void *buf){ struct cdrom_read_audio cdra;#if 1 cdra.addr.lba = pos - CDDA_MSF_OFFSET; cdra.addr_format = CDROM_LBA;#else cdra.addr.msf.minute = pos / (60 * 75); cdra.addr.msf.second = (pos / 75) % 60; cdra.addr.msf.frame = pos % 75; cdra.addr_format = CDROM_MSF;#endif cdra.nframes = num; cdra.buf = buf; if (ioctl(fd, CDROMREADAUDIO, &cdra) < 0) return -errno; return cdra.nframes;}#endif /* CDROMREADAUDIO */#if defined(CDROMCDDA)int read_audio_data(int fd, int pos, int num, void *buf){ struct cdrom_cdda cdra; cdra.cdda_addr = pos - CDDA_MSF_OFFSET; cdra.cdda_length = num; cdra.cdda_data = buf; cdra.cdda_subcode = CDROM_DA_NO_SUBCODE; if (ioctl(fd, CDROMCDDA, &cdra) < 0) return -errno; return cdra.cdda_length;}#endifstatic gboolean cdda_get_toc_lowlevel(int fd, cdda_disc_toc_t *info){ struct cdrom_tochdr tochdr; struct cdrom_tocentry tocentry; int i; if (ioctl(fd, CDROMREADTOCHDR, &tochdr)) return FALSE; for (i = tochdr.cdth_trk0; i <= tochdr.cdth_trk1; i++) { tocentry.cdte_format = CDROM_MSF; tocentry.cdte_track = i; if (ioctl(fd, CDROMREADTOCENTRY, &tocentry)) return FALSE; info->track[i].minute = tocentry.cdte_addr.msf.minute; info->track[i].second = tocentry.cdte_addr.msf.second; info->track[i].frame = tocentry.cdte_addr.msf.frame; info->track[i].flags.data_track = tocentry.cdte_ctrl == CDROM_DATA_TRACK; } /* Get the leadout track */ tocentry.cdte_track = CDROM_LEADOUT; tocentry.cdte_format = CDROM_MSF; if (ioctl(fd, CDROMREADTOCENTRY, &tocentry)) return FALSE; info->leadout.minute = tocentry.cdte_addr.msf.minute; info->leadout.second = tocentry.cdte_addr.msf.second; info->leadout.frame = tocentry.cdte_addr.msf.frame; info->first_track = tochdr.cdth_trk0; info->last_track = tochdr.cdth_trk1; return TRUE;}#endif#ifdef XMMS_CDROM_BSD/* * Lowlevel cdrom access, BSD style (FreeBSD, OpenBSD, NetBSD, Darwin) */static void play_ioctl(struct cdda_msf *start, struct cdda_msf *end){ struct ioc_play_msf msf; msf.start_m = start->minute; msf.start_s = start->second; msf.start_f = start->frame; msf.end_m = end->minute; msf.end_s = end->second; msf.end_f = end->frame; ioctl(cdda_playing.fd, CDIOCPLAYMSF, &msf);}static int get_current_frame(void){ struct ioc_read_subchannel subchnl; struct cd_sub_channel_info subinfo; subchnl.address_format = CD_MSF_FORMAT; subchnl.data_format = CD_CURRENT_POSITION; subchnl.track = 0; subchnl.data_len = sizeof(subinfo); subchnl.data = &subinfo; if (ioctl(cdda_playing.fd, CDIOCREADSUBCHANNEL, &subchnl) < 0) return -1;#ifdef XMMS_CDROM_BSD_DARWIN return ((subchnl.data->what.position.absaddr[1] * 60 subchnl.data->what.position.absaddr[2]) * 75 + subchnl.data->what.position.absaddr[3]);#else return (LBA(subchnl.data->what.position.absaddr.msf));#endif}static void drive_get_volume(int *l, int *r){ struct ioc_vol vol; if (cdda_playing.fd != -1) { ioctl(cdda_playing.fd, CDIOCGETVOL, &vol); *l = (100 * vol.vol[0]) / 255; *r = (100 * vol.vol[1]) / 255; }}static void drive_set_volume(int l, int r){ struct ioc_vol vol; if (cdda_playing.fd != -1) { vol.vol[0] = vol.vol[2] = (l * 255) / 100; vol.vol[1] = vol.vol[3] = (r * 255) / 100; ioctl(cdda_playing.fd, CDIOCSETVOL, &vol); }}#ifdef __FreeBSD__# if defined(CDIOCREADAUDIO)/* Digital extraction before ATAng */int read_audio_data(int fd, int pos, int num, void *buf){ struct ioc_read_audio cdra; cdra.address.lba = pos - CDDA_MSF_OFFSET; cdra.address_format = CD_LBA_FORMAT; cdra.nframes = num; cdra.buffer = buf; if (ioctl(fd, CDIOCREADAUDIO, &cdra) < 0) return -errno; return cdra.nframes;}# else/* Digital extraction with ATAng */int read_audio_data(int fd, int pos, int num, void *buf){ int bsize = 2352; if (ioctl(fd, CDRIOCSETBLOCKSIZE, &bsize) == -1) return -errno; if (pread(fd, buf, num*bsize, (pos - 150)*bsize) != num*bsize) return 0; return num; }# endif /* CDIOCREADAUDIO */#endif#ifdef XMMS_CDROM_BSD_NETBSD /* NetBSD, OpenBSD */static gboolean cdda_get_toc_lowlevel(int fd, cdda_disc_toc_t *info){ struct ioc_toc_header tochdr; struct ioc_read_toc_entry tocentry; struct cd_toc_entry tocentrydata; int i; if (ioctl(fd, CDIOREADTOCHEADER, &tochdr)) return FALSE; for (i = tochdr.starting_track; i <= tochdr.ending_track; i++) { tocentry.address_format = CD_MSF_FORMAT; tocentry.starting_track = i; tocentry.data = &tocentrydata; tocentry.data_len = sizeof(tocentrydata); if (ioctl(fd, CDIOREADTOCENTRYS, &tocentry)) return FALSE; info->track[i].minute = tocentry.data->addr.msf.minute; info->track[i].second = tocentry.data->addr.msf.second; info->track[i].frame = tocentry.data->addr.msf.frame; info->track[i].flags.data_track = (tocentry.data->control & 4) == 4; } /* Get the leadout track */ tocentry.address_format = CD_MSF_FORMAT; tocentry.starting_track = 0xAA; tocentry.data = &tocentrydata; tocentry.data_len = sizeof(tocentrydata); if (ioctl(fd, CDIOREADTOCENTRYS, &tocentry)) return FALSE; info->leadout.minute = tocentry.data->addr.msf.minute; info->leadout.second = tocentry.data->addr.msf.second; info->leadout.frame = tocentry.data->addr.msf.frame; info->first_track = tochdr.starting_track; info->last_track = tochdr.ending_track; return TRUE;}#elif defined(XMMS_CDROM_BSD_DARWIN)static gboolean cdda_get_toc_lowlevel(int fd, cdda_disc_toc_t *info){ struct ioc_toc_header tochdr; struct ioc_read_toc_entry tocentry; int i; if (ioctl(fd, CDIOREADTOCHEADER, &tochdr)) return FALSE; for (i = tochdr.starting_track; i <= tochdr.ending_track; i++) { tocentry.address_format = CD_MSF_FORMAT; tocentry.starting_track = i; if (ioctl(fd, CDIOREADTOCENTRYS, &tocentry)) return FALSE; info->track[i].minute = tocentry.data->addr[1]; info->track[i].second = tocentry.data->addr[2]; info->track[i].frame = tocentry.data->addr[3]; info->track[i].flags.data_track = (tocentry.data->control & 4) == 4; } /* Get the leadout track */ tocentry.address_format = CD_MSF_FORMAT; tocentry.starting_track = 0xAA; if (ioctl(fd, CDIOREADTOCENTRYS, &tocentry)) return FALSE; info->leadout.minute = tocentry.data->addr[1]; info->leadout.second = tocentry.data->addr[2]; info->leadout.frame = tocentry.data->addr[3]; return TRUE;}#else /* FreeBSD */static gboolean cdda_get_toc_lowlevel(int fd, cdda_disc_toc_t *info){ struct ioc_toc_header tochdr; struct ioc_read_toc_single_entry tocentry; int i; if (ioctl(fd, CDIOREADTOCHEADER, &tochdr)) return FALSE; for (i = tochdr.starting_track; i <= tochdr.ending_track; i++) { tocentry.address_format = CD_MSF_FORMAT; tocentry.track = i; if (ioctl(fd, CDIOREADTOCENTRY, &tocentry)) return FALSE; info->track[i].minute = tocentry.entry.addr.msf.minute; info->track[i].second = tocentry.entry.addr.msf.second; info->track[i].frame = tocentry.entry.addr.msf.frame; info->track[i].flags.data_track = (tocentry.entry.control & 4) == 4; } /* Get the leadout track */ tocentry.address_format = CD_MSF_FORMAT; tocentry.track = 0xAA; if (ioctl(fd, CDIOREADTOCENTRY, &tocentry)) return FALSE; info->leadout.minute = tocentry.entry.addr.msf.minute; info->leadout.second = tocentry.entry.addr.msf.second; info->leadout.frame = tocentry.entry.addr.msf.frame; info->first_track = tochdr.starting_track; info->last_track = tochdr.ending_track; return TRUE;}#endif#endifstatic void seek(int time){ struct cdda_msf *end, start; int track = cdda_playing.track; if (cdda_playing.drive.dae) { dae_data.seek = time; while (dae_data.seek != -1) xmms_usleep(20000); return; } start.minute = (cdda_playing.cd_toc.track[track].minute * 60 + cdda_playing.cd_toc.track[track].second + time) / 60; start.second = (cdda_playing.cd_toc.track[track].second + time) % 60; start.frame = cdda_playing.cd_toc.track[track].frame; if (track == cdda_playing.cd_toc.last_track) end = &cdda_playing.cd_toc.leadout; else end = &cdda_playing.cd_toc.track[track + 1]; play_ioctl(&start, end); if (is_paused) { cdda_pause(TRUE); pause_time = time * 1000; }}static int get_time_analog(void){ int frame, start_frame, length; int track = cdda_playing.track; if (is_paused && pause_time != -1) return pause_time; frame = get_current_frame(); if (frame == -1) return -1; start_frame = LBA(cdda_playing.cd_toc.track[track]); length = cdda_calculate_track_length(&cdda_playing.cd_toc, track); if (frame - start_frame >= length - 20) /* 20 seems to work better */ return -1; return ((frame - start_frame) * 1000) / 75;}static int get_time_dae(void){ if (dae_data.audio_error) return -2; if (!cdda_playing.playing || (dae_data.eof && !cdda_ip.output->buffer_playing())) return -1; return cdda_ip.output->output_time();}static int get_time(void){ if (cdda_playing.fd == -1) return -1; if (cdda_playing.drive.dae) return get_time_dae(); else return get_time_analog();}static void get_song_info(char *filename, char **title, int *len){ cdda_disc_toc_t toc; int t; char *tmp; struct driveinfo *drive; *title = NULL; *len = -1; if ((drive = cdda_find_drive(filename)) == NULL) return; tmp = strrchr(filename, '/'); if (tmp) tmp++; else tmp = filename; if (!sscanf(tmp, "Track %d.cda", &t)) return; if (!cdda_get_toc(&toc, drive->device)) return; if (t < toc.first_track || t > toc.last_track || toc.track[t].flags.data_track) return; *len = (cdda_calculate_track_length(&toc, t) * 1000) / 75; *title = cdda_get_title(&toc, t);}#ifdef HAVE_OSSstatic void oss_get_volume(int *l, int *r, int mixer_line){ int fd, v; fd = open(DEV_MIXER, O_RDONLY); if (fd != -1) { ioctl(fd, MIXER_READ(mixer_line), &v); *r = (v & 0xFF00) >> 8; *l = (v & 0x00FF); close(fd); }}static void oss_set_volume(int l, int r, int mixer_line){ int fd, v; fd = open(DEV_MIXER, O_RDONLY); if (fd != -1) { v = (r << 8) | l; ioctl(fd, MIXER_WRITE(mixer_line), &v); close(fd); }}#elsestatic void oss_get_volume(int *l, int *r, int mixer_line){}static void oss_set_volume(int l, int r, int mixer_line){}#endifstatic void get_volume(int *l, int *r){ if (cdda_playing.drive.dae) { if (cdda_ip.output->get_volume) cdda_ip.output->get_volume(l, r); } else if (cdda_playing.drive.mixer == CDDA_MIXER_OSS) oss_get_volume(l, r, cdda_playing.drive.oss_mixer); else if(cdda_playing.drive.mixer == CDDA_MIXER_DRIVE) drive_get_volume(l, r);}static void set_volume(int l, int r){ if (cdda_playing.drive.dae) cdda_ip.output->set_volume(l, r); else if (cdda_playing.drive.mixer == CDDA_MIXER_OSS) oss_set_volume(l, r, cdda_playing.drive.oss_mixer); else if (cdda_playing.drive.mixer == CDDA_MIXER_DRIVE) drive_set_volume(l, r);}gboolean cdda_get_toc(cdda_disc_toc_t *info, char *device){ gboolean retv = FALSE; int fd; if (is_mounted(device)) return FALSE; if ((fd = open(device, CDOPENFLAGS)) == -1) return FALSE; memset(info, 0, sizeof(cdda_disc_toc_t)); retv = cdda_get_toc_lowlevel(fd, info); close(fd); return retv;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -