~ubuntu-branches/ubuntu/saucy/indicator-sound/saucy

« back to all changes in this revision

Viewing changes to src/mpris2-watcher.vala

  • Committer: Package Import Robot
  • Author(s): Ubuntu daily release, Lars Uebernickel, Ubuntu daily release
  • Date: 2013-08-29 02:08:13 UTC
  • mfrom: (28.220.13)
  • Revision ID: package-import@ubuntu.com-20130829020813-24ps50e56moc1cfs
Tags: 12.10.2+13.10.20130829-0ubuntu1
[ Lars Uebernickel ]
* Use bus_watch_namespace() for more robust monitoring of mpris
  players appearing or disappearing on the bus.

[ Ubuntu daily release ]
* Automatic snapshot from revision 371

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
Copyright 2010 Canonical Ltd.
3
 
 
4
 
Authors:
5
 
    Conor Curran <conor.curran@canonical.com>
6
 
 
7
 
This program is free software: you can redistribute it and/or modify it 
8
 
under the terms of the GNU General Public License version 3, as published 
9
 
by the Free Software Foundation.
10
 
 
11
 
This program is distributed in the hope that it will be useful, but 
12
 
WITHOUT ANY WARRANTY; without even the implied warranties of 
13
 
MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR 
14
 
PURPOSE.  See the GNU General Public License for more details.
15
 
 
16
 
You should have received a copy of the GNU General Public License along 
17
 
with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 
*/
19
 
 
20
 
using Xml;
21
 
 
22
 
public class Mpris2Watcher : GLib.Object
23
 
