views:

37

answers:

1

basically the problem is, that the only way to get all instances of VLC is to search all non-named instances for the org.freedesktop.MediaPlayer identity function and call it.

(alternatively I could use the introspection API, but this wouldn't seem to solve my problem) Unfortunately many programs upon having sent a dbus call, simply do not respond, causing a long and costly timeout.

When this happens multiple times it can add up. Basically the builtin timeout is excessively long.

If I can decrease the dbus timeout somehow that will solve my problem, but the ideal solution would be a way.

I got the idea that I could put each call to "Identify" inside a thread and that I could kill threads that take too long, but this seems not to be suggested. Also adding multithreading greatly increases the CPU load while not increasing the speed of the program all that much.

here is the code that I am trying to get to run quickly (more or less) which is currently painfully slow.

import dbus
bus = dbus.SessionBus()
dbus_proxy = bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
names = dbus_proxy.ListNames()
for name in names:
    if name.startswith(':'):
        try:
            proxy = bus.get_object(name, '/')
            ident_method = proxy.get_dbus_method("Identity",     
                dbus_interface="org.freedesktop.MediaPlayer")

            print ident_method()

        except dbus.exceptions.DBusException:
            pass
+1  A: 

Easier than spawning a bunch of threads would be to make the calls to the different services asynchronously, providing a callback handler for when a result comes back or a D-Bus error occurs. All of the calls effectively happen in parallel, and your program can proceed as soon as it gets some positive results.

Here's a quick-and-dirty program that prints a list of all the services it finds. Note how quickly it gets all the positive results without having to wait for any timeouts from anything. In a real program you'd probably assign a do-nothing function to the error handler, since your goal here is to ignore the services that don't respond, but this example waits until it's heard from everything before quitting.

#! /usr/bin/env python

import dbus
import dbus.mainloop.glib
import functools
import glib

class VlcFinder (object):
    def __init__ (self, mainloop):
        self.outstanding = 0
        self.mainloop = mainloop

        bus = dbus.SessionBus ()
        dbus_proxy = bus.get_object ("org.freedesktop.DBus", "/org/freedesktop/DBus")
        names = dbus_proxy.ListNames ()
        for name in dbus_proxy.ListNames ():
            if name.startswith (":"):
                proxy = bus.get_object (name, "/")
                iface = dbus.Interface (proxy, "org.freedesktop.MediaPlayer")
                iface.Identity (reply_handler = functools.partial (self.reply_cb, name),
                                error_handler = functools.partial (self.error_cb, name))
                self.outstanding += 1

    def reply_cb (self, name, ver):
        print "Found {0}: {1}".format (name, ver)
        self.received_result ()

    def error_cb (self, name, msg):
        self.received_result ()

    def received_result (self):
        self.outstanding -= 1
        if self.outstanding == 0:
            self.mainloop.quit ()

if __name__ == "__main__":
    dbus.mainloop.glib.DBusGMainLoop (set_as_default = True)
    mainloop = glib.MainLoop ()
    finder = VlcFinder (mainloop)
    mainloop.run ()
Paul Kuliniewicz