libvlc and dbus interface
Asked Answered
D

2

7

I'm trying a to create a basic media player using libvlc which will be controlled through dbus. I'm using the gtk and libvlc bindings for python. The code is based on the official example from the vlc website

The only thing I modified is to add the dbus interface to the vlc instance

# Create a single vlc.Instance() to be shared by (possible) multiple players.
instance = vlc.Instance()
print vlc.libvlc_add_intf(instance, "dbus"); // this is what i added. // returns 0 which is ok

All is well, the demo works and plays any video files. but for some reason the dbus control module doesn't work (I can't believe I just said the dreaded "doesn't work" words):

I already have the working client dbus code which binds to the MPRIS 2 interface. I can control a normal instance of a VLC media player - that works just fine, but with the above example nothing happens. The dbus control module is loaded properly, since libvlc_add_intf doesn't return an error and i can see the MPRIS 2 service in D-Feet (org.mpris.MediaPlayer2.vlc). Even in D-Feet, trying to call any of the methods of the dbus vlc object returns no error but nothing happens.

Do I need to configure something else in order to make the dbus module control the libvlc player?

Thanks

UPDATE

It seems that creating the vlc Instance and setting a higher verbosity, shows that the DBus calls are received but they have no effect whatsoever on the player itself. Also, adding the RC interface to the instance instead of DBus, has some problems too: When I run the example from the command line it drops me to the RC interface console where i can type the control commands, but it has the same behaviour as DBus - nothing happens, no error, nada, absolutely nothing. It ignores the commands completely.

Any thoughts?

UPDATE 2

Here is the code that uses libvlc to create a basic player:

    from    dbus.mainloop.glib import DBusGMainLoop
    import gtk
    import  gobject


    import sys
    import vlc

    from gettext import gettext as _


    # Create a single vlc.Instance() to be shared by (possible) multiple players.
    instance = vlc.Instance("--one-instance --verbose 2")

    class VLCWidget(gtk.DrawingArea):
        """Simple VLC widget.

        Its player can be controlled through the 'player' attribute, which
        is a vlc.MediaPlayer() instance.
        """
        def __init__(self, *p):
            gtk.DrawingArea.__init__(self)
            self.player = instance.media_player_new()
            def handle_embed(*args):
                if sys.platform == 'win32':
                    self.player.set_hwnd(self.window.handle)
                else:
                    self.player.set_xwindow(self.window.xid)
                return True
            self.connect("map", handle_embed)
            self.set_size_request(640, 480)

    class VideoPlayer:
        """Example simple video player.
        """
        def __init__(self):
            self.vlc = VLCWidget()

        def main(self, fname):
            self.vlc.player.set_media(instance.media_new(fname))
            w = gtk.Window()
            w.add(self.vlc)
            w.show_all()
            w.connect("destroy", gtk.main_quit)
            self.vlc.player.play()
            DBusGMainLoop(set_as_default = True)
            gtk.gdk.threads_init()
            gobject.MainLoop().run()


    if __name__ == '__main__':
        if not sys.argv[1:]:
           print "You must provide at least 1 movie filename"
           sys.exit(1)
        if len(sys.argv[1:]) == 1:
            # Only 1 file. Simple interface
            p=VideoPlayer()
            p.main(sys.argv[1])

the script can be run from the command line like:

python example_vlc.py file.avi

The client code which connects to the vlc dbus object is too long to post so instead pretend that i'm using D-Feet to get the bus connection and post messages to it. Once the example is running, i can see the players dbus interface in d-feet, but i am unable to control it. Is there anything else that i should add to the code above to make it work?

