diff --git a/plugins/daap/Makefile.am b/plugins/daap/Makefile.am
index a22f866..c8f246d 100644
--- a/plugins/daap/Makefile.am
+++ b/plugins/daap/Makefile.am
@@ -22,6 +22,8 @@ libdaap_la_SOURCES = \
 	rb-dmap-container-db-adapter.h		  \
 	rb-daap-dialog.c			  \
 	rb-daap-dialog.h			  \
+	rb-dacp-source.c			  \
+	rb-dacp-source.h			  \
 	rb-rhythmdb-dmap-db-adapter.c             \
 	rb-rhythmdb-dmap-db-adapter.h             \
 	rb-rhythmdb-query-model-dmap-db-adapter.c \
@@ -83,10 +85,12 @@ BUILT_SOURCES =							\
 
 plugin_DATA = 			\
 	$(BUILT_SOURCES)	\
+	$(top_srcdir)/plugins/daap/remote-icon.png		\
 	$(NULL)
 
 EXTRA_DIST = 			\
 	$(gtkbuilder_DATA)	\
+	$(top_srcdir)/plugins/daap/remote-icon.png		\
 	$(uixml_DATA)		\
 	$(plugin_in_files)	\
 	$(NULL)
diff --git a/plugins/daap/daap-prefs.ui b/plugins/daap/daap-prefs.ui
index 961f391..cccbeb1 100644
--- a/plugins/daap/daap-prefs.ui
+++ b/plugins/daap/daap-prefs.ui
@@ -5,12 +5,10 @@
   <object class="GtkVBox" id="daap_vbox">
     <property name="visible">True</property>
     <property name="border_width">12</property>
-    <property name="orientation">vertical</property>
     <property name="spacing">18</property>
     <child>
       <object class="GtkVBox" id="vbox9">
         <property name="visible">True</property>
-        <property name="orientation">vertical</property>
         <property name="spacing">6</property>
         <child>
           <object class="GtkLabel" id="browser_views_label">
@@ -53,10 +51,26 @@
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkVBox" id="vbox10">
+                  <object class="GtkTable" id="table1">
                     <property name="visible">True</property>
-                    <property name="orientation">vertical</property>
-                    <property name="spacing">6</property>
+                    <property name="n_rows">4</property>
+                    <property name="n_columns">2</property>
+                    <property name="column_spacing">6</property>
+                    <property name="row_spacing">6</property>
+                    <child>
+                      <object class="GtkCheckButton" id="dacp_enable_check">
+                        <property name="label" translatable="yes">_Look for iPhone &amp; iPod Touch Remotes</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="use_underline">True</property>
+                        <property name="draw_indicator">True</property>
+                      </object>
+                      <packing>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                      </packing>
+                    </child>
                     <child>
                       <object class="GtkCheckButton" id="daap_enable_check">
                         <property name="label" translatable="yes">_Share my music</property>
@@ -67,99 +81,268 @@
                         <property name="draw_indicator">True</property>
                       </object>
                       <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">False</property>
-                        <property name="position">0</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="daap_name_entry">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="invisible_char">&#x25CF;</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="label18">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">Library _name:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">daap_name_entry</property>
+                      </object>
+                      <packing>
+                        <property name="x_options">GTK_FILL</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="forget_remotes_button">
+                        <property name="label" translatable="yes">Forget known Remotes</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="daap_password_check">
+                        <property name="label" translatable="yes">Require _password:</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="use_underline">True</property>
+                        <property name="draw_indicator">True</property>
+                      </object>
+                      <packing>
+                        <property name="top_attach">3</property>
+                        <property name="bottom_attach">4</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="daap_password_entry">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="visibility">False</property>
+                        <property name="invisible_char">&#x25CF;</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">3</property>
+                        <property name="bottom_attach">4</property>
                       </packing>
                     </child>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">False</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+  </object>
+  <object class="GtkAlignment" id="passcode_widget">
+    <property name="visible">True</property>
+    <child>
+      <object class="GtkVBox" id="vbox98">
+        <property name="visible">True</property>
+        <child>
+          <object class="GtkLabel" id="label2">
+            <property name="visible">True</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">&lt;b&gt;Add Remote&lt;/b&gt;</property>
+            <property name="use_markup">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkAlignment" id="pairing_widget">
+            <property name="visible">True</property>
+            <property name="xscale">0</property>
+            <property name="yscale">0</property>
+            <child>
+              <object class="GtkVBox" id="vbox99">
+                <property name="visible">True</property>
+                <property name="spacing">16</property>
+                <child>
+                  <object class="GtkLabel" id="label1">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">Please enter the passcode displayed on your device.</property>
+                  </object>
+                  <packing>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkAlignment" id="alignment3">
+                    <property name="visible">True</property>
+                    <property name="xscale">0</property>
+                    <property name="yscale">0</property>
                     <child>
-                      <object class="GtkTable" id="daap_box">
+                      <object class="GtkHBox" id="hbox1">
                         <property name="visible">True</property>
-                        <property name="n_rows">2</property>
-                        <property name="n_columns">2</property>
-                        <property name="column_spacing">6</property>
-                        <property name="row_spacing">6</property>
+                        <property name="spacing">8</property>
                         <child>
-                          <object class="GtkCheckButton" id="daap_password_check">
-                            <property name="label" translatable="yes">Require _password:</property>
+                          <object class="GtkEntry" id="passcode_entry1">
                             <property name="visible">True</property>
                             <property name="can_focus">True</property>
-                            <property name="receives_default">False</property>
-                            <property name="use_underline">True</property>
-                            <property name="draw_indicator">True</property>
+                            <property name="max_length">1</property>
+                            <property name="invisible_char">&#x25CF;</property>
+                            <property name="width_chars">1</property>
+                            <property name="xalign">0.5</property>
                           </object>
                           <packing>
-                            <property name="top_attach">1</property>
-                            <property name="bottom_attach">2</property>
-                            <property name="x_options">GTK_FILL</property>
-                            <property name="y_options"></property>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">0</property>
                           </packing>
                         </child>
                         <child>
-                          <object class="GtkEntry" id="daap_name_entry">
+                          <object class="GtkEntry" id="passcode_entry2">
                             <property name="visible">True</property>
                             <property name="can_focus">True</property>
+                            <property name="max_length">1</property>
                             <property name="invisible_char">&#x25CF;</property>
+                            <property name="width_chars">1</property>
+                            <property name="xalign">0.5</property>
                           </object>
                           <packing>
-                            <property name="left_attach">1</property>
-                            <property name="right_attach">2</property>
-                            <property name="y_options"></property>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">1</property>
                           </packing>
                         </child>
                         <child>
