I noticed that the web interface was still displaying the previous song after a new one had started playing. It looks like nup-headless got confused, probably because the first song was resampled from 48 kHz to 44.1 kHz (TIL that I actually have some 48 kHz songs):
Jan 06 20:33:13 Created decoder for /var/cache/nup/5203231604998144.mp3 (48.0kHz stereo, 55714862 samples)
Jan 06 20:33:13 Resampling /var/cache/nup/5203231604998144.mp3 from 48000 to 44100
Jan 06 20:33:13 Set next to /var/cache/nup/5203231604998144.mp3 (10m31.688s)
Jan 06 20:33:32 Switching to /var/cache/nup/5203231604998144.mp3 (10m31.688s)
...
Jan 06 20:37:32 Reporting play of 5203231604998144 at 2026年01月06日T20:33:32.855-07:00
Jan 06 20:37:33 Reported play successfully
Jan 06 20:42:53 Created decoder for /var/cache/nup/6591047685636096.mp3 (44.1kHz stereo, 18553752 samples)
Jan 06 20:42:53 Set next to /var/cache/nup/6591047685636096.mp3 (3m30.36s)
Jan 06 20:44:00 Dumping state
Jan 06 20:44:00 Current song:
Jan 06 20:44:00 Artist: Nine Inch Nails
Jan 06 20:44:00 Title: With Faith
Jan 06 20:44:00 Album: Ghosts V: Together
Jan 06 20:44:00 Time: 627.417 / 580.392
Jan 06 20:44:00 Song ID: 5203231604998144
Jan 06 20:44:00 Filename: nine_inch_nails/ghosts_v_together/04 - Nine Inch Nails - With Faith....
...
Jan 06 20:44:04 Switching to /var/cache/nup/6591047685636096.mp3 (3m30.36s)
The file is actually 9:40. From ffprobe:
Duration: 00:09:40.39, start: 0.023021, bitrate: 320 kb/s
Stream #0:0: Audio: mp3 (mp3float), 48000 Hz, stereo, fltp, 320 kb/s
nup debug -mpeg also gets it right:
23265585 bytes: 48817 header, 23216640 data, 128 footer (76bb9bd617c26c8ec7215735e36696231320dcfd)
Xing: 9:40.392 (24183 frames, 23216640 data, 576 start delay, 809 end padding, LAME3.99r CBR)
Actual: 9:40.392 (24183 frames, 23216640 data, 320 kb/s CBR)
The database also has the length as 580.392 seconds.
I think the problem is that gaplessPlayer.durationLocked passes the decoder-provided sample count to gaplessPlayer.samplesDuration, which divides it by gaplessPlayer.sampleRate, which is the target sample rate (i.e. 44100) rather than the file's sample rate.