diff --git a/configure.ac b/configure.ac
index 999af91..f53c9e5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -790,14 +790,9 @@ AC_ARG_ENABLE(daap,
                              [Disable DAAP support]),,
               enable_daap=auto)
 if test "x$enable_daap" != "xno"; then
-	PKG_CHECK_MODULES(DMAPSHARING, libdmapsharing-2.0,
+	PKG_CHECK_MODULES(DMAPSHARING, libdmapsharing-2.2,
 			  have_libdmapsharing=yes,
 			  have_libdmapsharing=no)
-	if test "x$have_libdmapsharing" = "xno"; then
-		PKG_CHECK_MODULES(DMAPSHARING, libdmapsharing-1.9 >= 1.9.0.21,
-				  have_libdmapsharing=yes,
-				  have_libdmapsharing=no)
-	fi
 
 	if test "x$have_libdmapsharing" = "xno" -a "x$enable_daap" = "xyes"; then
 		AC_MSG_ERROR([DAAP support explicitly requested, but libdmapsharing couldn't be found])
diff --git a/plugins/daap/Makefile.am b/plugins/daap/Makefile.am
index a22f866..8f9ea28 100644
--- a/plugins/daap/Makefile.am
+++ b/plugins/daap/Makefile.am
@@ -22,6 +22,10 @@ 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-dacp-player.c			  \
+	rb-dacp-player.h			  \
 	rb-rhythmdb-dmap-db-adapter.c             \
 	rb-rhythmdb-dmap-db-adapter.h             \
 	rb-rhythmdb-query-model-dmap-db-adapter.c \
@@ -83,10 +87,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..7cef165 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,27 @@
                   </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 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>
+                        <property name="x_options">GTK_FILL</property>
+                      </packing>
+                    </child>
                     <child>
                       <object class="GtkCheckButton" id="daap_enable_check">
                         <property name="label" translatable="yes">_Share my music</property>
@@ -67,99 +82,272 @@
                         <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="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                        <property name="x_options">GTK_FILL</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="GtkTable" id="daap_box">
+                      <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>
+                        <property name="x_options">GTK_FILL</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>
+                    <child>
+                      <placeholder/>
+                    </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="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..9ab7c04 100644
--- a/plugins/daap/rb-daap-plugin.c
+++ b/plugins/daap/rb-daap-plugin.c
@@ -51,6 +51,7 @@
 #include "rb-daap-source.h"
 #include "rb-daap-sharing.h"
 #include "rb-daap-src.h"
+#include "rb-dacp-source.h"
 #include "rb-uri-dialog.h"
 
 #include <libdmapsharing/dmap.h>
@@ -58,6 +59,7 @@
 /* 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 +77,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;
@@ -87,7 +92,8 @@ struct RBDaapPluginPrivate
 enum
 {
 	PROP_0,
-	PROP_SHUTDOWN
+	PROP_SHUTDOWN,
+	PROP_SHELL
 };
 
 G_MODULE_EXPORT GType register_rb_plugin (GTypeModule *module);
@@ -113,6 +119,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,
@@ -159,6 +169,14 @@ rb_daap_plugin_class_init (RBDaapPluginClass *klass)
 							       FALSE,
 							       G_PARAM_READABLE));
 
+	g_object_class_install_property (object_class,
+	                                 PROP_SHELL,
+	                                 g_param_spec_object ("shell",
+	                                                      "Shell",
+	                                                      "The Rhythmbox Shell",
+	                                                      RB_TYPE_SHELL,
+	                                                      G_PARAM_READABLE));
+
 	g_type_class_add_private (object_class, sizeof (RBDaapPluginPrivate));
 }
 
@@ -204,6 +222,9 @@ rb_daap_plugin_get_property (GObject *object,
 	case PROP_SHUTDOWN:
 		g_value_set_boolean (value, plugin->priv->shutdown);
 		break;
+	case PROP_SHELL:
+		g_value_take_object (value, plugin->priv->shell);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -217,6 +238,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 +270,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 +368,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);
@@ -616,6 +663,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,15 +802,32 @@ preferences_response_cb (GtkWidget *dialog, gint response, RBPlugin *plugin)
 
 static void
 share_check_button_toggled_cb (GtkToggleButton *button,
-			       GtkWidget *widget)
+			       GtkBuilder *builder)
 {
 	gboolean b;
+	GtkToggleButton *password_check;
+	GtkWidget *password_entry;
 
 	b = gtk_toggle_button_get_active (button);
 
 	eel_gconf_set_boolean (CONF_DAAP_ENABLE_SHARING, b);
 
-	gtk_widget_set_sensitive (widget, b);
+	password_check = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "daap_password_check"));
+	password_entry = GTK_WIDGET (gtk_builder_get_object (builder, "daap_password_entry"));
+
+	gtk_widget_set_sensitive (password_entry, b && gtk_toggle_button_get_active (password_check));
+	gtk_widget_set_sensitive (GTK_WIDGET (password_check), 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
@@ -764,6 +843,13 @@ password_check_button_toggled_cb (GtkToggleButton *button,
 	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
 share_name_entry_focus_out_event_cb (GtkEntry *entry,
 				     GdkEventFocus *event,
@@ -828,29 +914,38 @@ 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;
 	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 +962,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-record.c b/plugins/daap/rb-daap-record.c
index e995b90..0c50ae0 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;
@@ -55,11 +56,13 @@ struct RBDAAPRecordPrivate {
 	int bitrate;
 	char *sort_artist;
 	char *sort_album;
+	gint64 albumid;
 };
 
 enum {
 	PROP_0,
 	PROP_LOCATION,
+	PROP_MEDIAKIND,
 	PROP_TITLE,
 	PROP_RATING,
 	PROP_FILESIZE,
@@ -77,7 +80,8 @@ enum {
 	PROP_HAS_VIDEO,
 	PROP_REAL_FORMAT,
 	PROP_ARTIST_SORT_NAME,
-	PROP_ALBUM_SORT_NAME
+	PROP_ALBUM_SORT_NAME,
+	PROP_ALBUM_ID
 };
 
 static void rb_daap_record_finalize (GObject *object);
@@ -103,6 +107,9 @@ rb_daap_record_set_property (GObject *object,
 			g_free (record->priv->album);
 			record->priv->album = g_value_dup_string (value);
 			break;
+		case PROP_ALBUM_ID:
+			record->priv->albumid = g_value_get_int64 (value);
+			break;
 		case PROP_ARTIST:
 			g_free (record->priv->artist);
 			record->priv->artist = g_value_dup_string (value);
@@ -115,6 +122,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;
@@ -181,6 +191,9 @@ rb_daap_record_get_property (GObject *object,
 		case PROP_ALBUM:
 			g_value_set_string (value, record->priv->album);
 			break;
+		case PROP_ALBUM_ID:
+			g_value_set_int64 (value, record->priv->albumid);
+			break;
 		case PROP_ARTIST:
 			g_value_set_string (value, record->priv->artist);
 			break;
@@ -190,6 +203,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 +294,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");
@@ -295,6 +312,7 @@ rb_daap_record_class_init (RBDAAPRecordClass *klass)
 	g_object_class_override_property (gobject_class, PROP_HAS_VIDEO, "has-video");
 	g_object_class_override_property (gobject_class, PROP_ARTIST_SORT_NAME, "sort_artist");
 	g_object_class_override_property (gobject_class, PROP_ALBUM_SORT_NAME, "sort_album");
+	g_object_class_override_property (gobject_class, PROP_ALBUM_ID, "songalbumid");
 
 	g_object_class_install_property (gobject_class, PROP_REAL_FORMAT,
 	                        g_param_spec_string ("real-format",
@@ -369,6 +387,9 @@ RBDAAPRecord *rb_daap_record_new (RhythmDBEntry *entry)
 		record->priv->album    = rhythmdb_entry_dup_string
 						(entry, RHYTHMDB_PROP_ALBUM);
 
+		/* Since we don't support album id's on Rhythmbox, use the hash instead */
+		record->priv->albumid  = (gint64) g_quark_from_string (record->priv->album);
+
 		record->priv->genre    = rhythmdb_entry_dup_string
 						(entry, RHYTHMDB_PROP_GENRE);
 
@@ -382,6 +403,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-player.c b/plugins/daap/rb-dacp-player.c
new file mode 100644
index 0000000..bd8e005
--- /dev/null
+++ b/plugins/daap/rb-dacp-player.c
@@ -0,0 +1,274 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * rhythmbox
+ * Copyright (C) Alexandre Rosenfeld 2010 <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 <sys/stat.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include "rhythmdb.h"
+#include "rb-shell.h"
+#include "rb-shell-player.h"
+#include "rb-daap-record.h"
+
+#include "rb-dacp-player.h"
+
+struct _RBDACPPlayerPrivate {
+	RBShell *shell;
+};
+
+static void rb_dacp_player_get_property (GObject *object, guint prop_id, 
+                                         GValue *value, GParamSpec *pspec);
+static void rb_dacp_player_set_property (GObject *object, guint prop_id, 
+                                         const GValue *value, GParamSpec *pspec);
+enum {
+	PROP_0,
+	PROP_PLAYING_TIME,
+	PROP_SHUFFLE_STATE,
+	PROP_REPEAT_STATE,
+	PROP_PLAY_STATE,
+	PROP_VOLUME
+};
+
+static void
+rb_dacp_player_iface_init (gpointer iface, gpointer data)
+{
+	DACPPlayerInterface *dacp_player = iface;
+
+	g_assert (G_TYPE_FROM_INTERFACE (dacp_player) == TYPE_DACP_PLAYER);
+
+	dacp_player->now_playing_record  = rb_dacp_player_now_playing_record;
+	dacp_player->now_playing_artwork = rb_dacp_player_now_playing_artwork;
+	dacp_player->play_pause          = rb_dacp_player_play_pause;
+	dacp_player->next_item           = rb_dacp_player_next_item;
+	dacp_player->prev_item           = rb_dacp_player_prev_item;
+
+	dacp_player->cue_clear           = rb_dacp_player_cue_clear;
+	dacp_player->cue_play            = rb_dacp_player_cue_play;
+}
+
+G_DEFINE_TYPE_WITH_CODE (RBDACPPlayer, rb_dacp_player, G_TYPE_OBJECT, 
+                         G_IMPLEMENT_INTERFACE (TYPE_DACP_PLAYER, rb_dacp_player_iface_init))
+
+static void
+rb_dacp_player_init (RBDACPPlayer *object)
+{
+	object->priv = RB_DACP_PLAYER_GET_PRIVATE (object);
+}
+
+static void
+rb_dacp_player_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (rb_dacp_player_parent_class)->finalize (object);
+}
+
+static void
+rb_dacp_player_class_init (RBDACPPlayerClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (RBDACPPlayerPrivate));
+
+	object_class->set_property = rb_dacp_player_set_property;
+	object_class->get_property = rb_dacp_player_get_property;
+	object_class->finalize     = rb_dacp_player_finalize;
+
+	g_object_class_override_property (object_class, PROP_PLAYING_TIME, "playing-time");
+	g_object_class_override_property (object_class, PROP_SHUFFLE_STATE, "shuffle-state");
+	g_object_class_override_property (object_class, PROP_REPEAT_STATE, "repeat-state");
+	g_object_class_override_property (object_class, PROP_PLAY_STATE, "play-state");
+	g_object_class_override_property (object_class, PROP_VOLUME, "volume");
+	
+	object_class->finalize = rb_dacp_player_finalize;
+}
+
+static void
+rb_dacp_player_get_property (GObject *object,
+                             guint prop_id,
+                             GValue *value,
+                             GParamSpec *pspec)
+{
+	RBDACPPlayer *player = RB_DACP_PLAYER (object);
+	RBShellPlayer *shell_player;
+
+	shell_player = RB_SHELL_PLAYER (rb_shell_get_player (player->priv->shell));
+
+	gboolean repeat;
+	gboolean shuffle;
+	guint playing_time;
+	gboolean playing;
+	gdouble volume;
+	RhythmDBEntry *entry;
+	
+	switch (prop_id) {
+		case PROP_PLAYING_TIME:
+			rb_shell_player_get_playing_time (shell_player, &playing_time, NULL);
+			g_value_set_ulong (value, playing_time * 1000);
+			break;
+		case PROP_SHUFFLE_STATE:
+			rb_shell_player_get_playback_state (shell_player, &shuffle, &repeat);
+			g_value_set_boolean (value, shuffle);
+			break;
+		case PROP_REPEAT_STATE:
+			rb_shell_player_get_playback_state (shell_player, &shuffle, &repeat);
+			g_value_set_enum (value, repeat ? REPEAT_ALL : REPEAT_NONE);
+			break;
+		case PROP_PLAY_STATE:
+			entry = rb_shell_player_get_playing_entry (shell_player);
+			if (entry) {
+				g_object_get (shell_player, "playing", &playing, NULL);
+				g_value_set_enum (value, playing ? PLAY_PLAYING : PLAY_PAUSED);
+				rhythmdb_entry_unref (entry);
+			} else {
+				g_value_set_enum (value, PLAY_STOPPED);
+			}
+			break;
+		case PROP_VOLUME:
+			rb_shell_player_get_volume (shell_player, &volume, NULL);
+			g_value_set_ulong (value, (gulong) ceil (volume * 100.0));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+rb_dacp_player_set_property (GObject *object,
+                             guint prop_id,
+                             const GValue *value,
+                             GParamSpec *pspec)
+{
+	RBDACPPlayer *player = RB_DACP_PLAYER (object);
+	RBShellPlayer *shell_player;
+
+	shell_player = RB_SHELL_PLAYER (rb_shell_get_player (player->priv->shell));
+
+	gulong playing_time;
+	gboolean shuffle;
+	gboolean repeat;
+	gdouble volume;
+
+	switch (prop_id) {
+		case PROP_PLAYING_TIME:
+			playing_time = g_value_get_ulong (value);
+			rb_shell_player_set_playing_time (shell_player, (ulong) ceil (playing_time / 1000), NULL);
+			break;
+		case PROP_SHUFFLE_STATE:
+			rb_shell_player_get_playback_state (shell_player, &shuffle, &repeat);
+			rb_shell_player_set_playback_state (shell_player, g_value_get_boolean (value), repeat);
+			break;
+		case PROP_REPEAT_STATE:
+			rb_shell_player_get_playback_state (shell_player, &shuffle, &repeat);
+			repeat = (g_value_get_enum (value) != REPEAT_NONE);
+			rb_shell_player_set_playback_state (shell_player, shuffle, repeat);
+			break;
+		case PROP_VOLUME:
+			volume = ((double) g_value_get_ulong (value))  / 100.0;
+			rb_shell_player_set_volume (shell_player, volume, NULL);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+RBDACPPlayer *
+rb_dacp_player_new (RBShell *shell)
+{
+	RBDACPPlayer *player = NULL;
+
+	player = RB_DACP_PLAYER (g_object_new (RB_TYPE_DACP_PLAYER, NULL));
+	player->priv->shell = shell;
+
+	return player;
+}
+
+DAAPRecord *
+rb_dacp_player_now_playing_record (DACPPlayer *player)
+{
+	RBShellPlayer *shell_player;
+	RhythmDBEntry *entry;
+	DAAPRecord *record;
+
+	shell_player = RB_SHELL_PLAYER (rb_shell_get_player (RB_DACP_PLAYER (player)->priv->shell));
+	entry = rb_shell_player_get_playing_entry (shell_player);
+	if (entry == NULL) {
+		return NULL;
+	} else {
+		record = DAAP_RECORD (rb_daap_record_new (entry));
+		rhythmdb_entry_unref (entry);
+		return record;
+	}
+}
+
+GdkPixbuf *
+rb_dacp_player_now_playing_artwork (DACPPlayer *player, guint width, guint height)
+{
+	return NULL;
+}
+
+void 
+rb_dacp_player_play_pause (DACPPlayer *player)
+{
+	RBShellPlayer *shell_player;
+	shell_player = RB_SHELL_PLAYER (rb_shell_get_player (RB_DACP_PLAYER (player)->priv->shell));
+	rb_shell_player_playpause (shell_player, FALSE, NULL);
+}
+
+void 
+rb_dacp_player_next_item (DACPPlayer *player)
+{
+	RBShellPlayer *shell_player;
+	shell_player = RB_SHELL_PLAYER (rb_shell_get_player (RB_DACP_PLAYER (player)->priv->shell));
+	rb_shell_player_do_next (shell_player, NULL);
+}
+
+void 
+rb_dacp_player_prev_item (DACPPlayer *player)
+{
+	RBShellPlayer *shell_player;
+	shell_player = RB_SHELL_PLAYER (rb_shell_get_player (RB_DACP_PLAYER (player)->priv->shell));
+	rb_shell_player_do_previous (shell_player, NULL);
+}
+
+void 
+rb_dacp_player_cue_clear (DACPPlayer *player)
+{
+	//FIXME Implement
+	return;
+}
+
+void 
+rb_dacp_player_cue_play (DACPPlayer *player, GList *records, guint index)
+{
+	//FIXME Implement
+	return;
+}
\ No newline at end of file
diff --git a/plugins/daap/rb-dacp-player.h b/plugins/daap/rb-dacp-player.h
new file mode 100644
index 0000000..c35f5b3
--- /dev/null
+++ b/plugins/daap/rb-dacp-player.h
@@ -0,0 +1,78 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * rhythmbox
+ * Copyright (C) Alexandre Rosenfeld 2010 <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_PLAYER_H_
+#define _RB_DACP_PLAYER_H_
+
+#include <glib-object.h>
+#include <libdmapsharing/dmap.h>
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_DACP_PLAYER             (rb_dacp_player_get_type ())
+#define RB_DACP_PLAYER(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), RB_TYPE_DACP_PLAYER, RBDACPPlayer))
+#define RB_DACP_PLAYER_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), RB_TYPE_DACP_PLAYER, RBDACPPlayerClass))
+#define RB_IS_DACP_PLAYER(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), RB_TYPE_DACP_PLAYER))
+#define RB_IS_DACP_PLAYER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), RB_TYPE_DACP_PLAYER))
+#define RB_DACP_PLAYER_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), RB_TYPE_DACP_PLAYER, RBDACPPlayerClass))
+#define RB_DACP_PLAYER_GET_PRIVATE(o)   (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_DACP_PLAYER, RBDACPPlayerPrivate))
+
+typedef struct _RBDACPPlayerClass RBDACPPlayerClass;
+typedef struct _RBDACPPlayer RBDACPPlayer;
+
+typedef struct _RBDACPPlayerPrivate RBDACPPlayerPrivate;
+
+struct _RBDACPPlayerClass
+{
+	GObjectClass parent_class;
+};
+
+struct _RBDACPPlayer
+{
+	GObject parent_instance;
+	
+	RBDACPPlayerPrivate *priv;
+};
+
+GType rb_dacp_player_get_type (void) G_GNUC_CONST;
+
+RBDACPPlayer *rb_dacp_player_new (RBShell *shell);
+
+DAAPRecord *rb_dacp_player_now_playing_record  (DACPPlayer *player);
+GdkPixbuf  *rb_dacp_player_now_playing_artwork (DACPPlayer *player, guint width, guint height);
+void        rb_dacp_player_play_pause          (DACPPlayer *player);
+void        rb_dacp_player_next_item           (DACPPlayer *player);
+void        rb_dacp_player_prev_item           (DACPPlayer *player);
+
+void        rb_dacp_player_cue_clear           (DACPPlayer *player);
+void        rb_dacp_player_cue_play            (DACPPlayer *player, GList *records, guint index);
+
+G_END_DECLS
+
+#endif /* _RB_DACP_PLAYER_H_ */
diff --git a/plugins/daap/rb-dacp-source.c b/plugins/daap/rb-dacp-source.c
new file mode 100644
index 0000000..dfc7307
--- /dev/null
+++ b/plugins/daap/rb-dacp-source.c
@@ -0,0 +1,716 @@
+/* -*- 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-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 "rb-daap-sharing.h"
+#include "rb-dacp-player.h"
+
+#include "rb-dacp-source.h"
+
+#include <libdmapsharing/dmap.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);
+
+/* DACPShare signals */
+static gboolean dacp_lookup_guid (DACPShare *share, gchar *guid);
+static void     dacp_add_guid    (DACPShare *share, gchar *guid);
+
+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;
+	DACPPlayer *player;
+	RhythmDB *rdb;
+	DMAPDb *db;
+	DMAPContainerDb *container_db;
+	RBPlaylistManager *playlist_manager;
+	RBShell *shell;
+	gchar *name;
+	
+	g_object_get (plugin, "shell", &shell, NULL);
+
+	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));
+
+	player = DACP_PLAYER (rb_dacp_player_new (shell));
+	
+	name = eel_gconf_get_string (CONF_DAAP_SHARE_NAME);
+	if (name == NULL || *name == '\0') {
+		g_free (name);
+		name = rb_daap_sharing_default_share_name ();
+	}
+	
+	share = dacp_share_new (name, player, 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_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;
+
+	g_object_get (plugin, "shell", &shell, NULL);
+	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;
+
+	g_object_get (plugin, "shell", &shell, NULL);
+	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;
+
+	g_object_get (plugin, "shell", &shell, NULL);
+	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);
+
+	g_object_get (plugin, "shell", &shell, NULL);
+
+	GDK_THREADS_ENTER ();
+	
+	source = find_dacp_source (shell, service_name);
+	if (source == NULL) {
+		source = rb_dacp_source_new (RB_PLUGIN (plugin),
+		                             shell,
+		                             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);
+
+	g_object_get (plugin, "shell", &shell, NULL);
+	
+	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..02dabc8
--- /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/dmap.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 0000000000000000000000000000000000000000..3ff94a8607bdc48dea7697cf544a8bac0b764146
GIT binary patch
literal 4641
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
XTd(r#ieo0`00000NkvXXu0mjfm>Q<!

literal 0
HcmV?d00001

