nixamp streams have a phone number. Call +1 408-357-2326, key a six digit code, and if that code belongs to a live stream you hear the stream. That was the idea. What actually happened was that you heard a friendly voice say "here it is" and then nothing at all, for as long as you cared to hold, at your own expense.
The bug is a good one, so here it is.
A nixamp that lists itself in the directory announces a listen link. That link looks like https://host/s/<key>. It is not a file. It is a 302 that sets a cookie and redirects a browser to the player page, which is exactly right for a person and exactly wrong for everything else.
The phone line handed that link to Telnyx to play into the call. Telnyx fetches an audio URL once, anonymously, with no cookie jar. So it followed the redirect, arrived with no cookie, and got this:
HTTP/1.1 401
{"error":"this nixamp needs the key from its share link"}
That is not audio. Nobody was ever going to hear anything.
The part I liked least is that there was a test for it. It keyed a code, found the playback_start call, and asserted the played URL equalled the listing's URL. It passed. The fixture called itself listen.mp3, so the assertion looked like it was checking that audio got played, when all it checked was that two identical strings were identical. The fixture and the code agreed with each other and neither agreed with a telephone.
The fix is that a listing carries two addresses now, not one. url is for a person with a browser. audio is for anything handed a single address and expected to play it. They have to be the same origin, because that second one gets played into a call somebody pays for by the minute, and an announcement that could name any address on the internet could point the phone line at any of them.
audio points at a new endpoint, /api/live, which is whatever is playing as one endless MP3. There was already /api/stream/N, but that is one track and it stops at the end of the song. Fine for a browser, which knows what is playing and can ask for the next one. Useless for a telephone, which cannot ask for anything. /api/live follows the player instead and keeps writing into the same response across track boundaries. It reads at native rate, because otherwise ffmpeg finishes a four minute song in two seconds and the thing deciding what plays next ends up minutes behind what the listener hears.
Two things fell out of chasing it.
Matroska was not on the list of audio extensions, so a directory full of .mkv films scanned as zero tracks and said nothing was wrong. Everything leaving nixamp is decoded by ffmpeg with -vn anyway, so a film is just a long track with a picture nobody asked for. Those containers are on the list now.
And the installer opens the streaming port. A published listing is an address on your machine that the phone line fetches audio from, so a firewall quietly dropping that port turns every listing into one nobody can open, with nothing anywhere saying so. It asks for root without waiting, since curl | sh has no terminal to type a password into, and prints the exact command when it cannot.
0.4.1 is out, and it is the first release that has the phone line at all. 0.3.0 does not contain partyline.ts, which means every copy installed from the site could read the directory and could not put a single thing into the telephone.
0.4.0 was that release and it lasted about twenty minutes, because it did not run. The packer named its dependencies by hand and had been given one of them, back when there was one, so the tarball installed perfectly and then stopped on the first import looking for a package nobody had packed. 0.3.0 shipped the same way and nobody noticed, since the release before it predated all four. The list is read out of package.json now, and the release workflow extracts the tarball and runs it under plain Node before publishing, which is the check that was missing the whole time.
curl -fsSL https://nixamp.com/install.sh | sh
Drafted with AI assistance.
Top comments (0)