A number of other bugs and requests in the forums have dealt with issues other than maintaining synchronization when playing with multiple synchronized players. This thread is to discuss their relative merits and solicit input on priorities, problems, solutions, etc.
Alan.
- Gapless
The current sync design uses start-all-players-one-after-another-as-quickly-as-possible at the start of each track as a way of achieving synchronized playback. The start (unpause) commands are sent out serially and really need to reach each player within a window of around 10ms to get good sync playback and sometimes this does not happen. Some proposed firmware changes (unpauseAt) may be able to improve on that.
But waiting for all players to be ready at the start of each new track almost inevitably introduces an audible delay between tracks. In fact the delay would be even greater if a larger syncBufferThreshold were used, and reliable sync-startup without an immediate underrun really does require a much larger threshold than the current default of 128 bytes. We are talking of around 100-250ms here and so this is only really relevant to gapless playback.
If the sync-maintenance algorithms are sufficiently reliable then it no longer becomes necessary to wait for all players to have finished playing out the previous track before starting the next one. For an SB1, however, a change in format (mp3, wav, etc.) still requires playout to complete and only then open a new stream.
The current design is reflected in code scattered over many parts of the server and will require careful work to unwind it.
- Adding a player to an existing sync-group without restart
The main thing needed for this is maintenance of a relationship between stream bytes (at frame boundaries) and play-time represented at the same frame-boundary. This is needed in any case if SliMP3s or SB1s are part of the sync-group but would not otherwise be required for SB2+ players. Also, because of the larger buffers in the SB2+ players, the range of the stream for which this data is needed is much larger. The cost of maintaining this data is neither trivial nor excessive. It seems a pity to have to maintain it when not required – that is, when there is no intention to dynamically add a player to an existing sync-group mid-track without restart. Nonetheless, it is doable.
There are a number of other issues which raise problems with respect to this functionality.
- stream-format
The current design use a lowest-common-supported model for the stream format across the set of synced players. A single source stream is then used to feed the data stream to each player. This is clearly a problem if one tries to add a player to a sync-group where the new player does not support the current stream format.
An option might be to abandon the lowest-common-supported format model, and use multiple streams with (potentially) different formats, but there would be a danger that a transcoded stream might not have a tractable relationship with respect to playing time - for example, if the transcoding involved a change between 48000 and 44100 frame rates. Also, multiple parallel transcoding operations could become very CPU intensive.
- buffered-data
Modern players (SB2/3, Transporter) buffer a significant amount of encoded audio data, possibly representing more than 5 minutes of audio playback, and easily more than 3 minutes (for 128kbps MP3). If a player were simply spliced into the stream at the current point, then it could be an unacceptably long time before the new player actually started playback.
For local files, where it can be sure that rewinding or reopening the stream will result in the same byte-stream, then this is an option. For local data with a transcoded stream there is the danger that the CPU-intensive transcoding might take too long to get to the same point in the stream as is currently playing on the existing players. For remote streams then rewinding is simply not an option; restarting may be an option for live streams but one needs a way to know that it is live.
- stream-format
- Syncing a player with a standalone player w/o restart
This is really just a slightly more extreme version of adding a client to an existing sync-group.
In the case of a locally-streamed file then it should simply be possible to grab the file (and any waiting chunks) from Slim::Web:HTTP.
In the case that the existing player is streaming directly from a remote source then there seems to be little possibility of syncing-in another player.
The question then arises as to what to do when:- adding player to existing sync-group mid-track is not possible;
- adding player will result in substantial delay before new player starts.
Options are:- restart current track across all players in group (current behaviour);
- add new player only at start of next track (or after substantial delay).
Alan.
Comment