]> git.sesse.net Git - vlc/blobdiff - modules/control/dbus/dbus_player.c
playlist: rename playlist_Pause() to playlist_TogglePause()
[vlc] / modules / control / dbus / dbus_player.c
index 54d1af1a9292f1c2dcb5ad3666006d1646d6e8a1..d55824906106c0c22571b17d5893eb7df03c806f 100644 (file)
@@ -1,13 +1,15 @@
 /*****************************************************************************
- * dbus-player.h : dbus control module (mpris v1.0) - /Player object
+ * dbus_player.c : dbus control module (mpris v2.2) - Player object
  *****************************************************************************
- * Copyright © 2006-2008 Rafaël Carré
- * Copyright © 2007-2010 Mirsal Ennaime
- * Copyright © 2009-2010 The VideoLAN team
+ * Copyright © 2006-2011 Rafaël Carré
+ * Copyright © 2007-2011 Mirsal Ennaime
+ * Copyright © 2009-2011 The VideoLAN team
+ * Copyright © 2013      Alex Merry
  * $Id$
  *
  * Authors:    Mirsal Ennaime <mirsal at mirsal fr>
  *             Rafaël Carré <funman at videolanorg>
+ *             Alex Merry <dev at randomguy3 me uk>
  *
  * 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
 
 #include <vlc_common.h>
 #include <vlc_playlist.h>
+#include <vlc_input.h>
 #include <vlc_interface.h>
-#include <vlc_aout.h>
 
 #include <math.h>
 
 #include "dbus_player.h"
 #include "dbus_common.h"
 
-static int MarshalStatus ( intf_thread_t *, DBusMessageIter * );
-
-/* XML data to answer org.freedesktop.DBus.Introspectable.Introspect requests */
-static const char* psz_player_introspection_xml =
-"<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
-"\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
-"<node>"
-"  <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
-"    <method name=\"Introspect\">\n"
-"      <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
-"    </method>\n"
-"  </interface>\n"
-"  <interface name=\"org.freedesktop.MediaPlayer\">\n"
-"    <method name=\"GetStatus\">\n"
-"      <arg type=\"(iiii)\" direction=\"out\" />\n"
-"    </method>\n"
-"    <method name=\"Prev\">\n"
-"    </method>\n"
-"    <method name=\"Next\">\n"
-"    </method>\n"
-"    <method name=\"Stop\">\n"
-"    </method>\n"
-"    <method name=\"Play\">\n"
-"    </method>\n"
-"    <method name=\"Pause\">\n"
-"    </method>\n"
-"    <method name=\"Repeat\">\n"
-"      <arg type=\"b\" direction=\"in\" />\n"
-"    </method>\n"
-"    <method name=\"VolumeSet\">\n"
-"      <arg type=\"i\" direction=\"in\" />\n"
-"    </method>\n"
-"    <method name=\"VolumeGet\">\n"
-"      <arg type=\"i\" direction=\"out\" />\n"
-"    </method>\n"
-"    <method name=\"PositionSet\">\n"
-"      <arg type=\"i\" direction=\"in\" />\n"
-"    </method>\n"
-"    <method name=\"PositionGet\">\n"
-"      <arg type=\"i\" direction=\"out\" />\n"
-"    </method>\n"
-"    <method name=\"GetMetadata\">\n"
-"      <arg type=\"a{sv}\" direction=\"out\" />\n"
-"    </method>\n"
-"    <method name=\"GetCaps\">\n"
-"      <arg type=\"i\" direction=\"out\" />\n"
-"    </method>\n"
-"    <signal name=\"TrackChange\">\n"
-"      <arg type=\"a{sv}\"/>\n"
-"    </signal>\n"
-"    <signal name=\"StatusChange\">\n"
-"      <arg type=\"(iiii)\"/>\n"
-"    </signal>\n"
-"    <signal name=\"CapsChange\">\n"
-"      <arg type=\"i\"/>\n"
-"    </signal>\n"
-"  </interface>\n"
-"</node>\n"
-;
-
-DBUS_METHOD( PositionGet )
-{ /* returns position in milliseconds */
-    REPLY_INIT;
-    OUT_ARGUMENTS;
-    dbus_int32_t i_pos;
-
-    input_thread_t *p_input = playlist_CurrentInput( PL );
+static int
+MarshalPosition( intf_thread_t *p_intf, DBusMessageIter *container )
+{
+    /* returns position in microseconds */
+    dbus_int64_t i_pos;
+    input_thread_t *p_input = pl_CurrentInput( p_intf );
 
     if( !p_input )
         i_pos = 0;
+
     else
     {
-        i_pos = var_GetTime( p_input, "time" ) / 1000;
+        i_pos = var_GetTime( p_input, "time" );
         vlc_object_release( p_input );
     }
-    ADD_INT32( &i_pos );
-    REPLY_SEND;
+
+    if( !dbus_message_iter_append_basic( container, DBUS_TYPE_INT64, &i_pos ) )
+        return VLC_ENOMEM;
+
+    return VLC_SUCCESS;
 }
 
-DBUS_METHOD( PositionSet )
-{ /* set position in milliseconds */
+DBUS_METHOD( SetPosition )
+{ /* set position in microseconds */
 
     REPLY_INIT;
+    dbus_int64_t i_pos;
     vlc_value_t position;
-    dbus_int32_t i_pos;
+    char *psz_trackid, *psz_dbus_trackid;
+    input_item_t *p_item;
 
     DBusError error;
     dbus_error_init( &error );
 
     dbus_message_get_args( p_from, &error,
-            DBUS_TYPE_INT32, &i_pos,
+            DBUS_TYPE_OBJECT_PATH, &psz_dbus_trackid,
+            DBUS_TYPE_INT64, &i_pos,
             DBUS_TYPE_INVALID );
 
     if( dbus_error_is_set( &error ) )
@@ -138,45 +86,48 @@ DBUS_METHOD( PositionSet )
         dbus_error_free( &error );
         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     }
-    input_thread_t *p_input = playlist_CurrentInput( PL );
+
+    input_thread_t *p_input = pl_CurrentInput( p_this );
 
     if( p_input )
     {
-        position.i_time = ((mtime_t)i_pos) * 1000;
-        var_Set( p_input, "time", position );
+        if( ( p_item = input_GetItem( p_input ) ) )
+        {
+            if( -1 == asprintf( &psz_trackid,
+                                MPRIS_TRACKID_FORMAT,
+                                p_item->i_id ) )
+            {
+                vlc_object_release( p_input );
+                return DBUS_HANDLER_RESULT_NEED_MEMORY;
+            }
+
+            if( !strcmp( psz_trackid, psz_dbus_trackid ) )
+            {
+                position.i_time = (mtime_t) i_pos;
+                var_Set( p_input, "time", position );
+            }
+            free( psz_trackid );
+        }
+
         vlc_object_release( p_input );
     }
-    REPLY_SEND;
-}
-
-DBUS_METHOD( VolumeGet )
-{ /* returns volume in percentage */
-    REPLY_INIT;
-    OUT_ARGUMENTS;
-    dbus_int32_t i_dbus_vol;
-    audio_volume_t i_vol;
 
-    /* 2nd argument of aout_VolumeGet is int32 */
-    aout_VolumeGet( PL, &i_vol );
 
-    double f_vol = 100. * i_vol / AOUT_VOLUME_MAX;
-    i_dbus_vol = round( f_vol );
-    ADD_INT32( &i_dbus_vol );
     REPLY_SEND;
 }
 
-DBUS_METHOD( VolumeSet )
-{ /* set volume in percentage */
+DBUS_METHOD( Seek )
+{
     REPLY_INIT;
+    dbus_int64_t i_step;
+    vlc_value_t  newpos;
+    mtime_t      i_pos;
 
     DBusError error;
     dbus_error_init( &error );
 
-    dbus_int32_t i_dbus_vol;
-    audio_volume_t i_vol;
-
     dbus_message_get_args( p_from, &error,
-            DBUS_TYPE_INT32, &i_dbus_vol,
+            DBUS_TYPE_INT64, &i_step,
             DBUS_TYPE_INVALID );
 
     if( dbus_error_is_set( &error ) )
@@ -187,9 +138,49 @@ DBUS_METHOD( VolumeSet )
         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     }
 
-    double f_vol = AOUT_VOLUME_MAX * i_dbus_vol / 100.;
-    i_vol = round( f_vol );
-    aout_VolumeSet( PL, i_vol );
+    input_thread_t *p_input = pl_CurrentInput( p_this );
+    if( p_input && var_GetBool( p_input, "can-seek" ) )
+    {
+        i_pos = var_GetTime( p_input, "time" );
+        newpos.i_time = (mtime_t) i_step + i_pos;
+
+        if( newpos.i_time < 0 )
+            newpos.i_time = 0;
+
+        var_Set( p_input, "time", newpos );
+    }
+
+    if( p_input )
+        vlc_object_release( p_input );
+
+    REPLY_SEND;
+}
+
+static int
+MarshalVolume( intf_thread_t *p_intf, DBusMessageIter *container )
+{
+    float f_vol = playlist_VolumeGet( p_intf->p_sys->p_playlist );
+    if( f_vol < 0.f )
+        f_vol = 1.f; /* ? */
+
+    double d_vol = f_vol;
+
+    if( !dbus_message_iter_append_basic( container, DBUS_TYPE_DOUBLE, &d_vol ) )
+        return VLC_ENOMEM;
+
+    return VLC_SUCCESS;
+}
+
+DBUS_METHOD( VolumeSet )
+{
+    REPLY_INIT;
+    double d_dbus_vol;
+
+    if( VLC_SUCCESS != DemarshalSetPropertyValue( p_from, &d_dbus_vol ) )
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+    playlist_VolumeSet( PL, fmaxf( d_dbus_vol, 0.f ) );
+
     REPLY_SEND;
 }
 
@@ -214,18 +205,16 @@ DBUS_METHOD( Stop )
     REPLY_SEND;
 }
 
