Rockbox mail archiveSubject: Playback Engine Rework - The basic rundown
Playback Engine Rework - The basic rundown
From: Michael Sevakis <jethead71_at_sbcglobal.net>
Date: Mon, 25 Apr 2011 13:39:27 -0400
Good day all,
With suffient time before a looming release, I would like to commit
http://www.rockbox.org/tracker/task/12069 - Playback Rewrite - first stages.
There is a small amount of follow up work to do immediately afterwords in
the area of codecs that write directly into the WPS through the ID3 pointer,
of which, thankfully, there are few.
It has had significant testing not only by myself for a couple months but a
few others over the last week or so and noone has reported any issues (not
to me anyway).
What does it do? Mostly it addresses the area of codec control. track
skipping, buffering and metadata handling.
* Unlike current SVN, playback says what codecs do, codecs do not control
playback - playback engine is not helpless when no codec is present.
* Playlist are advanced in-time with the playing audio (you might have
noticed the track number going up several second ahead of time if using
gapless transtions - not crossfaded ones).
* Thus, resume at track transitions is automatically correct becuase the
playlist is in the correct place.
* Autoresume will work properly whether or not the track is kept on the
buffer; this bug would be most noticeable on targets with >=16 MB of RAM
where many tracks are commonly buffered at once.
* Track skipping while in transitional state works whether at the end of the
playlist or just in transition without it being a hack (while delt with in a
reasonable way, at the end of directories, some functions are locked out
since playlist advances must occur before finishing the last track in a
directory -- playlist issue). The current hack is to skip backwards by one
and then seek but this creates lots of phony transitional activity that
should not exist because no transition is in fact in progress. It can also
lead to incorrect results in playlist boundaries were crossed, such as
ending up the the wrong track altogether because playlists do not always go
in reverse the same way they went forward. At the final few seconds of the
end of a playlist, skipping and rewinding does not work at all in SVN
because no codec is loaded to help. With resident codecs, the last codec
used is still present to run again to perform the seek and for a skip the
engine needs no assistance.
* Buffer only as many codecs as required at format transitions.
* Atomic formats are reliably locked in place while the codec is working
* Rebuffer on skip is handled slighly differently for atomic formats if
track load was incomplete - if necessary, playback will attempt to reset the
buffer so that the buffer is available in its entirety. Only an atomic type
that is actually too large for the available RAM should fail to buffer,
barring other complications.
* Addresses the fact the watermarking is essentially meaningless for atomic
* Essential information such as the runtime-db and autoresume info is not
clobbered. The playing track's metadata is the playing track's metadata and
is always available in the same place. Information is kept properly up to
date that is changed late in the load process.
* Track end/change events really are track end/change events. There is one
compulsory exception when skipping back to time 0 tagtree expects a track
* Watermark handling is better. Low buffer events trigger only discard of
old tracks and filling continues after the last loaded track where
previously all tracks but the current track would be pointlessly discarded.
Spurious buffering events are eliminated and handled on the audio thread
alone. Refill point is never above 75% of the buffer so that continuous
buffering and disk spinning does not happen no matter how generous the
* Handle broken tracks and playlists without playback dying or being out of
* Many more arcane details were worked out. Codec-based gapless playback and
latency hiding is *not* simple and never will be. The current approach fails
to sync up with reality in that regard! Do it right or don't bother! :)
* Codecs are essentially TSR at load time and stay resident until a codec
change is required.
* Use of naked variables in the codec API to control codec operation is
* Codec load/unload and run entrypoints are separate - codec_main is called
for load/unload and codec_run for each track to be decoded.
* Codecs can rely on their metadata being correct and available when they
are called to decode a track - no wait loop is required.
* The codec's mp3entry is it's own and is private to it and playback and as
mentioned prior, it is stably available while executing in codec_run. It is
undefined in codec_main.
* Codec interface and implementation is simpler - codec just responds to
commands by consistently listening to its message queue though
* Codecs must set their initial read positions before decoding - playback
will not do this any longer. Playback initializes ci.curpos to where the
handle left off or where buffering first began (if freshly-buffered) by
using bufftell. The initial position in the id3 is still set by playback for
resume purposes. Current codecs have been corrected (correctly, I think).
* The playback engine implements the hard stuff in the area of codec control
to suit its own requirements; codecs can still be run in other environments
such as within the test_codec plugin.
* Speedier previewing when skipping and the tracks are not yet buffered;
this code can be left out if it has little benefit on a particular target.
* Handle short files (one less than the PCM buffer length) nicely and have
the WPS display them properly as they are common with some videogame formats
and not a truly unusual case at all.
* A more powerful function, queue_peek_ex is included and is also used as
the backend to implement the current APIs queue_remove_from_head and
queue_peek. This allows peeking and optionally removal without blocking
using a message filter list, each being a range of messages to check. We
need this to reliably remove events from of the audio queue that might, and
often do, arrive while backing out of transitional states. This method
combined with knowing what the codec and pcmbuffer is doing is implemented
to be non-racy.
* Queue functions can take NULL for the event parameter if message removal
in not desired but blocking for a message is.
* With some improved support in surrounding areas, most notably with
playlists, this will likely be able shed a bit of weight because fewer
internal states would be needed.
Michael Sevakis (jhMikeS)
Received on 2011-04-25