Track-based CD-ROM access non-functional
Version: sdl12_compat-1.2.68, openSUSE Tumbleweed 20241129 amd64, tcd 2.2.0
Observed
Starting tcd with sdl12-compat-1.2.68 leads to program termination:
$ strace -e openat,ioctl tcd
openat(AT_FDCWD, "/lib64/libSDL-1.2.so.0", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib64/libncurses.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib64/libtinfo.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
…the usual libc fluff…
INFO: This app is looking for CD-ROM drives, but no path was specified
INFO: Set the SDL12COMPAT_FAKE_CDROM_PATH environment variable to a directory
INFO: of MP3 files named trackXX.mp3 where XX is a track number in two digits
INFO: from 01 to 99
No CDROM devices available
+++ exited with 1 +++
Expected to see instead
With SDL-1.2.15, tcd works fine:
$ strace -e open,ioctl tcd /dev/sr0
openat(AT_FDCWD, "/dev/cdrom", O_RDONLY|O_NONBLOCK) = 3
ioctl(3, CDROMSUBCHNL, 0x7ffec5632210) = 0
openat(AT_FDCWD, "/etc/mtab", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/dev/sr0", O_RDONLY|O_NONBLOCK) = 4
ioctl(4, CDROMSUBCHNL, 0x7ffec5631960) = 0
openat(AT_FDCWD, "/etc/fstab", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/dev/cdrom", O_RDONLY|O_NONBLOCK) = 3
ioctl(3, CDROMSUBCHNL, 0x7ffec56323d0) = 0
…
So, okay, yes, this doesn't support physical discs, making a CD player app significantly less useful, but this program does work with a directory of MP3s[^1], like the INFO lines say.
The reasons we dropped physical drive support:
- Lots of computers don't even have a CD/DVD drive anymore.
- On the ones that do (notably, all the Macs sold in the last several years of Apple offering an internal optical disc drive), many weren't hooked up to the audio hardware, so even if SDL could command the drive to play an audio track, the disc would spin but no audio would play. Obviously something like a USB drive will never work with this unless one can plug speakers directly into it.
- Some of this could be mitigated by reading the raw data from an audio CD and playing it through a sound card directly, but SDL 1.2 never offered this outside of Mac OS X; most platforms just sent a "play" command to the drive in some way.
- On a source code level: every platform did their own thing for CD audio control: not just Windows vs Linux vs Mac, but also Linux vs FreeBSD vs OpenBSD vs AIX, etc. the source code to SDL-1.2's cdrom subsystem, with all these variations, is larger than all of sdl12-compat as a whole. Also: it's LGPL'd, so we'd have to rewrite it from scratch it instead of incorporate it, since we can't comply with the license in sdl12-compat.
The thinking is that faking audio discs with a directory of MP3s fixes up a generation of games that have CD audio tracks--like Quake 1, etc--for modern systems that might be able to play the game but can't even insert a physical disc.
Obviously all of this does not help tcd at all though. If we were to deal better with this, my thinking would be:
- Many of those platforms (Mac OS Classic, Dreamcast, etc) can't run SDL2 at all, let alone sdl12-compat, so we don't have to reimplement everything. In fact, I'd be surprised if there were any generic CD Audio apps (not games) using SDL 1.2 outside of Linux, so maybe implementing exactly one platform is the correct thing to do here.
- For platforms we might implement, we definitely still want the MP3 support for all the reasons mentioned; it would just be one more reported drive over any physical drives.
Right now sdl12-compat's entire CD subsystem runs on the expectation that there's either zero drives, or one fake drive, and all of that would need to get more generalized if we're going to drop platform-specific code in here to work with actual physical hardware.
I'm putting this in the next milestone, but I'm extremely likely to bump it back out, as this is low-priority for me. If someone else wants to take a run at it before I get around to it, I'm happy to help, though.
[^1]: I had to fix a buffer overflow in cddb.c's cddb_filename where it ended up with a massively large value for discid, presumably because somewhere it's trying to read real data from a Linux CD-ROM drive device node, outside of SDL, that doesn't exist, and long went from 32 to 64 bits since tcd was written.
Lots of computers don't even have a CD/DVD drive anymore.
Rest assured we emulate it already ;-)
# readcd dev=/dev/disk/by-id/usb-TSSTcorp_CDDVDW_SE-208DB_R90V6GAD1006WH-0:0 f=fury3.readcd -clone
# modprobe vhba
# cdemu-daemon &
# cdemu load 0 fury3.readcd.toc
# cdrecord -dev=/dev/disk/by-id/scsi-1CDEmu_CD-ROM_000 -toc
first: 1 last 6
track: 1 lba: 0 ( 0) 00:02:00 adr: 1 control: 4 mode: -1
track: 2 lba: 100302 ( 401208) 22:19:27 adr: 1 control: 0 mode: -1
track: 3 lba: 124178 ( 496712) 27:37:53 adr: 1 control: 0 mode: -1
track: 4 lba: 137278 ( 549112) 30:32:28 adr: 1 control: 0 mode: -1
track: 5 lba: 154824 ( 619296) 34:26:24 adr: 1 control: 0 mode: -1
track: 6 lba: 179617 ( 718468) 39:56:67 adr: 1 control: 0 mode: -1
track:lout lba: 191631 ( 766524) 42:37:06 adr: 1 control: 0 mode: -1
FWIW, I have a super-hacky half-finished proof-of-concept to implement CD-audio using libcdio_paranoia — this does the digital audio extraction (so works with any modern CD/DVD/Blu-Ray drive), and then mixes it in the same way the mp3 implementation works.
I think, if I clean it up and update it to (a) not hang the audio thread while the drive is spinning up, and (b) make it dlopen() the cdio/cdio_paranoia libraries, then this could be a pretty good solution. (If we were building on top of SDL3's new audio API, this'd actually be really quite easy. As-is it'd be uglier, but not too bad if done carefully.)
Feel free to assign this to me if that sounds like a good plan, and I'll try to get something done over the holidays.
FWIW, I have a super-hacky half-finished proof-of-concept to implement CD-audio using libcdio_paranoia
Sure!
Edit: Oops, @icculus pointed out this has an incompatible license, never mind.
cdemu has audio output on its own, so I'd already be happy if SDL just sent the necessary ioctls :-)
… (meaning CDROMSTART, CDROMSTOP, CDROMPLAYTRKIND, ... and let audio be sent over the CD device's own "analog" output.)
libcdio-paranoia
GPL3: https://github.com/libcdio/libcdio-paranoia
dlopen()'ing a GPL'd library still makes your program a derivative work, according to the FSF.
I do think reading the raw disc data and sending it through the audio card is the right thing to do, though, but we can't use that library afaict.
GPL3: https://github.com/libcdio/libcdio-paranoia
Rats! Nice catch — the old Xiph.org version was LGPL.
It turns out the ioctl interface is quite easy to use on Linux, and I successfully listened to a CD without any of cdparanoia's fancy overlapping-protection being necessary, and there was at worst a very occasional, very quiet 'pop' noise, so I think this is still definitely a go. (Though I'm not going to commit to supporting all of the other platforms libcdio supported.)