-DBUS_METHOD( GetStatus )
-{ /* returns the current status as a struct of 4 ints */
-/*
-    First   0 = Playing, 1 = Paused, 2 = Stopped.
-    Second  0 = Playing linearly , 1 = Playing randomly.
-    Third   0 = Go to the next element once the current has finished playing , 1 = Repeat the current element
-    Fourth  0 = Stop playing once the last element has been played, 1 = Never give up playing *
- */
+DBUS_METHOD( Play )
+{
     REPLY_INIT;
-    OUT_ARGUMENTS;
+    input_thread_t *p_input =  pl_CurrentInput( p_this );
+
+    if( !p_input || var_GetInteger( p_input, "state" ) != PLAYING_S )
+        playlist_Play( PL );
 
-    MarshalStatus( p_this, &args );
+    if( p_input )
+        vlc_object_release( p_input );
 
     REPLY_SEND;
 }
@@ -233,39 +222,43 @@ DBUS_METHOD( GetStatus )
 DBUS_METHOD( Pause )
 {
     REPLY_INIT;
-    playlist_Pause( PL );
+    input_thread_t *p_input = pl_CurrentInput( p_this );
+
+    if( p_input && var_GetInteger(p_input, "state") == PLAYING_S )
+        playlist_TogglePause( PL );
+
+    if( p_input )
+        vlc_object_release( p_input );
+
     REPLY_SEND;
 }
 
-DBUS_METHOD( Play )
+DBUS_METHOD( PlayPause )
 {
     REPLY_INIT;
+    input_thread_t *p_input = pl_CurrentInput( p_this );
 
-    input_thread_t *p_input =  playlist_CurrentInput( PL );
+    if( p_input && var_GetInteger(p_input, "state") == PLAYING_S )
+        playlist_TogglePause( PL );
+    else
+        playlist_Play( PL );
 
     if( p_input )
-    {
-        double i_pos = 0;
-        input_Control( p_input, INPUT_SET_POSITION, i_pos );
         vlc_object_release( p_input );
-    }
-    else
-        playlist_Play( PL );
 
     REPLY_SEND;
 }
 
-DBUS_METHOD( Repeat )
+DBUS_METHOD( OpenUri )
 {
     REPLY_INIT;
-    OUT_ARGUMENTS;
 
+    char *psz_mrl;
     DBusError error;
-    dbus_bool_t b_repeat;
-
     dbus_error_init( &error );
+
     dbus_message_get_args( p_from, &error,
-            DBUS_TYPE_BOOLEAN, &b_repeat,
+            DBUS_TYPE_STRING, &psz_mrl,
             DBUS_TYPE_INVALID );
 
     if( dbus_error_is_set( &error ) )
@@ -276,96 +269,508 @@ DBUS_METHOD( Repeat )
         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     }
 
-    var_SetBool( PL, "repeat", ( b_repeat == TRUE ) );
+    playlist_Add( PL, psz_mrl, NULL,
+                  PLAYLIST_APPEND | PLAYLIST_GO,
+                  PLAYLIST_END, true, false );
 
     REPLY_SEND;
 }
 