Dosi answered 25/11, 2012 at 12:21 Comment(3)
did you managed to make it work ?Degree
@Degree unfortunately no :(Dosi
The problem might be that the gtk/vlc code is eating events. Try putting dbus in a subprocess via multiprocessing and communicate to it via queue. That way you ensure the two pieces use separate process space and events.Nothing
S
0

I can't see your implementation of your event loop, so it's hard to tell what might be causing commands to not be recognized or to be dropped. Is it possible your threads are losing the stacktrace information and are actually throwing exceptions?

You might get more responses if you added either a psuedo-code version of your event loop and DBus command parsing or a simplified version?

Slivovitz answered 25/11, 2012 at 12:21 Comment(0)
G
0

The working programs found on nullege.com use ctypes. One which acted as a server used rpyc. Ignoring that one.

The advantages of ctypes over dbus is a huge speed advantage (calling the C library code, not interacting using python) as well as not requiring the library to implement the dbus interface.

Didn't find any examples using gtk or dbus ;-(

Notable examples

PyNuvo vlc.py

Milonga Tango DJing program

Using dbus / gtk

dbus uses gobject mainloop, not gtk mainloop. Totally different beasts. Don't cross the streams! Some fixes:

Don't need this. Threads are evil.

gtk.gdk.threads_init()

gtk.main_quit() shouldn't work when using gobject Mainloop. gobject mainloop can't live within ur class.

if __name__ == '__main__':
loop = gobject.MainLoop()
loop.run()

Pass in loop into ur class. Then call to quit the app

loop.quit()

dbus (notify) / gtk working example

Not going to write ur vlc app for u. But here is a working example of using dbus / gtk. Just adapt to vlc. Assumed u took my advise on gtk above. As u know any instance of DesktopNotify must be called while using gobject.Mainloop . But u can place it anywhere within ur main class.

desktop_notify.py

from __future__ import print_function
import gobject
import time, dbus
from dbus.exceptions import DBusException
from dbus.mainloop.glib import DBusGMainLoop

class DesktopNotify(object):
    """ Notify-OSD ubuntu's implementation has a 20 message limit. U've been warned. When queue is full, delete old message before adding new messages."""
    #Static variables
    dbus_loop = None
    dbus_proxy = None
    dbus_interface = None
    loop = None

    @property
    def dbus_name(self):
        return ("org.freedesktop.Notifications")

    @property
    def dbus_path(self):
        return ("/org/freedesktop/Notifications")

    @property
    def dbus_interface(self):
        return self.dbus_name

    def __init__(self, strInit="initializing passive notification messaging")
        strProxyInterface = "<class 'dbus.proxies.Interface'>"
        """ Reinitializing dbus when making a 2nd class instance would be bad"""
        if str(type(DesktopNotify.dbus_interface)) != strProxyInterface:
            DesktopNotify.dbus_loop = DBusGMainLoop(set_as_default=True)
            bus = dbus.SessionBus(mainloop=DesktopNotify.dbus_loop)
            DesktopNotify.dbus_proxy = bus.get_object(self.dbus_name, self.dbus_path)
            DesktopNotify.dbus_interface = dbus.Interface(DesktopNotify.dbus_proxy, self.dbus_interface )
            DesktopNotify.dbus_proxy.connect_to_signal("NotificationClosed", self.handle_closed)

    def handle_closed(self, *arg, **kwargs):
        """ Notification closed by user or by code. Print message or not"""
        lngNotificationId = int(arg[0])
        lngReason = int(arg[1])

    def pop(self, lngID):
        """ ID stored in database, but i'm going to skip this and keep it simple"""
        try:
            DesktopNotify.dbus_interface.CloseNotification(lngID)
        except DBusException as why:
            print(self.__class__.__name__ + ".pop probably no message with id, lngID, why)
        finally:
            pass

    def push(self, strMsgTitle, strMsg, dictField):
        """ Create a new passive notification (took out retrying and handling full queues)"""
        now = time.localtime( time.time() )
        strMsgTime = strMsg + " " + time.asctime(now)
        del now
        strMsgTime = strMsgTime % dictField

        app_name="[your app name]"
        app_icon = ''
        actions = ''
        hint = ''
        expire_timeout = 10000 #Use seconds * 1000
        summary = strMsgTitle
        body = strMsgTime
        lngNotificationID = None
        try:
            lngNotificationID = DesktopNotify.dbus_interfacec.Notify(app_name, 0, app_icon, summary, body, actions, hint, expire_timeout)
        except DBusException as why:
            #Excellent spot to delete oldest notification and then retry
            print(self.__class__.__name__ + ".push Being lazy. Posting passive notification was unsuccessful.", why)
        finally:
            #Excellent spot to add to database upon success
            pass
Garrotte answered 8/4, 2013 at 15:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.