![]() |
![]() |
![]() |
![]() |
This chapter describes how to work with track sessions and play audio media on the MME.
The MME is designed to facilitate development of a user-friendly, efficient, and versatile HMI for playing diverse media. A client application can instruct the MME to begin playing media from a mediastore even before the mediastore has been synchronized with the MME database. However, most client applications will start synchronizing a mediastore before starting playback, so they can provide metadata, such as song artist and genre, to their end users.
To play media through the MME, the client application requires:
![]() |
|
A track session is the basic unit for playing media. It is created by an SQL query or an explorer API function that generates a list of media tracks that can be played in a control context. Each track in a track session is identified by its zero-based offset in the list; this method permits duplicate file IDs (fids) in a track session.
To play media, the client application must:
![]() |
|
For more information about the fields in the track session table, see the trksessions table entry in the appendix: MME Database Schema Reference of the MME API Library Reference.
The MME supports two types of track sessions:
A library-based track session is built with files from mediastores that have been synchronized and, therefore, have entries in the library table in the MME database. To create a library-based track session, simply proceed as with previous releases, calling mme_newtrksession() with the mode argument set to MME_PLAYMODE_LIBRARY (0).
The figure below illustrates the flow of activities from the creation of a track session to the end of the track session, with a mediastore synchronization in the background.
Playing media with the MME.
A file-based track session is a track session built with files discovered through the the MME's explorer API. Unlike tracks in a library-based track session, tracks in a file-based track session can be from unsynchronized mediastores and do not, therefore, have to have entries in the library table. For more information about the MME's explorer API, see the chapter Unsynchronized Media in this guide.
The difference between a track session and a playlist, is that a playlist is an arbitrary collection of tracks that is created by a user, either by selecting individual songs or by creating some selection criteria (such as all the songs by a particular artist), represented as an SQL statement. The user can name a playlist and store it. A playlist isn't associated with a control context.
To play a playlist, the client application creates a track session from the playlist and associates that track session with a control context. Set the track session with the playlist to be the current track session by calling mme_settrksession(). For more information about playlists, see the chapter Playlists.
Your application should create either a library-based track session or a file-based track session, depending the synchronization status of the mediastore with the media to be played:
![]() |
MME track sessions support duplicate file IDs (fids), because the MME references tracks in track sessions by their offsets, not their fids. To start playback with a specific track offset in a track session, use mme_play_offset(). |
Library-based track sessions are used for playing found on synchronized mediastores, and are the most commonly used type of track session.
To create a library-based new track session, call mme_newtrksession() with an SQL statement to select the tracks you want to play and the mode argument set to MME_PLAYMODE_LIBRARY (0). This function will use your query statement to:
![]() |
Always use MME functions to update the trksessions table. Never write directly to this table. If you write directly to this table, you will make its data unreliable. |
Below are some examples of how your client application could create a library-based track session and play it. To keep things simple, these examples assume that you have already connected to the MME database and MME resource manager, and they don't check return codes, which your application should do.
We can start with the simplest case: create a track session to play all the tracks in the library. This case has the following steps:
Since we are not interested in metadata or playlists, we can start playing tracks from any new mediastores after only the first synchronization pass has completed on these stores.
mme_hdl_t *mme; char *sql; uint64_t trksessionid; mme = mme_connect("/dev/mme/default", 0); // Connect to MME sql = "SELECT library.fid AS fid FROM library " " INNER JOIN mediastores ON mediastores.msid = library.msid " " WHERE mediastores.available=1 AND ftype=1 " " ORDER BY title"; // create the new track session mme_newtrksession( mme, sql, MME_PLAYMODE_LIBRARY, &trksessionid ); // set the new track session as the active track session mme_settrksession( mme, trksessionid ); // start playing the track session, // pass in a fid of 0 to start from the beginning. mme_play(mme, 0);
Note that:
For more information about the SQL queries used with the MME and QDB as well as recommendations, see the chapter Working with the MME Database and SQL.
The MME adds a fid to the library table for many types of mediastores, including iPods and type MME_STORAGETYPE_DEVB mediastores (which includes HDDs, USB sticks, CDs and DVDs).
When composing queries for a track session, you should exclude fids that refer to mediastores by adding a WHERE clause to the query statement to select the file type entry (ftype) you need. For example to select only entries where ftype=FTYPE_AUDIO:
SELECT fid, ftype, title FROM library WHERE ftype=1 ORDER BY title;
File-based track sessions are used for playing found on unsynchronized mediastores.
To create a file-based track session:
![]() |
You don't need to use the explorer API before you create or set the track session. You can use it at any time to discover tracks of interest, which you can then add to your track session using one of the methods described below. |
You can explore mediastores and add tracks to your track session at any time after creating the track session, or after you have started playback. You can change an existing file-based track session by:
After you have created a track session, you must set it by calling mme_settrksession(). When you call mme_settrksession(), the MME takes a snapshot of the SQL statement that represents the track session and stores it in the trksessionview table. This entry in the trksessionview table changes only when a new track session is set, or if you call the function mme_trksessionview_update().
If a client application sets a track session before the MME has completed the first synchronization pass of a mediastore (before it receives the event MME_EVENT_MS_1PASSCOMPLETE), the track session contains only a subset of the data available on the mediastore. For example, if the client application calls mme_settrksession() before it receives the event MME_EVENT_MS_1PASSCOMPLETE, the track session it sets will contain only those tracks that were synchronized up to that point; the remaining tracks on the mediastore will not be included in the track session.
![]() |
If the SQL SELECT statement used to create the track session uses metadata, the client application has to wait for the event MME_EVENT_MS_2PASSCOMPLETE before making its final update to the trksessionview table. For example, SELECT fid FROM library WHERE artist_id=4 AND msid=3 uses metadata, so all fids for the track session will not be found until after the second synchronization pass is complete. However, a query such as SELECT fid FROM library WHERE msid=3 ORDER BY filename uses only information provided by the first synchronization pass, so all fids for the track session are found by the first synchronization pass. |
To enable playback as quickly as possible while ensuring that all requested tracks are included in the track session, the client application should update the trksessionview table when it knows that the first syncrhonization pass has completed, and, for large mediastores that can take a long time to synchronized fully, periodically so that the track session does not run out of tracks. For example, with a large mediastore with 10,000 files, the client application can do something like the following, assuming that synchronization was started automatically, and that the SQL SELECT statement does not use metadata:
![]() |
|
You can clear a track session by:
To prevent a track session “leak” — an accumulation of useless track sessions in the trksessions table — you should delete track sessions from the trksessions table in the following circumstances:
To delete a track session:
After you have started playing a track session, you need to monitor the progress of the playback by checking the MME playback events. The example below shows a client application displaying messages on receipt of some MME events:
switch (msg.single.type) { case MME_EVENT_NONE: fprintf(stderr, "Received MME_EVENT_NONE (%d)\n", MME_EVENT_NONE); break; case MME_EVENT_TIME: fprintf(stderr, "Received MME_EVENT_TIME (%d)\n", MME_EVENT_TIME); break; case MME_EVENT_FILECHANGE: fprintf(stderr, "Received MME_EVENT_FILECHANGE (%d)\n", MME_EVENT_FILECHANGE); break; case MME_EVENT_PLAYLIST: fprintf(stderr, "Received MME_EVENT_PLAYLIST (%d)\n", MME_EVENT_PLAYLIST); break; ... default: fprintf(stderr, "Unknown Event Received (%d)\n", msg.single.type); break; }
While the MME is playing a track session, it delivers the event MME_EVENT_TIME at set intervals to notify the client application of playback progress.
The default interval between deliveries of MME_EVENT_TIME is 100 milliseconds, but the MME allows you to change this interval by calling mme_set_notification_interval() with the time set to the desired interval, in milliseconds.
Note that:
You should monitor for events indicating errors, changes in tracks (so you can display the metadata display, for example), completion of playback, etc. For a complete list of playback event types, see “Playback events” in the chapter MME Events.
You can also check on the progress of the playback by calling mme_play_get_status(). This function retrieves the status of playback, providing the total play time of the track and the play time elapsed.
In most environments, users want to continue playback without interruption until they explicitly request a change. Therefore, once the MME has started playback of a track session, it continues playback until:
or:
or:
In short, once playback of a track session has started, the client application doesn't need to do anything except monitor MME events, and pass information and metadata to the end user, until it receives one of these events:
Both these events indicate that playback has stopped, and that action by the client application is required for playback to resume. No other events (not even MME_PLAY_ERROR_* events) require action from the client application for playback to continue.
![]() |
If the client application instructs the MME to stop playback (e.g. by calling mme_stop()), the MME does not deliver an MME_EVENT_FINISHED_* event. |
The MME can set the playback mode of a library-based track session to play through the track session sequentially, repeat the track being played, repeat the entire track session, or play through the track session in random order.
Track sessions inherit their repeat and random modes from the control context in which they are created. Use the functions mme_getrepeat() and mme_setrepeat(), and mme_getrandom() and mme_setrandom() to get and set these modes.
![]() |
|
The explorer API and file-based track sessions are designed to allow the client application to manage its track sessions, discovering tracks and adding new tracks to a track session a few at time, as required by the end-user.
When new tracks are added to a track session in random mode, the new tracks are appended in pseudo-random order to the end of the track session; they are not integrated into the pseudo-random order for the entire track session. For example, if five tracks are added to a track session with 20 tracks, the order for the tracks in positions 0 to 19 remains the same, and the new tracks are appended in pseudo-random order in postions 20 to 24.
When playing tracks in a file-based track session, to change the next track that will be played without interrupting the track currently being played, the client application can call mme_trksession_set_files() with the offset parameter set to the required track.
The MME lets you start playback with a specific track from a track session. The method for starting playback from a specific track is different for library-based and file-based track sessions.
![]() |
The MME can play a track that isn't in the current track session, as long as it has an active track session in the current control context. For more information, see mme_play(). |
To start playback with a specific track in a library-based track session, instead of passing mme_play() a 0 (zero) for the fid argument, which starts playback with the first track in the track session, pass it the fid of the track you want to play. The MME will start playback with the track you specified, then continue playing the track session as determined by the position of the track in the track session and the random and repeat mode settings for the control context. For example:
![]() |
If the library-based track session contains more than one instance of the specified fid, the MME starts playback at the first instance of this fid. |
To start playback from a specific point in the file-based track session, use mme_play_offset(), passing it the zero-based offset of the track where you want to start playback. For example, to start playback with the 17th track in the track session set the mme_play_offset() function's offset argument to 16.
![]() |
The MME can play a track that isn't in the current track session, as long as it has an active track session in the current control context. For more information, see mme_play(). |
Your client application should pause playback only in situations when it expects to resume playback or tear down the track session after a brief interval, such as when the end user sends a “pause” button command (MM_BUTTON_PAUSE) through the HMI. For situations when you expect a change to the system, such as a shutdown or a change to the mediastore being played, you should save the track session state and stop the track session. For more information, see “Stopping and resuming playback” below.
To pause playback temporarily, call mme_play_set_speed() with the speed set to 0. This action pauses playback until you call mme_play_set_speed() again with the speed set to something other than 0 (zero). Normal playback speed is 1000. For more information about how to use mme_play_set_speed(), see “Using fast forward and reverse” below.
Your client application should save the track session state and stop the track session when it expects or encounters a system change, such as a shutdown or a change to a mediastore. Such situations include, but are not limited to, the following:
The operations required to stop then resume playback are a function of the capabilities of the device with the media tracks for the track session. These devices can be:
For information about resuming playback when using the explorer API, see “Pausing and resuming playback in a file-based track session” below.
If you want to stop, then resume playback of a track session on a device or devices that don't manage their own track session, you must:
Method A (works only for devices and mediastores that don't support their own track sessions):
Method B (works for all devices and mediastores):
Stopping and resuming an MME-controlled track session.
The strategies described below allow your client application to call mme_trksession_resume_state() to resume playback at a later time at exactly the position where it was stopped.
Saving the track session state with mme_trksession_save_state() before stopping it assures that, when you resume playback, the MME has all the information it needs to start playing the correct track at the correct position.
Pausing the track session before saving its state ensures that when playback resumes, it will be exactly at the correct position in the track: the user will not hear the last few milliseconds of music played if there is a delay between the call to mme_trksession_save_state() and the call to mme_stop(). If you do not pause the track session before saving its state, a situation like the following may occur:
![]() |
|
Tracks in a file-based track session do not have corresponding entries in the MME library table. This particularity means that when stopping and resuming playback, the client application must take care of saving and restoring the file name and current time position for the track to be paused and resumed.
To pause playback of a track in a file-based track session:
To resume playback of a track in a file-based track session, assuming that the track was passed as describe in “Pause playback in a file-base track session” above:
Use mme_play_get_speed() to get the current playback speed of a track session (expressed in units of 1/1000 of normal speed). Use mme_play_set_speed() to pause, reverse, and playback more slowly or more rapidly than normal playback speed. Set the speed argument as shown in the table below:
Setting | speed < 0 | speed = 0 | speed > 0 and < 1000 | speed = 1000 | speed > 1000 |
Action | reverse at speed | pause playback | slow playback at speed | normal playback | fast playback at speed |
When setting fast-forward or fast-backward speeds, the requested speed can't be guaranteed for all devices. The graph used to play the track will select the supported speed closest to the one requested. The client application should use mme_play_get_status().
Some devices, such as iPods, do not maintain a constant fast-forward or fast-backward speed, but increase the speed according to the amount of time the fast-forward or fast-backward is maintained.
For devices with this behavior, there is no value in attempting to measure play time during a fast-forward or fast-backward. If you are testing with these devices, you can only ensure that fast-forward and fast-backward arrive at the end or beginning of a track faster with normal speed.
Note that behavior when fast-forward or fast-backward move to a new track is:
To seek to a specific time in a track that is being played, use mme_seektotime(), passing it the time location to which you want to go and continue playback. For example, to skip ahead 15 seconds from the current position in a track, use mme_play_get_status() to get the current time location of the playback, then call mme_seektotime() with the current time location plus 15000.
Scan mode plays a track for a specified number of seconds, then moves to the next track, scanning all tracks in a track session. To use scan mode and set the time that the MME plays a track before moving to the next track, call mme_setscanmode() with the number of milliseconds you want to play each track before moving the scan to the next track. To get the current scan mode setting, use mme_getscanmode(). To turn scan mode off, call mme_setscanmode() with the time-to-scan argument set to 0 (zero).
When gapless playback is enabled, if two tracks on the same mediastore use the same graph type, when moving from one track to the other, the MME attempts to minimize the silence between tracks.
To enable gapless playback, you need to start io-media with the appropriate arguments. For more information, see “Configuring gapless playback” in the MME Configuration Guide.
The MME stores information about tracks that have been played and will play in the track session in the trksessionview table. This information allows your client application to have the MME to move backwards through a track session, even if random play mode is enabled.
If random mode is off, playback advances through the tracks as they are listed in the sequentialid column of the trksessionview table. If random mode is on, playback advances through the tracks as they are listed in the randomid column of the trksessionview table. To view the previous or next tracks in a track session, use the file IDs listed before or after the current track in the relevant column.
The MME maintains information about how many times a track has been played. This count includes fast forwards through the track. The client application can use this information to build a most-popular or top-50 list.
The number of times a track has been played is maintained in the fullplay_count field of the library table.
The MME provides bookmarking capabilities that a client HMI can offer to end users. Bookmarks allow users to mark time locations on tracks in a track session and to resume playback from these locations. Bookmarks are recorded in the bookmarks table, and are identified by a bookmark ID (bookmarkid) and bookmark name (name), a mediastore ID (msid), and a track file ID (fid).
To view available bookmarks, query the bookmarks table. For example, to view all bookmarks for tracks on the current mediastore, where current_msid is the mediastore ID :
. SELECT bookmarkid, fid, msid, name FROM bookmarks WHERE msid=current_msid ORDER BY name;
Use the functions mme_bookmark_create() and mme_bookmark_delete() to create and delete bookmarks, and mme_play_bookmark() to start playback from a specified bookmark.
This section describes how to manage track sessions during playback.
The MME performs track changes across different mediastores. This feature is supported by buffer level reporting. The MME provides the amount of time (milliseconds of playback) remaining in the MME buffer. Client applications can retrieve this information by calling the function mme_play_get_status(). This information gives device controllers a more accurate measure on which to base decisions to wake up devices, such as the system HDD.
Client applications can use the time left in the MME buffer to decide to abort blocking reads in order to skip to tracks on a mediastore other than the HDD. Aborting a blocking read allows the MME to fulfill a request to start playback of a track on another mediastore, such as a CD, immediately. It does not have to wait for its buffer to empty, or for the device controller to wake up the HDD.
When a mediastore is removed from the system, the MME delivers the event MME_EVENT_MS_STATECHANGE, which carries the new state of the mediastore in mme_event_data_t.ms_state_change.new_state. If media on the mediastore is included in a currently playing track session, you can manage the change according to whether the track being played has been removed or is still on the system.
For example, if your track session includes tracks from both /fs/usb0 and /fs/usb1, and the track being played is on /fs/usb0:
If the track currently being played is on the removed mediastore, the MME delivers the event MME_PLAY_ERROR_DEVICEREMOVED, and stops playback:
If the track currently being played is not on the removed mediastore, the MME continues playback, and you can ensure that playback will continue uninterrupted to the end of the track session:
The MME supports seamless switching between track sessions; that is, changing playback from one track session to another without interrupting playback, if the new track session includes the track currently being played.
To seamlessly change track sessions during playback:
The MME will:
![]() |
|
For more information about MME behavior when switching playback between track sessions, see mme_settrksession() in the MME API Library Reference.
![]() |
![]() |
![]() |
![]() |