-DBUS_METHOD( GetCurrentMetadata )
+static int
+MarshalCanGoNext( intf_thread_t *p_intf, DBusMessageIter *container )
 {
-    REPLY_INIT;
-    OUT_ARGUMENTS;
-    playlist_t *p_playlist = PL;
+    VLC_UNUSED( p_intf );
+
+    dbus_bool_t b_can_go_next = TRUE;
+
+    if( !dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
+                                         &b_can_go_next ) )
+        return VLC_ENOMEM;
+
+    return VLC_SUCCESS;
+}
+
+static int
+MarshalCanGoPrevious( intf_thread_t *p_intf, DBusMessageIter *container )
+{
+    VLC_UNUSED( p_intf );
+
+    dbus_bool_t b_can_go_previous = TRUE;
+
+    if( !dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
+                                         &b_can_go_previous ) )
+        return VLC_ENOMEM;
+
+    return VLC_SUCCESS;
+}
+
+static int
+MarshalCanPlay( intf_thread_t *p_intf, DBusMessageIter *container )
+{
+    playlist_t *p_playlist = p_intf->p_sys->p_playlist;
 
     PL_LOCK;
-    playlist_item_t* p_item =  playlist_CurrentPlayingItem( p_playlist );
-    if( p_item )
-        GetInputMeta( p_item->p_input, &args );
+    dbus_bool_t b_can_play = playlist_CurrentSize( p_playlist ) > 0;
     PL_UNLOCK;
+
+    if( !dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
+                                         &b_can_play ) )
+        return VLC_ENOMEM;
+
+    return VLC_SUCCESS;
+}
+
+static int
+MarshalCanPause( intf_thread_t *p_intf, DBusMessageIter *container )
+{
+    dbus_bool_t b_can_pause = FALSE;
+    input_thread_t *p_input = pl_CurrentInput( p_intf );
+
+    if( p_input )
+    {
+        b_can_pause = var_GetBool( p_input, "can-pause" );
+        vlc_object_release( p_input );
+    }
+
+    if( !dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
+                                         &b_can_pause ) )
+        return VLC_ENOMEM;
+
+    return VLC_SUCCESS;
+}
+
+static int
+MarshalCanControl( intf_thread_t *p_intf, DBusMessageIter *container )
+{
+    VLC_UNUSED( p_intf );
+    dbus_bool_t b_can_control = TRUE;
+
+    if( !dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
+                                         &b_can_control ) )
+        return VLC_ENOMEM;
+
+    return VLC_SUCCESS;
+}
+
+static int
+MarshalCanSeek( intf_thread_t *p_intf, DBusMessageIter *container )
+{
+    dbus_bool_t b_can_seek = FALSE;
+    input_thread_t *p_input = pl_CurrentInput( p_intf );
+
+    if( p_input )
+    {
+        b_can_seek = var_GetBool( p_input, "can-seek" );
+        vlc_object_release( p_input );
+    }
+
+    if( !dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
+                                         &b_can_seek ) )
+        return VLC_ENOMEM;
+
+    return VLC_SUCCESS;
+}
+
+static int
+MarshalShuffle( intf_thread_t *p_intf, DBusMessageIter *container )
+{
+    dbus_bool_t b_shuffle = var_GetBool( p_intf->p_sys->p_playlist, "random" );
+
+    if( !dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
+                                         &b_shuffle ))
+        return VLC_ENOMEM;
+
+    return VLC_SUCCESS;
+}
+
+DBUS_METHOD( ShuffleSet )
+{
+    REPLY_INIT;
+    dbus_bool_t b_shuffle;
+
+    if( VLC_SUCCESS != DemarshalSetPropertyValue( p_from, &b_shuffle ) )
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+    var_SetBool( PL, "random", ( b_shuffle == TRUE ) );
+
     REPLY_SEND;
 }
 