{
24
 
  DBusConnection session_bus;
25
 
 
26
 
  public signal void client_appeared ( string desktop_file_name,
27
 
                                       string dbus_name,
28
 
                                       bool use_playlists );
29
 
  public signal void client_disappeared ( string dbus_name );
30
 
 
31
 
  public Mpris2Watcher ()
32
 
  {
33
 
  }
34
 
 
35
 
  construct
36
 
  {
37
 
    const string match_rule = "type='signal'," +
38
 
                              "sender='org.freedesktop.DBus'," +
39
 
                              "interface='org.freedesktop.DBus'," +
40
 
                              "member='NameOwnerChanged'," +
41
 
                              "path='/org/freedesktop/DBus'," +
42
 
                              "arg0namespace='org.mpris.MediaPlayer2'";
43
 
    try {
44
 
      this.session_bus = Bus.get_sync (BusType.SESSION);
45
 
 
46
 
      this.session_bus.call_sync ("org.freedesktop.DBus",
47
 
                                  "/",
48
 
                                  "org.freedesktop.DBus",
49
 
                                  "AddMatch",
50
 
                                  new Variant ("(s)", match_rule),
51
 
                                  VariantType.TUPLE,
52
 
                                  DBusCallFlags.NONE,
53
 
                                  -1);
54
 
 
55
 
      this.session_bus.signal_subscribe ("org.freedesktop.DBus",
56
 
                                         "org.freedesktop.DBus",
57
 
                                         "NameOwnerChanged",
58
 
                                         "/org/freedesktop/DBus",
59
 
                                         null,
60
 
                                         DBusSignalFlags.NO_MATCH_RULE,
61
 
                                         this.name_owner_changed);
62
 
 
63
 
      this.check_for_active_clients.begin();
64
 
    }
65
 
    catch (GLib.Error e) {
66
 
      warning ("unable to set up name watch for mrpis clients: %s", e.message);
67
 
    }
68
 
  }
69
 
 
70
 
  // At startup check to see if there are clients up that we are interested in
71
 
  // More relevant for development and daemon's like mpd. 
72
 
  async void check_for_active_clients()
73
 
  {
74
 
    Variant interfaces;
75
 
 
76
 
    try {
77
 
      interfaces = yield this.session_bus.call ("org.freedesktop.DBus",
78
 
                                                "/",
79
 
                                                "org.freedesktop.DBus",
80
 
                                                "ListNames",
81
 
                                                null,
82
 
                                                new VariantType ("(as)"),
83
 
                                                DBusCallFlags.NONE,
84
 
                                                -1);
85
 
    }
86
 
    catch (GLib.Error e) {
87
 
      warning ("unable to search for existing mpris clients: %s ", e.message);
88
 
      return;
89
 
    }
90
 
 
91
 
    foreach (var val in interfaces.get_child_value (0)) {
92
 
      var address = (string) val;
93
 
      if (address.has_prefix (MPRIS_PREFIX)){
94
 
        MprisRoot? mpris2_root = this.create_mpris_root(address);
95
 
        if (mpris2_root == null) return;
96
 
        bool use_playlists = this.supports_playlists ( address );
97
 
        client_appeared (mpris2_root.DesktopEntry + ".desktop", address, use_playlists);
98
 
      }
99
 
    }
100
 
  }
101
 
 
102
 
  void name_owner_changed (DBusConnection con, string sender, string object_path,
103
 
                                  string interface_name, string signal_name, Variant parameters)
104
 
  {
105
 
    string name, previous_owner, current_owner;
106
 
 
107
 
    parameters.get ("(sss)", out name, out previous_owner, out current_owner);
108
 
 
109
 
    MprisRoot? mpris2_root = this.create_mpris_root (name);
110
 
    if (mpris2_root == null) return;
111
 
 
112
 
    if (previous_owner != "" && current_owner == "") {
113
 
      debug ("Client '%s' gone down", name);
114
 
      client_disappeared (name);
115
 
    }
116
 
    else if (previous_owner == "" && current_owner != "") {
117
 
      debug ("Client '%s' has appeared", name);
118
 
      bool use_playlists = this.supports_playlists ( name );
119
 
      client_appeared (mpris2_root.DesktopEntry + ".desktop", name, use_playlists);
120
 
    }
121
 
  }
122
 
 
123
 
  private MprisRoot? create_mpris_root ( string name ){
124
 
    MprisRoot mpris2_root = null;
125
 
    if ( name.has_prefix (MPRIS_PREFIX) ){
126
 
      try {
127
 
        mpris2_root = Bus.get_proxy_sync (  BusType.SESSION,
128
 
                                            name,
129
 
                                            MPRIS_MEDIA_PLAYER_PATH );
130
 
      }
131
 
      catch (IOError e){
132
 
        warning( "Mpris2watcher could not create a root interface: %s",
133
 
                  e.message );
134
 
      }
135
 
    }
136
 
    return mpris2_root;
137
 
  }
138
 
 
139
 
  private bool supports_playlists ( string name )
140
 
  {
141
 
    FreeDesktopIntrospectable introspectable;
142
 
 
143
 
    try {
144
 
      /* The dbusproxy flag parameter is needed to ensure Banshee does not 
145
 
       blow up. I suspect the issue is that if you
146
 
       try to instantiate a dbus object which does not have any properties 
147
 
       associated  with it, gdbus will attempt to fetch the properties (this is
148
 
       in the documentation) but the banshee mpris dbus object more than likely 
149
 
       causes a crash because it doesn't check for the presence of properties 
150
 
       before attempting to access them.
151
 
      */
152
 
      introspectable = Bus.get_proxy_sync (  BusType.SESSION,
153
 
                                             name,
154
 
                                             MPRIS_MEDIA_PLAYER_PATH, 
155
 
                                             GLib.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES);
156
 
      var results = introspectable.Introspect();
157
 
      return this.parse_interfaces (results);
158
 
    }
159
 
    catch (IOError e){
160
 
      warning( "Could not create an introspectable object: %s",
161
 
                e.message );
162
 
    }
163
 
    return false;
164
 
  }
165
 
 
166
 
  private bool parse_interfaces( string interface_info )
167
 
  {
168
 
    //parse the document from path
169
 
    bool result = false;
170
 
    Xml.Doc* xml_doc = Parser.parse_doc (interface_info);
171
 
    if (xml_doc == null) {
172
 
      warning ("Mpris2Watcher - parse-interfaces - failed to instantiate xml doc");
173
 
      return false;
174
 
    }
175
 
    //get the root node. notice the dereferencing operator -> instead of .
176
 
    Xml.Node* root_node = xml_doc->get_root_element ();
177
 
    if (root_node == null) {
178
 
      //free the document manually before throwing because the garbage collector can't work on pointers
179
 
      delete xml_doc;
180
 
      warning ("Mpris2Watcher - the interface info xml is empty");
181
 
      return false;
182
 
    }
183
 
 
184
 
    //let's parse those nodes
185
 
    for (Xml.Node* iter = root_node->children; iter != null; iter = iter->next) {
186
 
      //spaces btw. tags are also nodes, discard them
187
 
      if (iter->type != ElementType.ELEMENT_NODE){
188
 
        continue;
189
 
      }
190
 
      Xml.Attr* attributes = iter->properties; //get the node's name    
191
 
      string interface_name = attributes->children->content;
192
 
      debug ( "this dbus object has interface %s ", interface_name );
193
 
      if ( interface_name == MPRIS_PREFIX.concat("Playlists")){
194
 
        result = true;
195
 
      }
196
 
    }
197
 
    delete xml_doc;
198
 
    return result;
199
 
  }  
200
 
}