3 This document will attempt to gather up some of the bits and pieces
4 I've learned while hacking Rhythmbox. Rhythmbox is fairly complex,
5 and while some people would claim it is unnecessarily so, I think
6 writing a good music player is just not as simple as you might
7 think at first. So, let's begin. We'll start from the lower layers of
8 the internal dependency stack, and build up.
12 This class handles extracting tag information from files, and in the
13 future it will also handle writing. It has two current backends - one
14 that uses GStreamer, and another that uses the internal MonkeyMedia
19 This class basically takes as input a URI, and handles playing it. It
20 has two current implementations - one for GStreamer, and another for
21 Xine. It depends on RBMetadata, since it can advertise tag information
22 only received during playback (such as from internet radio).
26 This class is kind of an internal database which stores all the tag
27 information acquired from RBMetadata, as well as other things such
28 as the user song ratings and last play times.
30 Basically, it's a queryable cache. The idea is for it to have
31 pluggable backends; right now it just stores everything in an
34 RhythmDB has multiple threads; we'll talk later about thread safety.
38 The core data type is RhythmDBEntry - this is an abstract pointer
39 which represents either a a local song in the library, or internet
42 **** Dynamic properties
44 Each RhythmDBEntry has a set of properties associated with it. A
45 property has both an ID and a value. The value can be of many
46 different types; e.g. a string, integer, or float.
48 These dynamic properties pretty much correspond to the song
49 metadata you can see like song length, duration, location, etc.
53 As we mentioned before, RhythmDB was designed to have multiple storage
54 backends - for instance, you could store all your music data in a SQL
55 database. However, the current default implementation uses a
56 tree-structured in-memory database.
58 The tree goes from Genre -> Artist -> Album -> Song. This is what
59 allows it to efficiently implement the browser (filtering by genre,
60 artist, album). When you click on say an artist, Rhythmbox just
61 searches for songs in that subtree. Here's a picture:
63 ____RHYTHMDB_ENTRY_TYPE_SONG__
69 Artist1 Artist2 Artist3
72 Album1 Album2 Album3-- -- Album5 Album6---
73 | / \ --- \-- \-- \---- ---- \---
74 | -/ \ \- \- \- \ \--- \--- \--
75 Song1 Song2 Song3 Song4 Song5 Song6 Song7 Song8 Song9 Song10
77 RhythmDBTree does a lot of work to maintain this tree structure - it
78 can handle you changing just the artist of a song.
80 There is actually one of these trees for each "type" of RhythmDBEntry.
81 The main type is RHYTHMDB_ENTRY_TYPE_SONG, but there is also
82 RHYTHMDB_ENTRY_TYPE_IRADIO_STATION for Internet Radio stations.
86 RhythmDBTree can serialize and deserialize all the RhythmDBEntries to
87 a custom XML format. This actually runs in a separate thread when you
88 first start up Rhythmbox.
90 **** RhythmDBQueryModel
92 This is a *very* important class. It holds a sequence of
93 RhythmDBEntries. A RhythmDBQueryModel is used to store the results of
94 a query. It automatically remembers its query, and watches the
97 A RhythmDBQueryModel is the "bridge" between the various RhythmDB
98 database threads and the main GTK+ display.
100 **** RhythmDBPropertyModel
102 This class "attaches" to a RhythmDBQueryModel and keeps track of a
103 list of a certain property, such as RHYTHMDB_PROP_ALBUM.
107 This directory holds a lot of random widgets that Rhythmbox uses.
108 Here are some examples:
112 This widget provides a view of a RhythmDBQueryModel. It is the main
113 song list you see in all the sources.
117 Similar to RBEntryView, this widget provides a view of a
118 RhythmDBPropertyModel.
122 Rhythmbox has an idea of multiple music "sources", like the Library
123 and (Internet) Radio. The RBSource classes are basically the
124 user interface part of the "source" concept.
126 All of these sources derive from RBSource (sources/rb-source.[ch]),
127 which is an abstract base class. RBSource has a number of methods
128 which the specific sources like the Library implement. For example,
129 one of the simpler ones is:
131 gboolean rb_source_can_pause (RBSource *player);
133 So here, a source returns TRUE if it can pause (i.e. pause button should
134 be displayed). Another example is the rb_source_get_status method,
135 which is called to display a status string at the bottom of the window.
137 The RBShell maintains a list of available RBSources.
141 Finally, the shell is the outer Rhythmbox framework. It controls the
142 playback, menus, preferences, and most of the user interface in
143 general. The core component of the shell is RBShell, in
144 shell/rb-shell.c. It acts as kind of a catch-all for the various bits
145 of glue needed to keep Rhythmbox working together. It "owns" most of
146 the core data structures and the UI.
148 The shell is broken up into a number of subcomponents.
152 This widget handles the play/previous/next buttons, and contains
153 various other widgets for the status display and volume.
154 RBShellPlayer is a pretty important class, because it contains a lot
155 of the playback logic. However, it delgates a fair amount of this to:
157 *** RBPlayOrder (and subclasses)
159 These classes handle playing back a group of songs in a certain order. They
160 are used by RBShellPlayer.
162 *** RBSourceHeader is that thingy with the "Hide Browser" button and the search
165 *** RBStatusBar is the thing on the bottom with the Shuffle and Repeat buttons
166 and the status output.
168 *** RBShellPreferences manages the user preferences. It is just a dialog box
169 which pops up when you hit Edit->Preferences.
171 *** RBPlaylistManager takes care of any kind of playlist request, such
172 as the "New Playlist" menu item, or drag and drop of an artist (which
179 arch-tag: A description of the Rhythmbox internals