-DBUS_METHOD( GetCaps )
+static int
+MarshalPlaybackStatus( intf_thread_t *p_intf, DBusMessageIter *container )
+{
+    input_thread_t *p_input = pl_CurrentInput( p_intf );
+    const char *psz_playback_status;
+
+    if( p_input != NULL )
+    {
+        switch( var_GetInteger( p_input, "state" ) )
+        {
+            case OPENING_S:
+            case PLAYING_S:
+                psz_playback_status = PLAYBACK_STATUS_PLAYING;
+                break;
+            case PAUSE_S:
+                psz_playback_status = PLAYBACK_STATUS_PAUSED;
+                break;
+            default:
+                psz_playback_status = PLAYBACK_STATUS_STOPPED;
+        }
+
+        vlc_object_release( (vlc_object_t*) p_input );
+    }
+    else
+        psz_playback_status = PLAYBACK_STATUS_STOPPED;
+
+    if( !dbus_message_iter_append_basic( container, DBUS_TYPE_STRING,
+                                         &psz_playback_status ) )
+        return VLC_ENOMEM;
+
+    return VLC_SUCCESS;
+}
+
+static int
+MarshalRate( intf_thread_t *p_intf, DBusMessageIter *container )
+{
+    double d_rate;
+    input_thread_t *p_input = pl_CurrentInput( p_intf );
+
+    if( p_input != NULL )
+    {
+        d_rate = var_GetFloat( p_input, "rate" );
+        vlc_object_release( (vlc_object_t*) p_input );
+    }
+    else
+        d_rate = 1.0;
+
+    if( !dbus_message_iter_append_basic( container, DBUS_TYPE_DOUBLE,
+                                         &d_rate ) )
+        return VLC_ENOMEM;
+
+    return VLC_SUCCESS;
+}
+
+DBUS_METHOD( RateSet )
 {
     REPLY_INIT;
-    OUT_ARGUMENTS;
 
-    ADD_INT32( &INTF->p_sys->i_caps );
+    double d_rate;
+
+    if( VLC_SUCCESS != DemarshalSetPropertyValue( p_from, &d_rate ) )
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+    input_thread_t *p_input = pl_CurrentInput( p_this );
+    if( p_input != NULL )
+    {
+        var_SetFloat( p_input, "rate", (float) d_rate );
+        vlc_object_release( (vlc_object_t*) p_input );
+    }
+    else
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
     REPLY_SEND;
 }
 
