build,core,plugins: Port to GDBus and GVariant
[profile/ivi/rygel.git] / src / plugins / mpris / rygel-mpris-plugin-factory.vala
1 /*
2  * Copyright (C) 2009 Zeeshan Ali (Khattak) <zeeshanak@gnome.org>.
3  * Copyright (C) 2009,2010 Nokia Corporation.
4  *
5  * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
6  *                               <zeeshan.ali@nokia.com>
7  *
8  * This file is part of Rygel.
9  *
10  * Rygel is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * Rygel is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  */
24
25 using Rygel;
26 using Gee;
27 using FreeDesktop;
28
29 private MPRIS.PluginFactory plugin_factory;
30
31 public void module_init (PluginLoader loader) {
32     try {
33         plugin_factory = new MPRIS.PluginFactory (loader);
34     } catch (IOError error) {
35         critical ("Failed to fetch list of MPRIS services: %s\n",
36                   error.message);
37     }
38 }
39
40 public class Rygel.MPRIS.PluginFactory {
41     private const string DBUS_SERVICE = "org.freedesktop.DBus";
42     private const string DBUS_OBJECT = "/org/freedesktop/DBus";
43
44     private const string SERVICE_PREFIX = "org.mpris.MediaPlayer2.";
45     private const string MEDIA_PLAYER_PATH = "/org/mpris/MediaPlayer2";
46
47     DBusObject   dbus_obj;
48     PluginLoader loader;
49
50     public PluginFactory (PluginLoader loader) throws IOError {
51         this.dbus_obj = Bus.get_proxy_sync (BusType.SESSION,
52                                             DBUS_SERVICE,
53                                             DBUS_OBJECT);
54         this.loader = loader;
55
56         this.load_plugins.begin ();
57     }
58
59     private async void load_plugins () throws IOError {
60         var services = yield this.dbus_obj.list_names ();
61
62         foreach (var service in services) {
63             if (service.has_prefix (SERVICE_PREFIX) &&
64                 this.loader.get_plugin_by_name (service) == null) {
65                 yield this.load_plugin_n_handle_error (service);
66             }
67         }
68
69         yield this.load_activatable_plugins ();
70     }
71
72     private async void load_activatable_plugins () throws IOError {
73         var services = yield this.dbus_obj.list_activatable_names ();
74
75         foreach (var service in services) {
76             if (service.has_prefix (SERVICE_PREFIX) &&
77                 this.loader.get_plugin_by_name (service) == null) {
78                 yield this.load_plugin_n_handle_error (service);
79             }
80         }
81
82         this.dbus_obj.name_owner_changed.connect (this.name_owner_changed);
83     }
84
85     private void name_owner_changed (DBusObject dbus_obj,
86                                      string     name,
87                                      string     old_owner,
88                                      string     new_owner) {
89         var plugin = this.loader.get_plugin_by_name (name);
90
91         if (plugin != null) {
92             if (old_owner != "" && new_owner == "") {
93                 debug ("Service '%s' going down, marking it as unavailable",
94                        name);
95                 plugin.available = false;
96             } else if (old_owner == "" && new_owner != "") {
97                 debug ("Service '%s' up again, marking it as available", name);
98                 plugin.available = true;
99             }
100         } else if (name.has_prefix (SERVICE_PREFIX)) {
101             // Ah, new plugin available, lets use it
102             this.load_plugin_n_handle_error.begin (name);
103         }
104     }
105
106     private async void load_plugin_n_handle_error (string service_name) {
107         try {
108             yield this.load_plugin (service_name);
109         } catch (IOError error) {
110             warning ("Failed to load MPRIS2 plugin '%s': %s",
111                      service_name,
112                      error.message);
113         }
114     }
115
116     private async void load_plugin (string service_name) throws IOError {
117         // Create proxy to MediaObject iface to get the display name through
118         Properties props = Bus.get_proxy_sync (BusType.SESSION,
119                                                service_name,
120                                                MEDIA_PLAYER_PATH);
121
122         var props_hash = yield props.get_all (MediaPlayerProxy.IFACE);
123
124         this.load_plugin_from_props (service_name, props_hash);
125     }
126
127     private void load_plugin_from_props (string                    service_name,
128                                          HashTable<string,Variant> props_hash) {
129         var title = (string) props_hash.lookup ("Identity");
130         if (title == null) {
131             title = service_name;
132         }
133
134         var mime_types = (string[]) props_hash.lookup ("SupportedMimeTypes");
135         var schemes = (string[]) props_hash.lookup ("SupportedUriSchemes");
136
137         var plugin = new MPRIS.Plugin (service_name,
138                                        title,
139                                        mime_types,
140                                        schemes);
141
142         this.loader.add_plugin (plugin);
143     }
144 }