Edzelf / Esp-radio

Internet radio based on Esp8266 and VS1053.
MIT License
625 stars 200 forks source link

Station transition latency reduction (?) #91

Open koskee opened 7 years ago

koskee commented 7 years ago

Just thinking out loud here, but judging by the debug prints that the radio spits out into the serial monitor, it appears the radio issues a stop request before connecting to the next station. This leaves a considerable audio gap while it connects to the next server, resolves metadata, etc.

Depending on how quickly the radio is able to resolve the new stream, could we not skip the stop request and just append the new stream onto the existing buffer? I read somewhere in the docs that the ring buffer should be able to hold enough for about 1.5 seconds of audio @ a certain bitrate, which although it probably wouldn't eliminate the gap entirely in all cases, it just seems like stopping the stream before doing anything else is only prolonging the gap between streams.

There's probably a good reason for doing it how it currently is done, but if not, wouldn't it make more sense to leave it playing as long as possible while transitioning servers?

koskee commented 7 years ago

I did a little bit of testing, and despite my choppy output from the most recent version (discussed in another issue) it seems with a minor code change to remove a stop request when changing stations, that the gap is significantly reduced. Now that I've gone back to a functional version, I will test the same change to see if the results are similar.

koskee commented 7 years ago

Well it appears to work. Depending on how fast the radio picks up the next stream, it seems like at least some of the time the transition is gapless. I haven't been able to thoroughly test the modification, because I have yet to take the time to create an ini file that has only stations that work, but i'm happy to report that switching stations without issuing a stop command doesn't cause a crash or anything overly undesirable.

All I did was comment out the if structure that checks if the radio is stopped and issues the command if it isnt in the loop function (where it decides to change stations). I'd create a pull request but I haven't ever done that before so I would likely need to figure out how. It's a simple enough change to implement tho, I doubt it really warrants a PR.

Let me know if you would rather I send a PR, or if you have questions about where the changes I made were.

Edzelf commented 7 years ago

During the switch station process, the "loop()" function is not executed. So there are no reads from the ringbuffer. Switch time in normally about one second. Some buffering is done by the VS1053 itself (size of audio FIFO is 2048 stereo (2x16 bit) samples) and that's what you can gain by postponing the stop command.

koskee commented 7 years ago

Well it seems to improve the fluidity of changing channels as there is less dead time. Unfortunately, for whatever reason the module will briefly pause for maybe a second as soon as it receives the command, and then finishes playing out whatever buffer it still has after this short pause. The new station comes in pretty much immediately after the remaining audio data runs out from the last station.

I haven't been able to trace the reason for the pause, but it occurs to me that it's either the heavy loading caused by the new connection, or maybe one of the various delay commands scattered throughout the sketch.

However, it seems odd that the buffer inside the mp3 module doesn't seem to offset the gap caused by the reconnection at all.

Perhaps the esp32 will be better at handling this, with its dual core, and other performance improvements.

If there are any deliberate reasons for the module to be taking a momentary break here, off the top of (anyone's?) head, that might point me in the right direction, would appreciate the tip.

Regardless, I find it much less noticeable if keep the audio going as much as possible.

Also, would it be fair to assume you've already considered using an interrupt to fill the ring buffer at more tightly controlled intervals? Or maybe even the ticker library? I don't think it's a real interrupt, but I could be wrong about that and it could be worth looking at if it allows the code to generate the data array in a more controlled & consistent fashion.