-                          <object class="GtkLabel" id="label18">
+                          <object class="GtkEntry" id="passcode_entry3">
                             <property name="visible">True</property>
-                            <property name="label" translatable="yes">Shared music _name:</property>
-                            <property name="use_underline">True</property>
-                            <property name="mnemonic_widget">daap_name_entry</property>
+                            <property name="can_focus">True</property>
+                            <property name="max_length">1</property>
+                            <property name="invisible_char">&#x25CF;</property>
+                            <property name="width_chars">1</property>
+                            <property name="xalign">0.5</property>
                           </object>
                           <packing>
-                            <property name="x_options">GTK_FILL</property>
-                            <property name="y_options"></property>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">2</property>
                           </packing>
                         </child>
                         <child>
-                          <object class="GtkEntry" id="daap_password_entry">
+                          <object class="GtkEntry" id="passcode_entry4">
                             <property name="visible">True</property>
                             <property name="can_focus">True</property>
-                            <property name="visibility">False</property>
+                            <property name="max_length">1</property>
                             <property name="invisible_char">&#x25CF;</property>
+                            <property name="width_chars">1</property>
+                            <property name="xalign">0.5</property>
                           </object>
                           <packing>
-                            <property name="left_attach">1</property>
-                            <property name="right_attach">2</property>
-                            <property name="top_attach">1</property>
-                            <property name="bottom_attach">2</property>
-                            <property name="y_options"></property>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">3</property>
                           </packing>
                         </child>
                       </object>
-                      <packing>
-                        <property name="position">1</property>
-                      </packing>
                     </child>
                   </object>
                   <packing>
                     <property name="position">1</property>
                   </packing>
                 </child>
+                <child>
+                  <object class="GtkLabel" id="pairing_status_widget">
+                    <property name="label" translatable="yes">&lt;span foreground="red"&gt;Could not pair with this Remote.&lt;/span&gt;</property>
+                    <property name="use_markup">True</property>
+                  </object>
+                  <packing>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
               </object>
-              <packing>
-                <property name="position">1</property>
-              </packing>
             </child>
           </object>
           <packing>
             <property name="position">1</property>
           </packing>
         </child>
+        <child>
+          <object class="GtkAlignment" id="finished_widget">
+            <property name="xscale">0</property>
+            <property name="yscale">0</property>
+            <child>
+              <object class="GtkHBox" id="finished_hbox">
+                <property name="visible">True</property>
+                <property name="spacing">16</property>
+                <child>
+                  <object class="GtkLabel" id="label3">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">You can now control Rhythmbox through your Remote</property>
+                  </object>
+                  <packing>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="close_pairing_button">
+                    <property name="label">gtk-close</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_stock">True</property>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="position">2</property>
+          </packing>
+        </child>
       </object>
-      <packing>
-        <property name="expand">False</property>
-        <property name="fill">False</property>
-        <property name="position">0</property>
-      </packing>
     </child>
   </object>
+  <object class="GtkSizeGroup" id="daap_group">
+    <property name="mode">both</property>
+  </object>
 </interface>
diff --git a/plugins/daap/rb-daap-plugin.c b/plugins/daap/rb-daap-plugin.c
index c03afe0..9802214 100644
--- a/plugins/daap/rb-daap-plugin.c
+++ b/plugins/daap/rb-daap-plugin.c
@@ -51,13 +51,17 @@
 #include "rb-daap-source.h"
 #include "rb-daap-sharing.h"
 #include "rb-daap-src.h"
+#include "rb-dacp-sharing.h"
+#include "rb-dacp-source.h"
 #include "rb-uri-dialog.h"
 
 #include <libdmapsharing/dmap.h>
+#include <libdmapsharing/dacp-share.h>
 
 /* preferences */
 #define CONF_DAAP_PREFIX  	CONF_PREFIX "/plugins/daap"
 #define CONF_ENABLE_BROWSING 	CONF_DAAP_PREFIX "/enable_browsing"
+#define CONF_ENABLE_REMOTE	CONF_DAAP_PREFIX "/enable_remote"
 
 #define DAAP_DBUS_PATH	"/org/gnome/Rhythmbox/DAAP"
 
@@ -75,10 +79,13 @@ struct RBDaapPluginPrivate
 	guint daap_ui_merge_id;
 
 	DMAPMdnsBrowser *mdns_browser;
+	
+	DACPShare *dacp_share;
 
 	GHashTable *source_lookup;
 
 	guint enable_browsing_notify_id;
+	guint enable_remote_notify_id;
 
 	GdkPixbuf *daap_share_pixbuf;
 	GdkPixbuf *daap_share_locked_pixbuf;
@@ -113,6 +120,10 @@ static void enable_browsing_changed_cb (GConfClient *client,
 					guint cnxn_id,
 					GConfEntry *entry,
 					RBDaapPlugin *plugin);