-/*****************************************************************************
- * StatusChange: Player status change signal
- *****************************************************************************/
+static int
+MarshalMinimumRate( intf_thread_t *p_intf, DBusMessageIter *container )
+{
+    VLC_UNUSED( p_intf );
+    double d_min_rate = (double) INPUT_RATE_MIN / INPUT_RATE_DEFAULT;
 
-DBUS_SIGNAL( StatusChangeSignal )
-{ /* send the updated status info on the bus */
-    SIGNAL_INIT( DBUS_MPRIS_PLAYER_INTERFACE,
-                 DBUS_MPRIS_PLAYER_PATH,
-                 "StatusChange" );
+    if( !dbus_message_iter_append_basic( container, DBUS_TYPE_DOUBLE, &d_min_rate ) )
+        return VLC_ENOMEM;
 
-    OUT_ARGUMENTS;
+    return VLC_SUCCESS;
+}
 
-    /* we're called from a callback of input_thread_t, so it can not be
-     * destroyed before we return */
-    MarshalStatus( (intf_thread_t*) p_data, &args );
+static int
+MarshalMaximumRate( intf_thread_t *p_intf, DBusMessageIter *container )
+{
+    VLC_UNUSED( p_intf );
+    double d_max_rate = (double) INPUT_RATE_MAX / INPUT_RATE_DEFAULT;
 
-    SIGNAL_SEND;
+    if( !dbus_message_iter_append_basic( container, DBUS_TYPE_DOUBLE, &d_max_rate ) )
+        return VLC_ENOMEM;
+
+    return VLC_SUCCESS;
 }
 
-/*****************************************************************************
- * TrackChange: Playlist item change callback
- *****************************************************************************/
+static int
+MarshalLoopStatus( intf_thread_t *p_intf, DBusMessageIter *container )
+{
+    const char *psz_loop_status;
 
-DBUS_SIGNAL( TrackChangeSignal )
-{ /* emit the metadata of the new item */
-    SIGNAL_INIT( DBUS_MPRIS_PLAYER_INTERFACE,
-                 DBUS_MPRIS_PLAYER_PATH,
-                 "TrackChange" );
+    if( var_GetBool( p_intf->p_sys->p_playlist, "repeat" ) )
+        psz_loop_status = LOOP_STATUS_TRACK;
 
-    OUT_ARGUMENTS;
+    else if( var_GetBool( p_intf->p_sys->p_playlist, "loop" ) )
+        psz_loop_status = LOOP_STATUS_PLAYLIST;
 
-    input_item_t *p_item = (input_item_t*) p_data;
-    GetInputMeta ( p_item, &args );
+    else
+        psz_loop_status = LOOP_STATUS_NONE;
 
-    SIGNAL_SEND;
+    if( !dbus_message_iter_append_basic( container, DBUS_TYPE_STRING,
+                                         &psz_loop_status ) )
+        return VLC_ENOMEM;
+
+    return VLC_SUCCESS;
+}
+
+DBUS_METHOD( LoopStatusSet )
+{
+    REPLY_INIT;
+    char *psz_loop_status;
+
+    if( VLC_SUCCESS != DemarshalSetPropertyValue( p_from, &psz_loop_status ) )
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+    if( !strcmp( psz_loop_status, LOOP_STATUS_NONE ) )
+    {
+        var_SetBool( PL, "loop",   FALSE );
+        var_SetBool( PL, "repeat", FALSE );
+    }
+    else if( !strcmp( psz_loop_status, LOOP_STATUS_TRACK ) )
+    {
+        var_SetBool( PL, "loop",   FALSE );
+        var_SetBool( PL, "repeat", TRUE  );
+    }
+    else if( !strcmp( psz_loop_status, LOOP_STATUS_PLAYLIST ) )
+    {
+        var_SetBool( PL, "loop",   TRUE );
+        var_SetBool( PL, "repeat", FALSE  );
+    }
+    else
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+    REPLY_SEND;
+}
+
+static int
+MarshalMetadata( intf_thread_t *p_intf, DBusMessageIter *container )
+{
+    DBusMessageIter a;
+    input_thread_t *p_input = pl_CurrentInput( p_intf );
+    input_item_t   *p_item  = NULL;
+
+    if( p_input != NULL )
+    {
+        p_item = input_GetItem( p_input );
+
+        if( p_item )
+        {
+            int result = GetInputMeta( p_item, container );
+
+            if (result != VLC_SUCCESS)
+            {
+                vlc_object_release( (vlc_object_t*) p_input );
+                return result;
+            }
+        }
+
+        vlc_object_release( (vlc_object_t*) p_input );
+    }
+
+    if (!p_item)
+    {
+        // avoid breaking the type marshalling
+        if( !dbus_message_iter_open_container( container, DBUS_TYPE_ARRAY, "{sv}", &a ) ||
+              !dbus_message_iter_close_container( container, &a ) )
+            return VLC_ENOMEM;
+    }
+
+    return VLC_SUCCESS;
 }
 
+
 /******************************************************************************
- * CapsChange: player capabilities change signal
+ * Seeked: non-linear playback signal
  *****************************************************************************/
-DBUS_SIGNAL( CapsChangeSignal )
+DBUS_SIGNAL( SeekedSignal )
 {
     SIGNAL_INIT( DBUS_MPRIS_PLAYER_INTERFACE,
-                 DBUS_MPRIS_PLAYER_PATH,
-                 "CapsChange" );
+                 DBUS_MPRIS_OBJECT_PATH,
+                 "Seeked" );
 
     OUT_ARGUMENTS;
 
-    ADD_INT32( &((intf_thread_t*)p_data)->p_sys->i_caps );
+    dbus_int64_t i_pos = 0;
+    intf_thread_t *p_intf = (intf_thread_t*) p_data;
+    input_thread_t *p_input = pl_CurrentInput( p_intf );
+
+    if( p_input )
+    {
+        i_pos = var_GetTime( p_input, "time" );
+        vlc_object_release( p_input );
+    }
+
+    ADD_INT64( &i_pos );
     SIGNAL_SEND;
 }
 
-DBUS_METHOD( handle_introspect_player )
+#define PROPERTY_MAPPING_BEGIN if( 0 ) {}
+#define PROPERTY_GET_FUNC( prop, signature ) \
+    else if( !strcmp( psz_property_name,  #prop ) ) { \
+        if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, signature, &v ) ) \
+            return DBUS_HANDLER_RESULT_NEED_MEMORY; \
+        if( VLC_SUCCESS != Marshal##prop( p_this, &v ) ) { \
+            dbus_message_iter_abandon_container( &args, &v ); \
+            return DBUS_HANDLER_RESULT_NEED_MEMORY; \
+        } \
+        if( !dbus_message_iter_close_container( &args, &v ) ) \
+            return DBUS_HANDLER_RESULT_NEED_MEMORY; \
+    }
+#define PROPERTY_SET_FUNC( prop ) \
+    else if( !strcmp( psz_property_name,  #prop ) ) { \
+        return prop##Set( p_conn, p_from, p_this ); \
+    }
+#define PROPERTY_MAPPING_END else { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; }
+
+DBUS_METHOD( GetProperty )
 {
-    VLC_UNUSED(p_this);
+    DBusError error;
+
+    char *psz_interface_name = NULL;
+    char *psz_property_name  = NULL;
+
+    dbus_error_init( &error );
+    dbus_message_get_args( p_from, &error,
+            DBUS_TYPE_STRING, &psz_interface_name,
+            DBUS_TYPE_STRING, &psz_property_name,
+            DBUS_TYPE_INVALID );
+
+    if( dbus_error_is_set( &error ) )
+    {
+        msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
+                                         error.message );
+        dbus_error_free( &error );
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+
+    msg_Dbg( (vlc_object_t*) p_this, "Getting property %s",
+                                     psz_property_name );
+
+    if( strcmp( psz_interface_name, DBUS_MPRIS_PLAYER_INTERFACE ) ) {
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+
     REPLY_INIT;
     OUT_ARGUMENTS;
-    ADD_STRING( &psz_player_introspection_xml );
+    DBusMessageIter v;
+
+    PROPERTY_MAPPING_BEGIN
+    PROPERTY_GET_FUNC( Metadata,       "a{sv}" )
+    PROPERTY_GET_FUNC( Position,       "x" )
+    PROPERTY_GET_FUNC( PlaybackStatus, "s" )
+    PROPERTY_GET_FUNC( LoopStatus,     "s" )
+    PROPERTY_GET_FUNC( Shuffle,        "b" )
+    PROPERTY_GET_FUNC( Volume,         "d" )
+    PROPERTY_GET_FUNC( Rate,           "d" )
+    PROPERTY_GET_FUNC( MinimumRate,    "d" )
+    PROPERTY_GET_FUNC( MaximumRate,    "d" )
+    PROPERTY_GET_FUNC( CanControl,     "b" )
+    PROPERTY_GET_FUNC( CanPlay,        "b" )
+    PROPERTY_GET_FUNC( CanGoNext,      "b" )
+    PROPERTY_GET_FUNC( CanGoPrevious,  "b" )
+    PROPERTY_GET_FUNC( CanPause,       "b" )
+    PROPERTY_GET_FUNC( CanSeek,        "b" )
+    PROPERTY_MAPPING_END
+
     REPLY_SEND;
 }
 
+DBUS_METHOD( SetProperty )
+{
+    DBusError error;
+
+    char *psz_interface_name = NULL;
+    char *psz_property_name  = NULL;
+
+    dbus_error_init( &error );
+    dbus_message_get_args( p_from, &error,
+            DBUS_TYPE_STRING, &psz_interface_name,
+            DBUS_TYPE_STRING, &psz_property_name,
+            DBUS_TYPE_INVALID );
+
+    if( dbus_error_is_set( &error ) )
+    {
+        msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
+                                         error.message );
+        dbus_error_free( &error );
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+
+    PROPERTY_MAPPING_BEGIN
+    PROPERTY_SET_FUNC( LoopStatus )
+    PROPERTY_SET_FUNC( Shuffle )
+    PROPERTY_SET_FUNC( Volume )
+    PROPERTY_SET_FUNC( Rate )
+    PROPERTY_MAPPING_END
+}
+
+#undef PROPERTY_MAPPING_BEGIN
+#undef PROPERTY_GET_FUNC
+#undef PROPERTY_SET_FUNC
+#undef PROPERTY_MAPPING_END
+
+#define ADD_PROPERTY( prop, signature ) \
+    if( VLC_SUCCESS != AddProperty( (intf_thread_t*) p_this, \
+                &dict, #prop, signature, Marshal##prop ) ) { \
+        dbus_message_iter_abandon_container( &args, &dict ); \
+        return VLC_ENOMEM; \
+    }
+
+DBUS_METHOD( GetAllProperties )
+{
+    REPLY_INIT;
+    OUT_ARGUMENTS;
+
+    DBusError error;
+    DBusMessageIter dict;
+
+    char *const psz_interface_name = NULL;
+
+    dbus_error_init( &error );
+    dbus_message_get_args( p_from, &error,
+            DBUS_TYPE_STRING, &psz_interface_name,
+            DBUS_TYPE_INVALID );
+
+    if( dbus_error_is_set( &error ) )
+    {
+        msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
+                                         error.message );
+        dbus_error_free( &error );
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+
+    msg_Dbg( (vlc_object_t*) p_this, "Getting All properties" );
+
+    if( !dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "{sv}", &dict ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    ADD_PROPERTY ( Metadata,       "a{sv}" );
+    ADD_PROPERTY ( Position,       "x"     );
+    ADD_PROPERTY ( PlaybackStatus, "s"     );
+    ADD_PROPERTY ( LoopStatus,     "s"     );
+    ADD_PROPERTY ( Shuffle,        "b"     );
+    ADD_PROPERTY ( Volume,         "d"     );
+    ADD_PROPERTY ( Rate,           "d"     );
+    ADD_PROPERTY ( MinimumRate,    "d"     );
+    ADD_PROPERTY ( MaximumRate,    "d"     );
+    ADD_PROPERTY ( CanControl,     "b"     );
+    ADD_PROPERTY ( CanPlay,        "b"     );
+    ADD_PROPERTY ( CanGoNext,      "b"     );
+    ADD_PROPERTY ( CanGoPrevious,  "b"     );
+    ADD_PROPERTY ( CanPause,       "b"     );
+    ADD_PROPERTY ( CanSeek,        "b"     );
+
+    if( !dbus_message_iter_close_container( &args, &dict ))
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    REPLY_SEND;
+}
+
+#undef ADD_PROPERTY
+
 #define METHOD_FUNC( interface, method, function ) \
     else if( dbus_message_is_method_call( p_from, interface, method ) )\
         return function( p_conn, p_from, p_this )
@@ -373,25 +778,22 @@ DBUS_METHOD( handle_introspect_player )
 DBusHandlerResult
 handle_player ( DBusConnection *p_conn, DBusMessage *p_from, void *p_this )
 {
-    if( dbus_message_is_method_call( p_from,
-                DBUS_INTERFACE_INTROSPECTABLE, "Introspect" ) )
-        return handle_introspect_player( p_conn, p_from, p_this );
+    if(0);
+    METHOD_FUNC( DBUS_INTERFACE_PROPERTIES,   "Get",        GetProperty );
+    METHOD_FUNC( DBUS_INTERFACE_PROPERTIES,   "Set",        SetProperty );
+    METHOD_FUNC( DBUS_INTERFACE_PROPERTIES,   "GetAll",     GetAllProperties );
 
     /* here D-Bus method names are associated to an handler */
 
-    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Prev",        Prev );
-    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Next",        Next );
-    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Stop",        Stop );
-    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Play",        Play );
-    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Pause",       Pause );
-    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Repeat",      Repeat );
-    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "VolumeSet",   VolumeSet );
-    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "VolumeGet",   VolumeGet );
-    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "PositionSet", PositionSet );
-    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "PositionGet", PositionGet );
-    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "GetStatus",   GetStatus );
-    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "GetMetadata", GetCurrentMetadata );
-    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "GetCaps",     GetCaps );
+    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Previous",     Prev );
+    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Next",         Next );
+    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Stop",         Stop );
+    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Seek",         Seek );
+    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Play",         Play );
+    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Pause",        Pause );
+    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "PlayPause",    PlayPause );
+    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "OpenUri",      OpenUri );
+    METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "SetPosition",  SetPosition );
 
     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
