INTERNALS 6.37 KB
Newer Older
Colin Walters's avatar
Colin Walters committed
1 2 3 4 5 6
* Rhythmbox Internals

This document will attempt to gather up some of the bits and pieces
I've learned while hacking Rhythmbox.  Rhythmbox is fairly complex,
and while some people would claim it is unnecessarily so, I think
writing a good music player is just not as simple as you might
7 8
think at first.  So, let's begin.  We'll start from the lower layers of
the internal dependency stack, and build up.
Colin Walters's avatar
Colin Walters committed
9

10
** RBMetadata
Colin Walters's avatar
Colin Walters committed
11

12 13 14 15
This class handles extracting tag information from files, and in the
future it will also handle writing.  It has two current backends - one
that uses GStreamer, and another that uses the internal MonkeyMedia
library.
Colin Walters's avatar
Colin Walters committed
16

17
** RBPlayer
Colin Walters's avatar
Colin Walters committed
18

19 20 21 22
This class basically takes as input a URI, and handles playing it.  It
has two current implementations - one for GStreamer, and another for
Xine.  It depends on RBMetadata, since it can advertise tag information
only received during playback (such as from internet radio).
Colin Walters's avatar
Colin Walters committed
23

24
** RhythmDB
Colin Walters's avatar
Colin Walters committed
25

26 27 28
This class is kind of an internal database which stores all the tag
information acquired from RBMetadata, as well as other things such
as the user song ratings and last play times.
Colin Walters's avatar
Colin Walters committed
29

30 31 32
Basically, it's a queryable cache.  The idea is for it to have
pluggable backends; right now it just stores everything in an
XML file.
Colin Walters's avatar
Colin Walters committed
33

34
RhythmDB has multiple threads; we'll talk later about thread safety.
Colin Walters's avatar
Colin Walters committed
35

36
*** RhythmDBEntry
Colin Walters's avatar
Colin Walters committed
37

38 39 40
The core data type is RhythmDBEntry - this is an abstract pointer
which represents either a a local song in the library, or internet
radio station.
41 42 43

**** Dynamic properties

44 45 46
Each RhythmDBEntry has a set of properties associated with it.  A
property has both an ID and a value.  The value can be of many
different types; e.g. a string, integer, or float.
Colin Walters's avatar
Colin Walters committed
47 48 49 50

These dynamic properties pretty much correspond to the song
metadata you can see like song length, duration, location, etc.

51
*** RhythmDBTree
52

53 54 55 56
As we mentioned before, RhythmDB was designed to have multiple storage
backends - for instance, you could store all your music data in a SQL
database.  However, the current default implementation uses a
tree-structured in-memory database.
Colin Walters's avatar
Colin Walters committed
57

58 59 60 61
The tree goes from Genre -> Artist -> Album -> Song.  This is what
allows it to efficiently implement the browser (filtering by genre,
artist, album).  When you click on say an artist, Rhythmbox just
searches for songs in that subtree.  Here's a picture:
Colin Walters's avatar
Colin Walters committed
62

63 64 65
                          ____RHYTHMDB_ENTRY_TYPE_SONG__
                 ________/	       |		\__
	        /	               |	           \
Colin Walters's avatar
Colin Walters committed
66 67 68 69 70 71 72 73 74 75 76
       	  Genre1               	     Genre2                  Genre3
         /	---	    	       |       	       	       ...
        /	   \-	    	       |
       Artist1	    Artist2	     Artist3
     --	  |   ---      	 ---	       	--  -----
   -/  	  |	 \-	    Album4     	  \      \---
Album1  Album2   Album3--      	--    	  Album5   Album6---
  |	  /  \	   ---	 \-- 	  \-- 	    \----    ----   \---
  |	-/    \	      \-    \-	     \-	     \	 \---	 \---	\--
Song1  Song2  Song3   Song4 Song5    Song6   Song7  Song8  Song9  Song10

77 78
RhythmDBTree does a lot of work to maintain this tree structure - it
can handle you changing just the artist of a song.
Colin Walters's avatar
Colin Walters committed
79

80 81 82
There is actually one of these trees for each "type" of RhythmDBEntry.
The main type is RHYTHMDB_ENTRY_TYPE_SONG, but there is also
RHYTHMDB_ENTRY_TYPE_IRADIO_STATION for Internet Radio stations.
83

Colin Walters's avatar
Colin Walters committed
84 85
**** Saving/loading

86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
RhythmDBTree can serialize and deserialize all the RhythmDBEntries to
a custom XML format.  This actually runs in a separate thread when you
first start up Rhythmbox.

**** RhythmDBQueryModel

This is a *very* important class.  It holds a sequence of
RhythmDBEntries.  A RhythmDBQueryModel is used to store the results of
a query. It automatically remembers its query, and watches the
database for changes.

A RhythmDBQueryModel is the "bridge" between the various RhythmDB
database threads and the main GTK+ display.

**** RhythmDBPropertyModel

This class "attaches" to a RhythmDBQueryModel and keeps track of a
list of a certain property, such as RHYTHMDB_PROP_ALBUM.

** widgets

This directory holds a lot of random widgets that Rhythmbox uses.
Here are some examples:

*** RBEntryView:

This widget provides a view of a RhythmDBQueryModel.  It is the main
song list you see in all the sources.

*** RBPropertyView:

Similar to RBEntryView, this widget provides a view of a
RhythmDBPropertyModel.

** Sources

Rhythmbox has an idea of multiple music "sources", like the Library
and (Internet) Radio.  The RBSource classes are basically the
user interface part of the "source" concept.

All of these sources derive from RBSource (sources/rb-source.[ch]),
which is an abstract base class.  RBSource has a number of methods
which the specific sources like the Library implement.  For example,
one of the simpler ones is:

gboolean	rb_source_can_pause		(RBSource *player);

So here, a source returns TRUE if it can pause (i.e. pause button should
be displayed).  Another example is the rb_source_get_status method,
which is called to display a status string at the bottom of the window.

The RBShell maintains a list of available RBSources.

** The Shell

Finally, the shell is the outer Rhythmbox framework.  It controls the
playback, menus, preferences, and most of the user interface in
general.  The core component of the shell is RBShell, in
shell/rb-shell.c.  It acts as kind of a catch-all for the various bits
of glue needed to keep Rhythmbox working together.  It "owns" most of
the core data structures and the UI.

The shell is broken up into a number of subcomponents.

*** RBShellPlayer

This widget handles the play/previous/next buttons, and contains
various other widgets for the status display and volume.
RBShellPlayer is a pretty important class, because it contains a lot
of the playback logic.  However, it delgates a fair amount of this to:

*** RBPlayOrder (and subclasses)

These classes handle playing back a group of songs in a certain order.  They
are used by RBShellPlayer.

*** RBSourceHeader is that thingy with the "Hide Browser" button and the search
entry.

*** RBStatusBar is the thing on the bottom with the Shuffle and Repeat buttons
and the status output.

*** RBShellPreferences manages the user preferences.  It is just a dialog box
which pops up when you hit Edit->Preferences.

*** RBPlaylistManager takes care of any kind of playlist request, such
as the "New Playlist" menu item, or drag and drop of an artist (which
creates a playlist).
Colin Walters's avatar
Colin Walters committed
174

Colin Walters's avatar
Colin Walters committed
175 176 177
Local Variables:
mode: outline
End:
178 179

arch-tag: A description of the Rhythmbox internals