+static void enable_remote_changed_cb (GConfClient *client,
+					guint cnxn_id,
+					GConfEntry *entry,
+					RBDaapPlugin *plugin);
 static void libdmapsharing_debug (const char *domain,
 				  GLogLevelFlags level,
 				  const char *message,
@@ -217,6 +228,7 @@ impl_activate (RBPlugin *bplugin,
 	RBDaapPlugin *plugin = RB_DAAP_PLUGIN (bplugin);
 	gboolean no_registration;
 	gboolean enabled = TRUE;
+	gboolean remote_enabled = TRUE;
 	GConfValue *value;
 	GConfClient *client = eel_gconf_client_get_global ();
 	GtkUIManager *uimanager = NULL;
@@ -248,6 +260,24 @@ impl_activate (RBPlugin *bplugin,
 					    (GConfClientNotifyFunc) enable_browsing_changed_cb,
 					    plugin);
 
+	/* Check if Remote (DACP) lookup is enabled */
+	value = gconf_client_get_without_default (client,
+						  CONF_ENABLE_REMOTE, NULL);
+	if (value != NULL) {
+		remote_enabled = gconf_value_get_bool (value);
+		gconf_value_free (value);
+	}
+
+	plugin->priv->dacp_share = rb_daap_create_dacp_share (RB_PLUGIN (plugin));
+	if (remote_enabled) {
+		dacp_share_start_lookup (plugin->priv->dacp_share);
+	}
+
+	plugin->priv->enable_remote_notify_id =
+		eel_gconf_notification_add (CONF_ENABLE_REMOTE,
+					    (GConfClientNotifyFunc) enable_remote_changed_cb,
+					    plugin);
+
 	create_pixbufs (plugin);
 
 	g_object_get (shell,
@@ -328,6 +358,13 @@ impl_deactivate	(RBPlugin *bplugin,
 		plugin->priv->enable_browsing_notify_id = EEL_GCONF_UNDEFINED_CONNECTION;
 	}
 
+	g_object_unref (plugin->priv->dacp_share);
+	
+	if (plugin->priv->enable_remote_notify_id != EEL_GCONF_UNDEFINED_CONNECTION) {
+		eel_gconf_notification_remove (plugin->priv->enable_remote_notify_id);
+		plugin->priv->enable_remote_notify_id = EEL_GCONF_UNDEFINED_CONNECTION;
+	}
+
 	g_object_get (shell,
 		      "ui-manager", &uimanager,
 		      NULL);
@@ -453,6 +490,12 @@ rb_daap_plugin_get_icon (RBDaapPlugin *plugin,
 	return icon;
 }
 
+RBShell *
+rb_daap_plugin_get_shell (RBDaapPlugin *plugin)
+{
+	return plugin->priv->shell;
+}
+
 /* mDNS browsing */
 
 static RBSource *
@@ -616,6 +659,21 @@ enable_browsing_changed_cb (GConfClient *client,
 }
 
 static void
+enable_remote_changed_cb (GConfClient *client,
+			    guint cnxn_id,
+			    GConfEntry *entry,
+			    RBDaapPlugin *plugin)
+{
+	gboolean enabled = eel_gconf_get_boolean (CONF_ENABLE_REMOTE);
+
+	if (enabled) {
+		dacp_share_start_lookup (plugin->priv->dacp_share);
+	} else {
+		dacp_share_stop_lookup (plugin->priv->dacp_share);
+	}
+}
+
+static void
 libdmapsharing_debug (const char *domain,
 		      GLogLevelFlags level,
 		      const char *message,
@@ -740,7 +798,7 @@ preferences_response_cb (GtkWidget *dialog, gint response, RBPlugin *plugin)
 
 static void
 share_check_button_toggled_cb (GtkToggleButton *button,
-			       GtkWidget *widget)
+			       GtkBuilder *builder)
 {
 	gboolean b;
 
@@ -748,12 +806,23 @@ share_check_button_toggled_cb (GtkToggleButton *button,
 
 	eel_gconf_set_boolean (CONF_DAAP_ENABLE_SHARING, b);
 
-	gtk_widget_set_sensitive (widget, b);
+	//gtk_widget_set_sensitive (widget, b);
+}
+
+static void
+remote_check_button_toggled_cb (GtkToggleButton *button,
+			       gpointer data)
+{
+	gboolean b;
+
+	b = gtk_toggle_button_get_active (button);
+
+	eel_gconf_set_boolean (CONF_ENABLE_REMOTE, b);
 }
 
 static void
 password_check_button_toggled_cb (GtkToggleButton *button,
-				  GtkWidget *widget)
+				  GtkBuilder *builder)
 {
 	gboolean b;
 
@@ -761,7 +830,14 @@ password_check_button_toggled_cb (GtkToggleButton *button,
 
 	eel_gconf_set_boolean (CONF_DAAP_REQUIRE_PASSWORD, b);
 
-	gtk_widget_set_sensitive (widget, b);
+	//gtk_widget_set_sensitive (widget, b);
+}
+
+static void
+forget_remotes_button_toggled_cb (GtkToggleButton *button,
+				  gpointer data)
+{
+	eel_gconf_unset (CONF_KNOWN_REMOTES);
 }
 
 static gboolean
@@ -828,29 +904,40 @@ static void
 update_config_widget (RBDaapPlugin *plugin)
 {
 	GtkWidget *check;
+	GtkWidget *remote_check;
 	GtkWidget *name_entry;
 	GtkWidget *password_entry;
 	GtkWidget *password_check;
-	GtkWidget *box;
+	GtkWidget *forget_remotes_button;
+	//GtkWidget *box;
+	//GtkSizeGroup *daap_group;
 	gboolean sharing_enabled;
+	gboolean remote_enabled;
 	gboolean require_password;
 	char *name;
 	char *password;
 
 	check = GTK_WIDGET (gtk_builder_get_object (plugin->priv->builder, "daap_enable_check"));
+	remote_check = GTK_WIDGET (gtk_builder_get_object (plugin->priv->builder, "dacp_enable_check"));
 	password_check = GTK_WIDGET (gtk_builder_get_object (plugin->priv->builder, "daap_password_check"));
 	name_entry = GTK_WIDGET (gtk_builder_get_object (plugin->priv->builder, "daap_name_entry"));
 	password_entry = GTK_WIDGET (gtk_builder_get_object (plugin->priv->builder, "daap_password_entry"));
-	box = GTK_WIDGET (gtk_builder_get_object (plugin->priv->builder, "daap_box"));
+	forget_remotes_button = GTK_WIDGET (gtk_builder_get_object (plugin->priv->builder, "forget_remotes_button"));
 
 	sharing_enabled = eel_gconf_get_boolean (CONF_DAAP_ENABLE_SHARING);
 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), sharing_enabled);
-	g_signal_connect (check, "toggled", G_CALLBACK (share_check_button_toggled_cb), box);
+	g_signal_connect (check, "toggled", G_CALLBACK (share_check_button_toggled_cb), plugin->priv->builder);
+
+	remote_enabled = eel_gconf_get_boolean (CONF_ENABLE_REMOTE);
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (remote_check), remote_enabled);
+	g_signal_connect (remote_check, "toggled", G_CALLBACK (remote_check_button_toggled_cb), plugin->priv->builder);
 
 	require_password = eel_gconf_get_boolean (CONF_DAAP_REQUIRE_PASSWORD);
 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (password_check), require_password);
 	g_signal_connect (password_check, "toggled", G_CALLBACK (password_check_button_toggled_cb), password_entry);
 
+	g_signal_connect (forget_remotes_button, "clicked", G_CALLBACK (forget_remotes_button_toggled_cb), NULL);
+
 	name = eel_gconf_get_string (CONF_DAAP_SHARE_NAME);
 	if (name == NULL || name[0] == '\0')
 		name = rb_daap_sharing_default_share_name ();
@@ -867,7 +954,7 @@ update_config_widget (RBDaapPlugin *plugin)
 	g_signal_connect (password_entry, "focus-out-event",
 			  G_CALLBACK (share_password_entry_focus_out_event_cb), NULL);
 
-	gtk_widget_set_sensitive (box, sharing_enabled);
+	//gtk_widget_set_sensitive (box, sharing_enabled);
 	gtk_widget_set_sensitive (password_entry, require_password);
 }
 
diff --git a/plugins/daap/rb-daap-plugin.h b/plugins/daap/rb-daap-plugin.h
index 4f7686f..1b12599 100644
--- a/plugins/daap/rb-daap-plugin.h
+++ b/plugins/daap/rb-daap-plugin.h
@@ -30,6 +30,7 @@
 
 #include "rb-plugin.h"
 #include "rb-daap-source.h"