@@ -399,72 +801,106 @@ handle_player ( DBusConnection *p_conn, DBusMessage *p_from, void *p_this )
 #undef METHOD_FUNC
 
 /*****************************************************************************
- * StatusChangeEmit: Emits the StatusChange signal
+ * SeekedEmit: Emits the Seeked signal
  *****************************************************************************/
-int StatusChangeEmit( intf_thread_t * p_intf )
+int SeekedEmit( intf_thread_t * p_intf )
 {
     if( p_intf->p_sys->b_dead )
         return VLC_SUCCESS;
 
-    UpdateCaps( p_intf );
-    StatusChangeSignal( p_intf->p_sys->p_conn, p_intf );
+    SeekedSignal( p_intf->p_sys->p_conn, p_intf );
     return VLC_SUCCESS;
 }
 
-/*****************************************************************************
- * CapsChangeEmit: Emits the CapsChange signal
- *****************************************************************************/
-int CapsChangeEmit( intf_thread_t * p_intf )
+#define PROPERTY_MAPPING_BEGIN if( 0 ) {}
+#define PROPERTY_ENTRY( prop, signature ) \
+    else if( !strcmp( ppsz_properties[i], #prop ) ) \
+    { \
+        if( VLC_SUCCESS != AddProperty( (intf_thread_t*) p_intf, \
+                    &changed_properties, #prop, signature, Marshal##prop ) ) \
+            return DBUS_HANDLER_RESULT_NEED_MEMORY; \
+    }
+#define PROPERTY_MAPPING_END else { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; }
+
+/**
+ * PropertiesChangedSignal() synthetizes and sends the
+ * org.freedesktop.DBus.Properties.PropertiesChanged signal
+ */
+static DBusHandlerResult
+PropertiesChangedSignal( intf_thread_t    *p_intf,
+                         vlc_dictionary_t *p_changed_properties )
 {
-    if( p_intf->p_sys->b_dead )
-        return VLC_SUCCESS;
+    DBusConnection  *p_conn = p_intf->p_sys->p_conn;
+    DBusMessageIter changed_properties, invalidated_properties;
+    const char *psz_interface_name = DBUS_MPRIS_PLAYER_INTERFACE;
+    char **ppsz_properties = NULL;
+    int i_properties = 0;
 
-    CapsChangeSignal( p_intf->p_sys->p_conn, p_intf );
-    return VLC_SUCCESS;
-}
+    SIGNAL_INIT( DBUS_INTERFACE_PROPERTIES,
+                 DBUS_MPRIS_OBJECT_PATH,
+                 "PropertiesChanged" );
 
-/*****************************************************************************
- * TrackChangeEmit: Emits the TrackChange signal
- *****************************************************************************/
-int TrackChangeEmit( intf_thread_t * p_intf, input_item_t* p_item )
-{
-    if( p_intf->p_sys->b_dead )
-        return VLC_SUCCESS;
+    OUT_ARGUMENTS;
+    ADD_STRING( &psz_interface_name );
 
-    UpdateCaps( p_intf );
-    TrackChangeSignal( p_intf->p_sys->p_conn, p_item );
-    return VLC_SUCCESS;
-}
+    if( !dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "{sv}",
+                                           &changed_properties ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
-/*****************************************************************************
- * MarshalStatus: Fill a DBusMessage with the current player status
- *****************************************************************************/
+    i_properties = vlc_dictionary_keys_count( p_changed_properties );
+    ppsz_properties = vlc_dictionary_all_keys( p_changed_properties );
 
-static int MarshalStatus( intf_thread_t* p_intf, DBusMessageIter* args )
-{ /* This is NOT the right way to do that, it would be better to sore
-     the status information in p_sys and update it on change, thus
-     avoiding a long lock */
+    if( unlikely(!ppsz_properties) )
+    {
+        dbus_message_iter_abandon_container( &args, &changed_properties );
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+    }
 
-    DBusMessageIter status;
-    dbus_int32_t i_state, i_random, i_repeat, i_loop;
-    playlist_t* p_playlist = p_intf->p_sys->p_playlist;
+    for( int i = 0; i < i_properties; i++ )
+    {
+        PROPERTY_MAPPING_BEGIN
+        PROPERTY_ENTRY( Metadata,       "a{sv}" )
+        PROPERTY_ENTRY( PlaybackStatus, "s"     )
+        PROPERTY_ENTRY( LoopStatus,     "s"     )
+        PROPERTY_ENTRY( Rate,           "d"     )
+        PROPERTY_ENTRY( Shuffle,        "b"     )
+        PROPERTY_ENTRY( Volume,         "d"     )
+        PROPERTY_ENTRY( CanSeek,        "b"     )
+        PROPERTY_ENTRY( CanPlay,        "b"     )
+        PROPERTY_ENTRY( CanPause,       "b"     )
+        PROPERTY_MAPPING_END
+
+        free( ppsz_properties[i] );
+    }
 
-    vlc_mutex_lock( &p_intf->p_sys->lock );
-    i_state = p_intf->p_sys->i_playing_state;
-    vlc_mutex_unlock( &p_intf->p_sys->lock );
+    free( ppsz_properties );
 
-    i_random = var_CreateGetBool( p_playlist, "random" );
+    if( !dbus_message_iter_close_container( &args, &changed_properties ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
-    i_repeat = var_CreateGetBool( p_playlist, "repeat" );
+    if( !dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "s",
+                                           &invalidated_properties ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
-    i_loop = var_CreateGetBool( p_playlist, "loop" );
+    if( !dbus_message_iter_close_container( &args, &invalidated_properties ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
-    dbus_message_iter_open_container( args, DBUS_TYPE_STRUCT, NULL, &status );
-    dbus_message_iter_append_basic( &status, DBUS_TYPE_INT32, &i_state );
-    dbus_message_iter_append_basic( &status, DBUS_TYPE_INT32, &i_random );
-    dbus_message_iter_append_basic( &status, DBUS_TYPE_INT32, &i_repeat );
-    dbus_message_iter_append_basic( &status, DBUS_TYPE_INT32, &i_loop );
-    dbus_message_iter_close_container( args, &status );
+    SIGNAL_SEND;
+}
+
+#undef PROPERTY_MAPPING_BEGIN
+#undef PROPERTY_ADD
+#undef PROPERTY_MAPPING_END
+
+/*****************************************************************************
+ * PropertiesChangedEmit: Emits the Seeked signal
+ *****************************************************************************/
+int PlayerPropertiesChangedEmit( intf_thread_t    * p_intf,
+                                 vlc_dictionary_t * p_changed_properties )
+{
+    if( p_intf->p_sys->b_dead )
+        return VLC_SUCCESS;
 
+    PropertiesChangedSignal( p_intf, p_changed_properties );
     return VLC_SUCCESS;
 }