Rockbox.org home
release
dev builds
extras
themes manual
wiki
device status forums
mailing lists
IRC bugs
patches
dev guide



Rockbox mail archive

Subject: Suggested mpeg playing API
From: Dave Chapman (dave_at_dchapman.com)
Date: 2002-05-12


Here are some suggestions for an mpeg playing API for rockbox.

I think the most important thing is to abstract the method of choosing tracks
away from the actual playing of them. This will allow the implementation of
different play modes without affecting the mpeg playing code.

I see the final firmware having an "mpeg thread" which is started and
stopped, depending on whether there are any tracks to play. This gives us
the function:

int start_playback(char* fname, int start_time)

which creates the mpeg thread and starts playing the named file at the
specified start position (in milliseconds)

I don't know how the MAS driver will eventally work, but maybe the mpeg
thread actually needs to be two threads on the real device - one to fill the
play buffer, and one to empty it (i.e. send data to the MAS). However, the
application itself (and hence the API) shouldn't need to know this.

When the mpeg thread has finished reading (i.e. copying from disk to memory,
NOT playing) the current track, it needs to be able to start buffering the
next track (in order to prevent skips between tracks). Therefore, there
needs to be a function:

char* peek_next_track(void)

that returns either NULL (if there are no more tracks, in which case the mpeg
thread commits suicide) or the filename of the next track to play - but
doesn't change any data structure relating to the current playlist.

I am assuimg that mpeg audio files small enough to fit completely inside the
buffer are rare enough to mean we only need to look one track ahead to keep
the buffer full.

When the current track has actually finished playing, the mpeg thread should
double-check that the next track is still the same (for example, the user may
want to modify the current playlist) and change the position of the "playlist
cursor" by calling a function like:

char* get_next_track(void)

The UI thread should be responsible for checking if files exist before asking
the mpeg thread to play them - so feedback can be given to the user if
necessary.

The complications arise when the user starts pressing buttons. The UI thread
needs to be able to control the mpeg thread as follows:

pause_playback(void) - temporarily pause the playback

The following functions should only be called when the playback is paused:

resume_playback(void) - resume playback after a pause
kill_playback(void) - kill the mpeg playing thread
new_track(char* fname, int start_time) - start playing a completely new track
seek_absolute(int n) - seek to an absolute position (in milliseconds)
seek_relative(int n) - seek to a relative position (in milliseconds) in the
current track

None of these functions should fail. They should also block the UI thread
until they have finished - I think this will simplify the overall
implementation without any noticable delay to the user.

I think that all other possible functions are simply combinations of the
above. e.g. "skip to previous track" is simply a call to "new_track".

If skipping by N seconds takes the user to a different track, the UI thread
must either refuse to skip, or call the new_track command with the
appropriate offset.

Maybe the above functions can be implemented by having a simple type of
message queue that the mpeg thread polls at appropriate intervals. The
implementation of the above functions in the ui thread would just modify a
shared data structure (with proper locking). The mpeg thread would poll this
data structure to see if it contained a message and act accordingly.

There will also be a need for the User Interface thread to update the display
with the status of the current track (track details, time elapsed, time left
etc). Therefore, the mpeg thread should maintain a shared data structure that
contains the current status (i.e. current position in seconds) of the current
track

From the above description, the "thread API" will "only" need functions to
create a thread, kill a thread, and to provide a locking mechanism for data
structures.

I have tried to make this as simple as possible, yet also keeping it as
flexible and abstract as possible. It also puts most of the work (e.g.
reading and manipulating playlists) in the UI thread - where I think it
belongs.

Any comments?

Dave.



Page was last modified "Jan 10 2012" The Rockbox Crew
aaa