+#include <libdmapsharing/dacp-share.h>
 
 G_BEGIN_DECLS
 
@@ -63,6 +64,8 @@ GdkPixbuf *	rb_daap_plugin_get_icon 	(RBDaapPlugin *plugin,
 RBDAAPSource *	rb_daap_plugin_find_source_for_uri (RBDaapPlugin *plugin,
 						 const char *uri);
 
+RBShell *	rb_daap_plugin_get_shell	(RBDaapPlugin *plugin);
+
 G_END_DECLS
 
 #endif /* __RB_DAAP_PLUGIN_H */
diff --git a/plugins/daap/rb-daap-record.c b/plugins/daap/rb-daap-record.c
index e995b90..06ea9d7 100644
--- a/plugins/daap/rb-daap-record.c
+++ b/plugins/daap/rb-daap-record.c
@@ -45,6 +45,7 @@ struct RBDAAPRecordPrivate {
 	char *artist;
 	char *genre;
 	gboolean has_video;
+	gint mediakind;
 	gint rating;
 	int duration;
 	int track;
@@ -60,6 +61,7 @@ struct RBDAAPRecordPrivate {
 enum {
 	PROP_0,
 	PROP_LOCATION,
+	PROP_MEDIAKIND,
 	PROP_TITLE,
 	PROP_RATING,
 	PROP_FILESIZE,
@@ -115,6 +117,9 @@ rb_daap_record_set_property (GObject *object,
 			g_free (record->priv->format);
 			record->priv->format = g_value_dup_string (value);
 			break;
+		case PROP_MEDIAKIND:
+			record->priv->mediakind = g_value_get_int (value);
+			break;
 		case PROP_RATING:
 			record->priv->rating = g_value_get_int (value);
 			break;
@@ -190,6 +195,9 @@ rb_daap_record_get_property (GObject *object,
 		case PROP_FORMAT:
 			g_value_set_string (value, record->priv->format);
 			break;
+		case PROP_MEDIAKIND:
+			g_value_set_int (value, record->priv->mediakind);
+			break;
 		case PROP_RATING:
 			g_value_set_int (value, record->priv->rating);
 			break;
@@ -278,10 +286,11 @@ rb_daap_record_class_init (RBDAAPRecordClass *klass)
 	gobject_class->finalize     = rb_daap_record_finalize;	
 
 	g_object_class_override_property (gobject_class, PROP_LOCATION, "location");
+	g_object_class_override_property (gobject_class, PROP_MEDIAKIND, "mediakind");
 	g_object_class_override_property (gobject_class, PROP_TITLE, "title");
-	g_object_class_override_property (gobject_class, PROP_ALBUM, "daap.songalbum");
-	g_object_class_override_property (gobject_class, PROP_ARTIST, "daap.songartist");
-	g_object_class_override_property (gobject_class, PROP_GENRE, "daap.songgenre");
+	g_object_class_override_property (gobject_class, PROP_ALBUM, "songalbum");
+	g_object_class_override_property (gobject_class, PROP_ARTIST, "songartist");
+	g_object_class_override_property (gobject_class, PROP_GENRE, "songgenre");
 	g_object_class_override_property (gobject_class, PROP_FORMAT, "format");
 	g_object_class_override_property (gobject_class, PROP_RATING, "rating");
 	g_object_class_override_property (gobject_class, PROP_FILESIZE, "filesize");
@@ -382,6 +391,9 @@ RBDAAPRecord *rb_daap_record_new (RhythmDBEntry *entry)
 		}
 		record->priv->real_format = g_strdup (ext);
 		record->priv->format = g_strdup (record->priv->real_format);
+		
+		// Only support songs
+		record->priv->mediakind = 1;
 
 		record->priv->track    = rhythmdb_entry_get_ulong
 						(entry, RHYTHMDB_PROP_TRACK_NUMBER);
diff --git a/plugins/daap/rb-dacp-sharing.c b/plugins/daap/rb-dacp-sharing.c
new file mode 100644
index 0000000..82634e5
--- /dev/null
+++ b/plugins/daap/rb-dacp-sharing.c
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ *  Implmentation of DACP (aka iTouch Remote)
+ *
+ *  Copyright (C) 2010 Alexandre Rosenfeld <alexandre.rosenfeld@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <glib/gprintf.h>
+
+#include "rb-dacp-sharing.h"
+#include "rb-dacp-source.h"
+#include "rb-daap-plugin.h"
+#include "rb-rhythmdb-dmap-db-adapter.h"
+#include "rb-dmap-container-db-adapter.h"
+#include "rb-debug.h"
+#include "rb-dialog.h"
+#include "rb-playlist-manager.h"
+#include "eel-gconf-extensions.h"
+#include "rb-preferences.h"
+
+#include <libdmapsharing/dmap.h>
+#include <libdmapsharing/dacp-share.h>
+
+
+
+
+
diff --git a/plugins/daap/rb-dacp-sharing.h b/plugins/daap/rb-dacp-sharing.h
new file mode 100644
index 0000000..2b29b7a
--- /dev/null
+++ b/plugins/daap/rb-dacp-sharing.h
@@ -0,0 +1,40 @@
+/*
+ *  Header for DACP (aka iTouch Remote)
+ *
+ *  Copyright (C) 2010 Alexandre Rosenfeld <alexandre.rosenfeld@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#ifndef __DACP_SHARING_H
+#define __DACP_SHARING_H
+
+#include "rb-shell.h"
+
+G_BEGIN_DECLS
+
+
+G_END_DECLS
+
+#endif /* __DACP_SHARING_H */
diff --git a/plugins/daap/rb-dacp-source.c b/plugins/daap/rb-dacp-source.c
new file mode 100644
index 0000000..cfde212
--- /dev/null
+++ b/plugins/daap/rb-dacp-source.c
@@ -0,0 +1,725 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ *  Implementation of DACP (iTunes Remote) source object
+ *
+ *  Copyright (C) 2010 Alexandre Rosenfeld <alexandre.rosenfeld@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "rhythmdb.h"
+#include "rb-shell.h"
+#include "rb-source-group.h"
+#include "eel-gconf-extensions.h"
+#include "rb-dacp-source.h"
+#include "rb-stock-icons.h"
+#include "rb-debug.h"
+#include "rb-util.h"
+#include "rb-file-helpers.h"
+#include "rb-builder-helpers.h"
+#include "rb-dialog.h"
+#include "rb-preferences.h"
+#include "rb-playlist-manager.h"
+#include "rb-shell-player.h"
+#include "rb-sourcelist-model.h"
+#include "rb-rhythmdb-dmap-db-adapter.h"
+#include "rb-dmap-container-db-adapter.h"
+
+#include "rb-daap-plugin.h"
+
+#include <libdmapsharing/dmap.h>
+#include <libdmapsharing/dacp-share.h>
+
+static void rb_dacp_source_dispose (GObject *object);
+static void rb_dacp_source_set_property  (GObject *object,
+					  guint prop_id,
+					  const GValue *value,
+					  GParamSpec *pspec);
+static void rb_dacp_source_get_property  (GObject *object,
+					  guint prop_id,
+					  GValue *value,
+				 	  GParamSpec *pspec);
+
+static void rb_dacp_source_connecting (RBDACPSource *source, gboolean connecting);
+static gboolean entry_insert_text_cb (GtkWidget *entry, gchar *text, gint len, gint *position, RBDACPSource *rb_dacp_source);
+static gboolean entry_backspace_cb (GtkWidget *entry, RBDACPSource *rb_dacp_source);
+static void rb_dacp_source_create_ui (RBDACPSource *source, RBPlugin *plugin);
+static void remote_paired_cb (DACPShare *share, gchar *service_name, gboolean connected, RBDACPSource *source);
+
+static void dacp_remote_added (DACPShare *share, gchar *service_name, gchar *display_name, RBDaapPlugin *plugin);
+static void dacp_remote_removed (DACPShare *share, gchar *service_name, RBDaapPlugin *plugin);
+static void dacp_play_status_update (DACPShare *share, DACPPlayStatusUpdateData *data, RBDaapPlugin *plugin);
+
+/* DACPShare signals */
+static gboolean dacp_lookup_guid (DACPShare *share, gchar *guid);
+static void     dacp_add_guid    (DACPShare *share, gchar *guid);
+
+static void     dacp_set_volume  (DACPShare *share, gulong volume, RBDaapPlugin *plugin);
+static gulong   dacp_get_volume  (DACPShare *share, RBDaapPlugin *plugin);
+
+struct RBDACPSourcePrivate
+{
+	char *service_name;
+
+	gboolean done_pairing;
+	
+	DACPShare *dacp_share;
+	
+	GtkBuilder *builder;
+	GtkWidget *entries[4];
+	GtkWidget *finished_widget;
+	GtkWidget *pairing_widget;
+	GtkWidget *pairing_status_widget;
+};
+
+enum {
+	PROP_0,
+	PROP_SERVICE_NAME
+};
+
+G_DEFINE_TYPE (RBDACPSource, rb_dacp_source, RB_TYPE_SOURCE)
+
+static gboolean 
+entry_insert_text_cb (GtkWidget *entry, gchar *text, gint len, gint *position, RBDACPSource *source) 
+{
+	gchar new_char = text[*position];
+	gint entry_pos = 0;
+	gchar passcode[4];
+	int i;
+	
+	/* Find out which entry the user just entered text */
+	for (entry_pos = 0; entry_pos < 4; entry_pos++) {
+		if (entry == source->priv->entries[entry_pos]) {
+			break;
+		}
+	}
+	
+	if (!isdigit (new_char)) { 
+		/* is this a number? If not, don't let it in */
+		g_signal_stop_emission_by_name(entry, "insert-text");
+		return TRUE;
+	}
+	if (entry_pos < 3) {
+		/* Focus the next entry */
+		gtk_widget_grab_focus(source->priv->entries[entry_pos + 1]);
+	} else if (entry_pos == 3) {
+		/* The user entered all 4 characters of the passcode, so let's pair */
+		for (i = 0; i < 3; i++) {
+			const gchar *text = gtk_entry_get_text (GTK_ENTRY (source->priv->entries[i]));
+			passcode[i] = text[0];
+		}
+		/* The last character is still not in the entry */
+		passcode[3] = new_char;
+		rb_dacp_source_connecting (source, TRUE);
+		/* Let DACPShare do the heavy-lifting */
+		dacp_share_pair(source->priv->dacp_share, 
+		                source->priv->service_name, 
+		                passcode);
+	}
+	/* let the default handler display the number */
+	return FALSE; 
+}
+
+static gboolean 
+entry_backspace_cb (GtkWidget *entry, RBDACPSource *rb_dacp_source) 
+{
+	gint entry_pos = 0;
+	
+	/* Find out which entry the user just entered text */
+	for (entry_pos = 0; entry_pos < 4; entry_pos++) {
+		if (entry == rb_dacp_source->priv->entries[entry_pos]) {
+			break;
+		}
+	}
+	
+	if (entry_pos > 0) {
+		gtk_entry_set_text (GTK_ENTRY (rb_dacp_source->priv->entries[entry_pos]), "");
+		/* Focus the previous entry */
+		gtk_widget_grab_focus (rb_dacp_source->priv->entries[entry_pos - 1]);
+	}
+	
+	return FALSE;
+}
+
+static gboolean
+close_pairing_clicked_cb (GtkButton *button, RBDACPSource *source) 
+{
+	rb_source_delete_thyself (RB_SOURCE (source));
+	
+	return FALSE;
+}
+
+static void
+rb_dacp_source_dispose (GObject *object)
+{
+	G_OBJECT_CLASS (rb_dacp_source_parent_class)->dispose (object);
+}
+
+static void
+rb_dacp_source_finalize (GObject *object)
+{
+	RBDACPSource *source = RB_DACP_SOURCE (object);
+
+	g_free (source->priv->service_name);
+	g_object_unref (source->priv->builder);
+	g_object_unref (source->priv->dacp_share);
+
+	G_OBJECT_CLASS (rb_dacp_source_parent_class)->finalize (object);
+}
+
+static void
+rb_dacp_source_class_init (RBDACPSourceClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	RBSourceClass *source_class = RB_SOURCE_CLASS (klass);
+
+	object_class->dispose      = rb_dacp_source_dispose;
+	object_class->finalize     = rb_dacp_source_finalize;
+	object_class->get_property = rb_dacp_source_get_property;
+	object_class->set_property = rb_dacp_source_set_property;
+
+	source_class->impl_can_cut = (RBSourceFeatureFunc) rb_false_function;
+	source_class->impl_can_copy = (RBSourceFeatureFunc) rb_false_function;
+	source_class->impl_can_delete = (RBSourceFeatureFunc) rb_false_function;
+
+	g_object_class_install_property (object_class,
+					 PROP_SERVICE_NAME,
+					 g_param_spec_string ("service-name",
+						 	      "Service name",
+							      "mDNS/DNS-SD service name of the share",
+							      NULL,
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+	
+	g_type_class_add_private (klass, sizeof (RBDACPSourcePrivate));
+}
+
+static void
+rb_dacp_source_init (RBDACPSource *source)
+{
+	source->priv = G_TYPE_INSTANCE_GET_PRIVATE (source,
+						    RB_TYPE_DACP_SOURCE,
+						    RBDACPSourcePrivate);
+}
+
+static void
+rb_dacp_source_set_property (GObject *object,
+			    guint prop_id,
+			    const GValue *value,
+			    GParamSpec *pspec)
+{
+	RBDACPSource *source = RB_DACP_SOURCE (object);
+
+	switch (prop_id) {
+		case PROP_SERVICE_NAME:
+			source->priv->service_name = g_value_dup_string (value);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+rb_dacp_source_get_property (GObject *object,
+			    guint prop_id,
+			    GValue *value,
+			    GParamSpec *pspec)
+{
+	RBDACPSource *source = RB_DACP_SOURCE (object);
+
+	switch (prop_id) {
+		case PROP_SERVICE_NAME:
+			g_value_set_string (value, source->priv->service_name);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+RBDACPSource *
+rb_dacp_source_new (RBPlugin *plugin,
+                    RBShell *shell,
+                    DACPShare *dacp_share,
+                    const char *display_name,
+                    const char *service_name)
+{
+	RBDACPSource *source;
+	RhythmDB *db;
+	RhythmDBQueryModel *query_model;
+	RBSourceGroup *source_group;
+
+	/* Source icon data */
+	gchar *icon_filename;
+	gint icon_size;
+	GdkPixbuf *icon_pixbuf;
+	
+	icon_filename = rb_plugin_find_file (plugin, "remote-icon.png");
+	gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR, &icon_size, NULL);
+	icon_pixbuf = gdk_pixbuf_new_from_file_at_size (icon_filename, icon_size, icon_size, NULL);
+	
+	/* Remotes category */
+	source_group = rb_source_group_get_by_name ("remotes");
+	if (source_group == NULL) {
+		source_group = rb_source_group_register ("remotes", 
+		                                         _("Remotes"),
+		                                         RB_SOURCE_GROUP_CATEGORY_TRANSIENT);
+	}
+
+	/* This stops some assertions failing due to no query-model */
+	g_object_get (shell, "db", &db, NULL);
+	query_model = rhythmdb_query_model_new_empty (db);
+
+	source = RB_DACP_SOURCE (g_object_new (RB_TYPE_DACP_SOURCE,
+					  "name", display_name,
+					  "service-name", service_name,
+					  "icon", icon_pixbuf,
+					  "shell", shell,
+					  "visibility", TRUE,
+					  "entry-type", RHYTHMDB_ENTRY_TYPE_IGNORE,
+					  "source-group", source_group,
+					  "plugin", plugin,
+					  "query-model", query_model,
+					  NULL));
+
+	g_object_ref (dacp_share);
+	source->priv->dacp_share = dacp_share;
+	/* Retrieve notifications when the remote is finished pairing */
+	g_signal_connect_object (dacp_share, "remote-paired", G_CALLBACK (remote_paired_cb), source, 0);
+
+	g_free (icon_filename);
+	g_object_unref (icon_pixbuf);
+	
+	g_object_unref (db);
+	g_object_unref (query_model);
+	
+	rb_dacp_source_create_ui (source, plugin);
+
+	return source;
+}
+
+static void
+rb_dacp_source_create_ui (RBDACPSource *source, RBPlugin *plugin)
+{
+	gchar *builder_filename;
+	GtkButton *close_pairing_button;
+	PangoFontDescription *font;
+	int i;
+
+	builder_filename = rb_plugin_find_file (RB_PLUGIN (plugin), "daap-prefs.ui");
+	g_return_if_fail (builder_filename != NULL);
+
+	source->priv->builder = rb_builder_load (builder_filename, NULL);
+	g_free (builder_filename);
+
+	GtkWidget *passcode_widget = GTK_WIDGET (gtk_builder_get_object (source->priv->builder, "passcode_widget"));
+	gtk_container_add(GTK_CONTAINER(source), passcode_widget);
+	
+	close_pairing_button = GTK_BUTTON (gtk_builder_get_object (source->priv->builder, "close_pairing_button"));
+	g_signal_connect_object (close_pairing_button, "clicked", G_CALLBACK (close_pairing_clicked_cb), source, 0);
+	
+	source->priv->finished_widget = GTK_WIDGET (gtk_builder_get_object (source->priv->builder, "finished_widget"));
+	source->priv->pairing_widget = GTK_WIDGET (gtk_builder_get_object (source->priv->builder, "pairing_widget"));
+	source->priv->pairing_status_widget = GTK_WIDGET (gtk_builder_get_object (source->priv->builder, "pairing_status_widget"));
+	
+	font = pango_font_description_from_string ("normal 28");
+	
+	for (i = 0; i < 4; i++) {
+		gchar *entry_name = g_strdup_printf ("passcode_entry%d", i + 1);
+		source->priv->entries[i] = GTK_WIDGET (gtk_builder_get_object (source->priv->builder, entry_name));
+		gtk_widget_modify_font (source->priv->entries[i], font);
+		g_signal_connect_object (source->priv->entries[i], 
+		                         "insert-text", 
+		                         G_CALLBACK (entry_insert_text_cb), 
+		                         source,
+		                         0);
+		g_signal_connect_object (source->priv->entries[i], 
+		                         "backspace", 
+		                         G_CALLBACK (entry_backspace_cb), 
+		                         source,
+		                         0);
+		g_free(entry_name);
+	}
+	
+	pango_font_description_free (font);
+	
+	gtk_widget_show(passcode_widget);
+}
+
+
+static void
+rb_dacp_source_reset_passcode (RBDACPSource *source)
+{
+	int i;
+	
+	for (i = 0; i < 4; i++) {
+		gtk_entry_set_text (GTK_ENTRY (source->priv->entries[i]), "");
+	}
+	gtk_widget_grab_focus (source->priv->entries [0]);
+}
+
+void
+rb_dacp_source_remote_found (RBDACPSource *source) 
+{
+	if (source->priv->done_pairing) {
+		rb_dacp_source_reset_passcode (source);
+		gtk_widget_show (source->priv->pairing_widget);
+		gtk_widget_hide (source->priv->pairing_status_widget);
+		gtk_widget_hide (source->priv->finished_widget);
+		source->priv->done_pairing = FALSE;
+	}
+}
+
+void 
+rb_dacp_source_remote_lost (RBDACPSource *source)
+{
+	if (!source->priv->done_pairing) {
+		rb_source_delete_thyself (RB_SOURCE (source));
+	}
+}
+
+static void 
+rb_dacp_source_connecting (RBDACPSource *source, gboolean connecting) {
+	int i;
+	
+	if (connecting) {
+		gtk_widget_show (source->priv->pairing_status_widget);
+		gtk_label_set_markup (GTK_LABEL (source->priv->pairing_status_widget), "Connecting...");
+	} else {
+		gtk_label_set_markup (GTK_LABEL (source->priv->pairing_status_widget), "<span foreground=\"red\">Could not pair with this Remote.</span>");
+	}
+	
+	for (i = 0; i < 4; i++) {
+		gtk_widget_set_sensitive (source->priv->entries [i], !connecting);
+	}
+}
+
+static void
+remote_paired_cb (DACPShare *share, gchar *service_name, gboolean connected, RBDACPSource *source)
+{
+	/* Check if this remote is the remote paired */
+	if (g_strcmp0(service_name, source->priv->service_name) != 0)
+		return;
+	rb_dacp_source_connecting (source, FALSE);
+	if (connected) {
+		gtk_widget_hide (source->priv->pairing_widget);
+		gtk_widget_show (source->priv->finished_widget);
+		source->priv->done_pairing = TRUE;
+	} else {
+		gtk_widget_show (source->priv->pairing_status_widget);
+		rb_dacp_source_reset_passcode (source);
+	}
+}
+
+DACPShare *
+rb_daap_create_dacp_share (RBPlugin *plugin)
+{
+	DACPShare *share;
+	RhythmDB *rdb;
+	DMAPDb *db;
+	DMAPContainerDb *container_db;
+	RBPlaylistManager *playlist_manager;
+	RBShell *shell;
+
+	shell = rb_daap_plugin_get_shell (RB_DAAP_PLUGIN (plugin));
+
+	g_object_get (shell,
+	              "db", &rdb,
+	              "playlist-manager", &playlist_manager, 
+	              NULL);
+	db = DMAP_DB (rb_rhythmdb_dmap_db_adapter_new (rdb, RHYTHMDB_ENTRY_TYPE_SONG));
+	container_db = DMAP_CONTAINER_DB (rb_dmap_container_db_adapter_new (playlist_manager));
+
+	share = dacp_share_new (db, container_db);
+
+
+	g_signal_connect_object (share,
+				 "add-guid",
+				 G_CALLBACK (dacp_add_guid),
+				 RB_DAAP_PLUGIN (plugin),
+				 0);
+	g_signal_connect_object (share,
+				 "lookup-guid",
+				 G_CALLBACK (dacp_lookup_guid),
+				 RB_DAAP_PLUGIN (plugin),
+				 0);
+	
+	g_signal_connect_object (share,
+				 "remote-found",
+				 G_CALLBACK (dacp_remote_added),
+				 RB_DAAP_PLUGIN (plugin),
+				 0);
+	g_signal_connect_object (share,
+				 "remote-lost",
+				 G_CALLBACK (dacp_remote_removed),
+				 RB_DAAP_PLUGIN (plugin),
+				 0);
+	
+	g_signal_connect_object (share,
+				 "play-status-update",
+				 G_CALLBACK (dacp_play_status_update),
+				 RB_DAAP_PLUGIN (plugin),
+				 0);
+
+	
+	g_signal_connect_object (share,
+				 "set-volume",
+				 G_CALLBACK (dacp_set_volume),
+				 RB_DAAP_PLUGIN (plugin),
+				 0);
+	
+	g_signal_connect_object (share,
+				 "get-volume",
+				 G_CALLBACK (dacp_get_volume),
+				 RB_DAAP_PLUGIN (plugin),
+				 0);
+	
+	g_object_unref (db);
+	g_object_unref (container_db);
+	g_object_unref (rdb);
+	g_object_unref (playlist_manager);
+
+	return share;
+}
+
+static void
+dacp_add_guid (DACPShare *share,
+               gchar *guid)
+{
+	GSList *known_guids;
+	
+	known_guids = eel_gconf_get_string_list (CONF_KNOWN_REMOTES);
+	if (g_slist_find_custom (known_guids, guid, (GCompareFunc) g_strcmp0)) {
+		g_slist_free (known_guids);
+		return;
+	}
+	known_guids = g_slist_insert_sorted (known_guids, guid, (GCompareFunc) g_strcmp0);
+	eel_gconf_set_string_list (CONF_KNOWN_REMOTES, known_guids);
+
+	g_slist_free (known_guids);
+}
+
+static gboolean
+dacp_lookup_guid (DACPShare *share,
+                  gchar *guid)
+{
+	GSList *known_guids;
+	int found;
+	
+	known_guids = eel_gconf_get_string_list (CONF_KNOWN_REMOTES);
+	found = g_slist_find_custom (known_guids, guid, (GCompareFunc) g_strcmp0) != NULL;
+
+	g_slist_free (known_guids);
+	
+	return found;
+}
+
+static void
+dacp_set_volume (DACPShare *share,
+                 gulong volume,
+                 RBDaapPlugin *plugin)
+{
+	RBShellPlayer *player;
+	RBShell *shell;
+	
+	shell = rb_daap_plugin_get_shell (RB_DAAP_PLUGIN (plugin));
+	player = RB_SHELL_PLAYER (rb_shell_get_player (shell));
+
+	rb_debug ("Setting volume to %f (%lu)", volume / 100.0, volume);
+	rb_shell_player_set_volume (player, ((gdouble) volume) / 100.0, NULL);
+}
+
+
+static gulong
+dacp_get_volume (DACPShare *share,
+                 RBDaapPlugin *plugin)
+{
+	RBShellPlayer *player;
+	RBShell *shell;
+	gdouble volume;
+
+	shell = rb_daap_plugin_get_shell (RB_DAAP_PLUGIN (plugin));
+	player = RB_SHELL_PLAYER (rb_shell_get_player (shell));
+
+	rb_shell_player_get_volume (player, &volume, NULL);
+
+	return (gulong) ceil (volume * 100.0);
+}
+
+static void
+dacp_play_status_update (DACPShare *share,
+                         DACPPlayStatusUpdateData *data,
+                         RBDaapPlugin *plugin)
+{
+	RBShellPlayer *player;
+	RBShell *shell;
+	RhythmDBEntry *entry;
+	gboolean playing;
+	gboolean repeat;
+	guint playing_time;
+
+	shell = rb_daap_plugin_get_shell (RB_DAAP_PLUGIN (plugin));
+	player = RB_SHELL_PLAYER (rb_shell_get_player (shell));
+
+	rb_shell_player_get_playback_state (player, &(data->shuffle_state), &repeat);
+	data->repeat_state = repeat ? REPEAT_ALL : REPEAT_NONE;
+
+	entry = rb_shell_player_get_playing_entry (player);
+
+	if (entry) {
+		rb_shell_player_get_playing (player, &playing, NULL);
+		if (playing) {
+			data->play_state = PLAY_PLAYING;
+		} else {
+			data->play_state = PLAY_PAUSED;
+		}
+		data->track = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_TITLE);
+		data->artist = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_ARTIST);
+		data->album = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_ALBUM);
+		data->total_track_time = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DURATION) * 1000;
+
+		rb_shell_player_get_playing_time (player, &playing_time, NULL);
+		data->remaining_track_time = (data->total_track_time - playing_time * 1000);
+		
+		rhythmdb_entry_unref (entry);
+	} else {
+		data->play_state = PLAY_STOPPED;
+	}
+}
+
+/* Remote sources */
+typedef struct {
+	const gchar *name;
+	gboolean    found;
+	RBDACPSource *source;
+} FindSource;
+
+static gboolean
+sourcelist_find_dacp_source_foreach (GtkTreeModel *model,
+                                     GtkTreePath  *path,
+                                     GtkTreeIter  *iter,
+                                     FindSource   *fg)
+{
+	gchar *name;
+	RBSource *source;
+
+	gtk_tree_model_get (model, iter,
+	                    RB_SOURCELIST_MODEL_COLUMN_SOURCE, &source,
+	                    -1);
+	if (source && RB_IS_DACP_SOURCE (source)) {
+		g_object_get (source, "service-name", &name, NULL);
+		if (strcmp (name, fg->name) == 0) {
+			fg->found = TRUE;
+			fg->source = RB_DACP_SOURCE (source);
+		}
+		g_free (name);
+	}
+
+	return fg->found;
+}
+
+static RBDACPSource *
+find_dacp_source (RBShell *shell, const gchar *service_name)
+{
+	RBSourceListModel *source_list;
+	FindSource find_group;
+	
+	find_group.found = FALSE;
+	find_group.name = service_name;
+	
+	g_object_get (shell, "sourcelist-model", &source_list, NULL);
+	
+	gtk_tree_model_foreach (GTK_TREE_MODEL (source_list),
+	                        (GtkTreeModelForeachFunc) sourcelist_find_dacp_source_foreach,
+	                        &find_group);
+	
+	if (find_group.found) {
+		g_assert (find_group.source != NULL);
+		return find_group.source;
+	} else {
+		return NULL;
+	}
+}
+
+static void
+dacp_remote_added (DACPShare    *share,
+                   gchar        *service_name,
+                   gchar        *display_name,
+                   RBDaapPlugin *plugin)
+{
+	RBDACPSource *source;
+	RBShell *shell;
+
+	rb_debug ("Remote %s (%s) found", service_name, display_name);
+
+	shell = rb_daap_plugin_get_shell (plugin);
+
+	GDK_THREADS_ENTER ();
+	
+	source = find_dacp_source (shell, service_name);
+	if (source == NULL) {
+		source = rb_dacp_source_new (RB_PLUGIN (plugin),
+		                             rb_daap_plugin_get_shell (plugin),
+		                             share, 
+		                             display_name,
+		                             service_name);
+		rb_shell_append_source (shell, RB_SOURCE (source), NULL);
+	} else {
+		rb_dacp_source_remote_found (source);
+	}
+	
+	GDK_THREADS_LEAVE ();
+}
+
+static void
+dacp_remote_removed (DACPShare       *share,
+                     gchar           *service_name,
+                     RBDaapPlugin    *plugin)
+{
+	RBDACPSource *source;
+	RBShell *shell;
+
+	rb_debug ("Remote '%s' went away", service_name);
+
+	shell = rb_daap_plugin_get_shell (plugin);
+	
+	GDK_THREADS_ENTER ();
+	
+	source = find_dacp_source (shell, service_name);
+	
+	if (source != NULL) {
+		rb_dacp_source_remote_lost (source);
+	}
+	
+	GDK_THREADS_LEAVE ();
+}
\ No newline at end of file
diff --git a/plugins/daap/rb-dacp-source.h b/plugins/daap/rb-dacp-source.h
new file mode 100644
index 0000000..5da65e8
--- /dev/null
+++ b/plugins/daap/rb-dacp-source.h
@@ -0,0 +1,79 @@
+/*
+ *  Header for DACP (iTunes Remote) source object
+ *
+ *  Copyright (C) 2010 Alexandre Rosenfeld <alexandre.rosenfeld@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#ifndef __RB_DACP_SOURCE_H
+#define __RB_DACP_SOURCE_H
+
+#include "rb-shell.h"
+#include "rb-source.h"
+#include "rb-plugin.h"
+
+#include <libdmapsharing/dacp-share.h>
+
+G_BEGIN_DECLS
+
+/* preferences */
+#define CONF_DACP_PREFIX  	CONF_PREFIX "/sharing"
+#define CONF_KNOWN_REMOTES 	CONF_DACP_PREFIX "/known_remotes"
+
+#define RB_TYPE_DACP_SOURCE         (rb_dacp_source_get_type ())
+#define RB_DACP_SOURCE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_DACP_SOURCE, RBDACPSource))
+#define RB_DACP_SOURCE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_DACP_SOURCE, RBDACPSourceClass))
+#define RB_IS_DACP_SOURCE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_DACP_SOURCE))
+#define RB_IS_DACP_SOURCE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_DACP_SOURCE))
+#define RB_DACP_SOURCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_DACP_SOURCE, RBDACPSourceClass))
+
+typedef struct RBDACPSourcePrivate RBDACPSourcePrivate;
+
+typedef struct {
+	RBSource parent;
+
+	RBDACPSourcePrivate *priv;
+} RBDACPSource;
+
+typedef struct {
+	RBSourceClass parent;
+} RBDACPSourceClass;
+
+GType 		rb_dacp_source_get_type 	(void);
+
+RBDACPSource* rb_dacp_source_new 		(RBPlugin *plugin,
+						 RBShell *shell,
+						 DACPShare *dacp_share,
+						 const char *display_name,
+						 const char *service_name);
+
+void           rb_dacp_source_remote_found     (RBDACPSource *source);
+void           rb_dacp_source_remote_lost      (RBDACPSource *source);
+
+DACPShare     *rb_daap_create_dacp_share       (RBPlugin *plugin);
+
+G_END_DECLS
+
+#endif /* __RB_DACP_SOURCE_H */
diff --git a/plugins/daap/remote-icon.png b/plugins/daap/remote-icon.png
new file mode 100644
index 0000000..3ff94a8
Binary files /dev/null and b/plugins/daap/remote-icon.png differ
