在Debian上访问音频CD
這是一個為了進行調查所創建的示範程式。由於在Debian上很少有能夠訪問音頻光碟的示範程式,所以我將其放在這裡。我已經在Debian 9.5上進行了編譯和操作確認。
#include <stdio.h> // printf, perror
#include <fcntl.h> // open
#include <unistd.h> // close, write
#include <sys/ioctl.h> // ioctl
#include <string.h> // memset, memcpy
#include <stdlib.h> // malloc, free
#include <linux/cdrom.h> //
// ----------------------------------------------------------------------------
#define LBA2MIN(l) (__u8)((l / CD_FRAMES) / CD_SECS)
#define LBA2SEC(l) (__u8)((l / CD_FRAMES) % CD_SECS)
#define LBA2FRAME(l) (__u8)(l % CD_FRAMES)
#define MSF2LBA(m,s,f) (int)((m * CD_SECS + s) * CD_FRAMES + f - CD_MSF_OFFSET)
// ----------------------------------------------------------------------------
int cdrom_open(const char *pathname, int flags, mode_t mode)
{
int fd;
if ((fd = open(pathname, flags, mode)) < 0)
perror("cdrom_open: open");
return fd;
}
// ----------------------------------------------------------------------------
int cdrom_close(int *fd)
{
int ret;
if ((ret = close(*fd)) < 0)
perror("cdrom_close: close");
return ret;
}
// ----------------------------------------------------------------------------
off_t cdrom_lseek(int *fd, off_t offset, int whence)
{
off_t ret;
if ((ret = lseek(*fd, offset, whence)) < 0)
perror("cdrom_lseek: lseek");
return ret;
}
// ----------------------------------------------------------------------------
ssize_t cdrom_read(int *fd, void *buf, size_t count)
{
ssize_t ret;
if ((ret = read(*fd, buf, count)) < 0)
perror("cdrom_read: read");
return ret;
}
// ----------------------------------------------------------------------------
ssize_t cdrom_write(int *fd, const void *buf, size_t count)
{
ssize_t ret;
if ((ret = write(*fd, buf, count)) < 0)
perror("cdrom_write: write");
return ret;
}
// ----------------------------------------------------------------------------
int cdrom_ioctl(int *fd, unsigned long request, void *argp)
{
int ret;
if ((ret = ioctl(*fd, request, argp)) < 0)
perror("cdrom_ioctl: ioctl");
return ret;
}
// ----------------------------------------------------------------------------
int cdrom_read_tochdr(int *fd, struct cdrom_tochdr *header)
{
int ret;
memset(header, 0, sizeof(struct cdrom_tochdr));
if ((ret = ioctl(*fd, CDROMREADTOCHDR, header)) < 0)
perror("cdrom_read_tochdr: ioctl");
return ret;
}
// ----------------------------------------------------------------------------
int cdrom_read_tocentry(int *fd, struct cdrom_tocentry *entry)
{
int ret;
struct cdrom_tocentry p;
memset(&p, 0, sizeof(struct cdrom_tocentry));
p.cdte_format = entry->cdte_format;
p.cdte_track = entry->cdte_track;
if ((ret = ioctl(*fd, CDROMREADTOCENTRY, &p)) < 0)
perror("cdrom_read_tocentry: ioctl");
memcpy(entry, &p, sizeof(struct cdrom_tocentry));
return ret;
}
// ----------------------------------------------------------------------------
int cdrom_reset(int *fd)
{
int ret;
if ((ret = ioctl(*fd, CDROMRESET, 0)) < 0)
perror("cdrom_reset: ioctl");
return ret;
}
// ----------------------------------------------------------------------------
int cdrom_select_speed(int *fd, int speed)
{
int ret;
if (!speed)
speed = 0xffff; // set to max
else
speed *= 177; // Nx to kbytes/s
if ((ret = ioctl(*fd, CDROM_SELECT_SPEED, speed)) < 0)
perror("cdrom_select_speed: ioctl");
return ret;
}
// ----------------------------------------------------------------------------
int cdrom_get_mcn(int *fd, struct cdrom_mcn *mcn)
{
int ret = 0;
memset(mcn, 0, sizeof(struct cdrom_mcn));
if ((ret = ioctl(*fd, CDROM_GET_MCN, mcn)) < 0)
perror("cdrom_get_mcn: ioctl");
return ret;
}
// ----------------------------------------------------------------------------
int cdrom_read_audio(int *fd, struct cdrom_read_audio *ra)
{
int ret = 0;
memset(ra->buf, 0, (ra->nframes * CD_FRAMESIZE_RAW));
if ((ret = ioctl(*fd, CDROMREADAUDIO, ra)) < 0)
perror("cdrom_read_audio: ioctl");
return ret;
}
// ----------------------------------------------------------------------------
int main(int argc, char *argv[])
{
int ret = 0;
int ifd, ofd;
char *ipathname = "/dev/cdrom";
char *opathname = "./dump.bin";
struct cdrom_tochdr header;
struct cdrom_tocentry entry[99];
struct cdrom_mcn mcn;
struct cdrom_read_audio ra;
int i, trk, lba0, lba1;
// --- cdrom_open -------------------------------------------------------------
if ((ifd = cdrom_open(ipathname, O_RDONLY | O_NONBLOCK, 0)) < 0)
return -1;
// --- cdrom_reset ------------------------------------------------------------
/* if (cdrom_reset(&ifd) < 0) {
cdrom_close(&ifd);
return -1;
}*/
// --- cdrom_select_speed -----------------------------------------------------
if (cdrom_select_speed(&ifd, 0) < 0) {
cdrom_close(&ifd);
return -1;
}
// --- cdrom_read_tochdr ------------------------------------------------------
if (cdrom_read_tochdr(&ifd, &header) < 0) {
cdrom_close(&ifd);
return -1;
}
// --- cdrom_get_mcn ----------------------------------------------------------
if (cdrom_get_mcn(&ifd, &mcn) < 0) {
cdrom_close(&ifd);
return -1;
}
// --- cdrom_read_tocentry ----------------------------------------------------
for (i = 0, trk = header.cdth_trk0; trk <= header.cdth_trk1 + 1; i++, trk++) {
if (trk >= header.cdth_trk0 && trk <= header.cdth_trk1)
entry[i].cdte_track = trk;
else if (trk > header.cdth_trk1)
entry[i].cdte_track = CDROM_LEADOUT;
entry[i].cdte_format = CDROM_LBA;
if (cdrom_read_tocentry(&ifd, &entry[i]) < 0) {
cdrom_close(&ifd);
return -1;
}
}
// --- cdrom_read_audio -------------------------------------------------------
#if 0
if ((ofd = cdrom_open(opathname, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR)) < 0) {
ret = -1;
} else {
ra.addr_format = CDROM_LBA; // CDROM_LBA or CDROM_MSF
ra.nframes = 50; // number of 2352-byte-frames to read at once
// frame buffer (size: nframes*2352 bytes)
if ((ra.buf = malloc(ra.nframes * CD_FRAMESIZE_RAW)) == NULL) {
perror("malloc:ra.buf");
ret = -1;
goto extit_loop2;
}
// frame address
for (i = 0, trk = header.cdth_trk0; trk <= header.cdth_trk1; i++, trk++);
if (entry[0].cdte_format == CDROM_LBA) {
lba0 = entry[0].cdte_addr.lba;
lba1 = entry[i].cdte_addr.lba;
} else {
lba0 = MSF2LBA(entry[0].cdte_addr.msf.minute, entry[0].cdte_addr.msf.second, entry[0].cdte_addr.msf.frame);
lba1 = MSF2LBA(entry[i].cdte_addr.msf.minute, entry[i].cdte_addr.msf.second, entry[i].cdte_addr.msf.frame);
}
for (ra.addr.lba = lba0; (ra.addr.lba + ra.nframes) < lba1; ra.addr.lba += ra.nframes) {
printf("lba = %6d\r", ra.addr.lba);
if (cdrom_read_audio(&ifd, &ra) < 0) {
ret = -1;
goto extit_loop1;
}
if (cdrom_write(&ofd, ra.buf, ra.nframes * CD_FRAMESIZE_RAW) < 0) {
ret = -1;
goto extit_loop1;
}
}
ra.nframes = 1;
for (; ra.addr.lba < lba1; ra.addr.lba += ra.nframes) {
printf("lba = %6d\r", ra.addr.lba);
if (cdrom_read_audio(&ifd, &ra) < 0) {
ret = -1;
goto extit_loop1;
}
if (cdrom_write(&ofd, ra.buf, ra.nframes * CD_FRAMESIZE_RAW) < 0) {
ret = -1;
goto extit_loop1;
}
}
extit_loop1:
printf("lba = %6d\n", ra.addr.lba);
free(ra.buf);
extit_loop2:
if ((cdrom_close(&ofd)) < 0)
ret = -1;
}
#endif
// --- cdrom_close ------------------------------------------------------------
if (cdrom_close(&ifd) < 0)
ret = -1;
// --- debug print ------------------------------------------------------------
printf("start track=%02u\n", header.cdth_trk0); // start track
printf("end track =%02u\n", header.cdth_trk1); // end track
printf("\n");
for (i = 0; i < sizeof(mcn.medium_catalog_number); i++)
printf("mcn[%02d] =%02x\n", i, mcn.medium_catalog_number[i]);
printf("\n");
for (i = 0, trk = header.cdth_trk0; trk <= header.cdth_trk1 + 1; i++, trk++) {
printf("track =%02u\n", entry[i].cdte_track);
printf("adr =%02x\n", entry[i].cdte_adr);
printf("ctrl =%02x\n", entry[i].cdte_ctrl);
printf("format =%02x\n", entry[i].cdte_format);
if (entry[i].cdte_format == CDROM_LBA) { // CDROM_LBA
printf("addr lba =%d\n", entry[i].cdte_addr.lba);
printf("addr m =%02u\n", LBA2MIN(entry[i].cdte_addr.lba));
printf("addr s =%02u\n", LBA2SEC(entry[i].cdte_addr.lba));
printf("addr f =%02u\n", LBA2FRAME(entry[i].cdte_addr.lba));
} else { // CDROM_MSF
printf("addr lba =%d\n", MSF2LBA(entry[i].cdte_addr.msf.minute, entry[i].cdte_addr.msf.second, entry[i].cdte_addr.msf.frame));
printf("addr m =%02u\n", entry[i].cdte_addr.msf.minute);
printf("addr s =%02u\n", entry[i].cdte_addr.msf.second);
printf("addr f =%02u\n", entry[i].cdte_addr.msf.frame);
}
printf("datamode =%02x\n", entry[i].cdte_datamode);
printf("\n");
}
// printf("%s: %d\n", __FUNCTION__, __LINE__);
// ----------------------------------------------------------------------------
return ret;
}
PROGRAM = cdrom
OBJS = cdrom.o
CFLAGS = -Os -Wall
all : $(PROGRAM)
clean :; rm -f *.o *~ $(PROGRAM)
$(PROGRAM) : $(OBJS)
$(CC) $(OBJS) $(LDFLAGS) $(LIBS) -o $(PROGRAM)