DebianでAudio CDにアクセス

調べ事をするために作ったサンプルプログラムです。
DebianでAudio CDにアクセスするサンプルが少なかったのでここに置きます。
Debian 9.5にてコンパイルと動作確認を行いました。

```C:cdrom.c
#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;
}
```
```makefile:Makefile
PROGRAM		=	cdrom
OBJS		=	cdrom.o
CFLAGS		=	-Os -Wall

all			:	$(PROGRAM)

clean		:;	rm -f *.o *~ $(PROGRAM)

$(PROGRAM)	:	$(OBJS)
				$(CC) $(OBJS) $(LDFLAGS) $(LIBS) -o $(PROGRAM)
```