dbus: Implement the MPRIS v2.1, as published on http://www.mpris.org
authorMirsal Ennaime <mirsal.ennaime@gmail.com>
Wed, 4 Aug 2010 13:23:34 +0000 (15:23 +0200)
committerMirsal Ennaime <mirsal@mirsal.fr>
Mon, 16 May 2011 20:58:00 +0000 (22:58 +0200)
WARNING: These changes are backwards incompatible.
Please refer to the mpris project for documentation.

modules/control/dbus/dbus.c
modules/control/dbus/dbus.h
modules/control/dbus/dbus_common.h
modules/control/dbus/dbus_introspect.h [new file with mode: 0644]
modules/control/dbus/dbus_player.c
modules/control/dbus/dbus_player.h
modules/control/dbus/dbus_root.c
modules/control/dbus/dbus_root.h
modules/control/dbus/dbus_tracklist.c
modules/control/dbus/dbus_tracklist.h

index f0e6ee0..2cbb317 100644 (file)
@@ -50,6 +50,7 @@
 #include "dbus_root.h"
 #include "dbus_player.h"
 #include "dbus_tracklist.h"
+#include "dbus_introspect.h"
 
 #include <vlc_common.h>
 #include <vlc_plugin.h>
@@ -58,6 +59,7 @@
 #include <vlc_meta.h>
 #include <vlc_mtime.h>
 #include <vlc_fs.h>
+#include <vlc_aout.h>
 
 #include <assert.h>
 #include <string.h>
@@ -74,6 +76,7 @@ typedef struct
 {
     int signal;
     int i_node;
+    int i_item;
 } callback_info_t;
 
 typedef struct
@@ -165,10 +168,10 @@ static int Open( vlc_object_t *p_this )
     if( !p_sys || !dbus_threads_init_default())
         return VLC_ENOMEM;
 
-    p_sys->b_meta_read = false;
-    p_sys->i_caps = CAPS_NONE;
-    p_sys->b_dead = false;
-    p_sys->p_input = NULL;
+    p_sys->b_meta_read     = false;
+    p_sys->b_dead          = false;
+    p_sys->p_input         = NULL;
+    p_sys->i_player_caps   = PLAYER_CAPS_NONE;
     p_sys->i_playing_state = -1;
 
     if( vlc_pipe( p_sys->p_pipe_fds ) )
@@ -225,13 +228,9 @@ static int Open( vlc_object_t *p_this )
     msg_Info( p_intf, "listening on dbus as: %s", psz_service_name );
     free( psz_service_name );
 
-    /* we register the objects */
-    dbus_connection_register_object_path( p_conn, DBUS_MPRIS_ROOT_PATH,
-            &dbus_mpris_root_vtable, p_this );
-    dbus_connection_register_object_path( p_conn, DBUS_MPRIS_PLAYER_PATH,
-            &dbus_mpris_player_vtable, p_this );
-    dbus_connection_register_object_path( p_conn, DBUS_MPRIS_TRACKLIST_PATH,
-            &dbus_mpris_tracklist_vtable, p_this );
+    /* Register the entry point object path */
+    dbus_connection_register_object_path( p_conn, DBUS_MPRIS_OBJECT_PATH,
+            &dbus_mpris_vtable, p_this );
 
     dbus_connection_flush( p_conn );
 
@@ -248,6 +247,8 @@ static int Open( vlc_object_t *p_this )
 
     var_AddCallback( p_playlist, "item-current", AllCallback, p_intf );
     var_AddCallback( p_playlist, "intf-change", AllCallback, p_intf );
+    var_AddCallback( p_playlist, "volume-change", AllCallback, p_intf );
+    var_AddCallback( p_playlist, "volume-muted", AllCallback, p_intf );
     var_AddCallback( p_playlist, "playlist-item-append", AllCallback, p_intf );
     var_AddCallback( p_playlist, "playlist-item-deleted", AllCallback, p_intf );
     var_AddCallback( p_playlist, "random", AllCallback, p_intf );
@@ -286,8 +287,6 @@ static int Open( vlc_object_t *p_this )
                                               wakeup_main_loop,
                                               p_intf, NULL); */
 
-    UpdateCaps( p_intf );
-
     return VLC_SUCCESS;
 }
 
@@ -303,6 +302,8 @@ static void Close   ( vlc_object_t *p_this )
 
     var_DelCallback( p_playlist, "item-current", AllCallback, p_intf );
     var_DelCallback( p_playlist, "intf-change", AllCallback, p_intf );
+    var_DelCallback( p_playlist, "volume-change", AllCallback, p_intf );
+    var_DelCallback( p_playlist, "volume-muted", AllCallback, p_intf );
     var_DelCallback( p_playlist, "playlist-item-append", AllCallback, p_intf );
     var_DelCallback( p_playlist, "playlist-item-deleted", AllCallback, p_intf );
     var_DelCallback( p_playlist, "random", AllCallback, p_intf );
@@ -312,6 +313,8 @@ static void Close   ( vlc_object_t *p_this )
     if( p_sys->p_input )
     {
         var_DelCallback( p_sys->p_input, "intf-event", AllCallback, p_intf );
+        var_DelCallback( p_sys->p_input, "can-pause", AllCallback, p_intf );
+        var_DelCallback( p_sys->p_input, "can-seek", AllCallback, p_intf );
         vlc_object_release( p_sys->p_input );
     }
 
@@ -549,35 +552,95 @@ static int UpdateTimeouts( intf_thread_t *p_intf, mtime_t i_loop_interval )
 static void ProcessEvents( intf_thread_t *p_intf,
                            callback_info_t **p_events, int i_events )
 {
+    playlist_t *p_playlist = p_intf->p_sys->p_playlist;
+    bool        b_can_play = p_intf->p_sys->b_can_play;
+
+    vlc_dictionary_t player_properties;
+    vlc_dictionary_init( &player_properties, 0 );
+
     for( int i = 0; i < i_events; i++ )
     {
         switch( p_events[i]->signal )
         {
         case SIGNAL_ITEM_CURRENT:
             TrackChange( p_intf );
+            vlc_dictionary_insert( &player_properties, "Metadata", NULL );
             break;
         case SIGNAL_INTF_CHANGE:
         case SIGNAL_PLAYLIST_ITEM_APPEND:
         case SIGNAL_PLAYLIST_ITEM_DELETED:
-            TrackListChangeEmit( p_intf,
-                                 p_events[i]->signal,
-                                 p_events[i]->i_node );
+            PL_LOCK;
+            b_can_play = playlist_CurrentSize( p_playlist ) > 0;
+            PL_UNLOCK;
+            if( b_can_play != p_intf->p_sys->b_can_play )
+            {
+                p_intf->p_sys->b_can_play = b_can_play;
+                vlc_dictionary_insert( &player_properties, "CanPlay", NULL );
+            }
+            break;
+        case SIGNAL_VOLUME_MUTED:
+        case SIGNAL_VOLUME_CHANGE:
+            vlc_dictionary_insert( &player_properties, "Volume", NULL );
             break;
         case SIGNAL_RANDOM:
+            vlc_dictionary_insert( &player_properties, "Shuffle", NULL );
+            break;
         case SIGNAL_REPEAT:
         case SIGNAL_LOOP:
-            StatusChangeEmit( p_intf );
+            vlc_dictionary_insert( &player_properties, "LoopStatus", NULL );
             break;
         case SIGNAL_STATE:
-            StateChange( p_intf );
+            vlc_dictionary_insert( &player_properties, "PlaybackStatus", NULL );
+            break;
+        case SIGNAL_RATE:
+            vlc_dictionary_insert( &player_properties, "Rate", NULL );
             break;
         case SIGNAL_INPUT_METADATA:
+        {
+            input_thread_t *p_input = playlist_CurrentInput( p_playlist );
+            input_item_t   *p_item;
+            if( p_input )
+            {
+                p_item = input_GetItem( p_input );
+                vlc_object_release( p_input );
+
+                if( p_item )
+                    vlc_dictionary_insert( &player_properties,
+                                           "Metadata", NULL );
+            }
+            break;
+        }
+        case SIGNAL_CAN_SEEK:
+            vlc_dictionary_insert( &player_properties, "CanSeek", NULL );
+            break;
+        case SIGNAL_CAN_PAUSE:
+            vlc_dictionary_insert( &player_properties, "CanPause", NULL );
+            break;
+        case SIGNAL_SEEK:
+        {
+            input_thread_t *p_input;
+            input_item_t *p_item;
+            p_input = playlist_CurrentInput( p_intf->p_sys->p_playlist );
+            if( p_input )
+            {
+                p_item = input_GetItem( p_input );
+                vlc_object_release( p_input );
+
+                if( p_item && ( p_item->i_id == p_events[i]->i_item ) )
+                    SeekedEmit( p_intf );
+            }
             break;
+        }
         default:
             assert(0);
         }
         free( p_events[i] );
     }
+
+    if( vlc_dictionary_keys_count( &player_properties ) )
+        PlayerPropertiesChangedEmit( p_intf, &player_properties );
+
+    vlc_dictionary_clear( &player_properties, NULL, NULL );
 }
 
 /**
@@ -708,6 +771,57 @@ static void DispatchDBusMessages( intf_thread_t *p_intf )
     }
 }
 
+/**
+ * MPRISEntryPoint() routes incoming messages to their respective interface
+ * implementation.
+ *
+ * This function is called during dbus_connection_dispatch()
+ */
+static DBusHandlerResult
+MPRISEntryPoint ( DBusConnection *p_conn, DBusMessage *p_from, void *p_this )
+{
+    char *psz_target_interface;
+    const char *psz_interface = dbus_message_get_interface( p_from );
+    const char *psz_method    = dbus_message_get_member( p_from );
+
+    DBusError error;
+
+    if( strcmp( psz_interface, DBUS_INTERFACE_PROPERTIES ) )
+        psz_target_interface = psz_interface;
+
+    else
+    {
+        dbus_error_init( &error );
+        dbus_message_get_args( p_from, &error,
+                               DBUS_TYPE_STRING, &psz_target_interface,
+                               DBUS_TYPE_INVALID );
+
+        if( dbus_error_is_set( &error ) )
+        {
+            msg_Err( (vlc_object_t*) p_this, "D-Bus error on %s.%s: %s",
+                                             psz_interface, psz_method,
+                                             error.message );
+            dbus_error_free( &error );
+            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+        }
+    }
+
+    msg_Dbg( (vlc_object_t*) p_this, "Routing %s.%s D-Bus method call to %s",
+                                     psz_interface, psz_method,
+                                     psz_target_interface );
+
+    if( !strcmp( psz_target_interface, DBUS_INTERFACE_INTROSPECTABLE ) )
+        return handle_introspect( p_conn, p_from, p_this );
+
+    if( !strcmp( psz_target_interface, DBUS_MPRIS_ROOT_INTERFACE ) )
+        return handle_root( p_conn, p_from, p_this );
+
+    if( !strcmp( psz_target_interface, DBUS_MPRIS_PLAYER_INTERFACE ) )
+        return handle_player( p_conn, p_from, p_this );
+
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
 /*****************************************************************************
  * Run: main loop
  *****************************************************************************/
@@ -833,45 +947,6 @@ static void   wakeup_main_loop( void *p_data )
     }
 }
 
-/*****************************************************************************
- * UpdateCaps: update p_sys->i_caps
- * This function have to be called with the playlist unlocked
- ****************************************************************************/
-int UpdateCaps( intf_thread_t* p_intf )
-{
-    intf_sys_t* p_sys = p_intf->p_sys;
-    dbus_int32_t i_caps = CAPS_CAN_HAS_TRACKLIST;
-    playlist_t* p_playlist = p_sys->p_playlist;
-
-    PL_LOCK;
-    if( p_playlist->current.i_size > 0 )
-        i_caps |= CAPS_CAN_PLAY | CAPS_CAN_GO_PREV | CAPS_CAN_GO_NEXT;
-    PL_UNLOCK;
-
-    input_thread_t* p_input = playlist_CurrentInput( p_playlist );
-    if( p_input )
-    {
-        /* XXX: if UpdateCaps() is called too early, these are
-         * unconditionnaly true */
-        if( var_GetBool( p_input, "can-pause" ) )
-            i_caps |= CAPS_CAN_PAUSE;
-        if( var_GetBool( p_input, "can-seek" ) )
-            i_caps |= CAPS_CAN_SEEK;
-        vlc_object_release( p_input );
-    }
-
-    if( p_sys->b_meta_read )
-        i_caps |= CAPS_CAN_PROVIDE_METADATA;
-
-    if( i_caps != p_intf->p_sys->i_caps )
-    {
-        p_sys->i_caps = i_caps;
-        CapsChangeEmit( p_intf );
-    }
-
-    return VLC_SUCCESS;
-}
-
 /* InputIntfEventCallback() fills a callback_info_t data structure in response
  * to an "intf-event" input event.
  *
@@ -892,6 +967,8 @@ static int InputIntfEventCallback( intf_thread_t   *p_intf,
 {
     dbus_int32_t i_state = PLAYBACK_STATE_INVALID;
     assert(!p_info->signal);
+    mtime_t i_now = mdate(), i_pos, i_projected_pos, i_interval;
+    float f_current_rate, f_computed_rate;
 
     switch( i_event )
     {
@@ -900,17 +977,48 @@ static int InputIntfEventCallback( intf_thread_t   *p_intf,
             i_state = PLAYBACK_STATE_STOPPED;
             break;
         case INPUT_EVENT_STATE:
-            i_state = ( var_GetInteger( p_input, "state" ) == PAUSE_S ) ?
-                PLAYBACK_STATE_PAUSED : PLAYBACK_STATE_PLAYING;
+            switch( var_GetInteger( p_input, "state" ) )
+            {
+                case OPENING_S:
+                case PLAYING_S:
+                    i_state = PLAYBACK_STATE_PLAYING;
+                    break;
+                case PAUSE_S:
+                    i_state = PLAYBACK_STATE_PAUSED;
+                    break;
+                default:
+                    i_state = PLAYBACK_STATE_STOPPED;
+            }
             break;
         case INPUT_EVENT_ITEM_META:
             p_info->signal = SIGNAL_INPUT_METADATA;
             return VLC_SUCCESS;
+        case INPUT_EVENT_RATE:
+            p_info->signal = SIGNAL_RATE;
+            return VLC_SUCCESS;
+        case INPUT_EVENT_POSITION:
+            /* Detect seeks
+             * XXX: This is way more convoluted than it should be... */
+            if( !p_intf->p_sys->i_last_input_pos_event ||
+                !( var_GetInteger( p_input, "state" ) == PLAYING_S ) )
+                break;
+            i_pos = var_GetTime( p_input, "time" );
+            f_current_rate = var_GetFloat( p_input, "rate" );
+            i_interval = ( i_now - p_intf->p_sys->i_last_input_pos_event );
+            i_projected_pos = p_intf->p_sys->i_last_input_pos + ( i_interval * f_current_rate );
+            p_intf->p_sys->i_last_input_pos_event = i_now;
+            p_intf->p_sys->i_last_input_pos = i_pos;
+            if( ABS( i_pos - i_projected_pos ) < SEEK_THRESHOLD )
+                break;
+            p_info->signal = SIGNAL_SEEK;
+            p_info->i_item = input_GetItem( p_input )->i_id;
+            break;
         default:
             return VLC_EGENERIC;
     }
 
-    if( i_state != p_intf->p_sys->i_playing_state )
+    if( i_state != PLAYBACK_STATE_INVALID &&
+        i_state != p_intf->p_sys->i_playing_state )
     {
         p_intf->p_sys->i_playing_state = i_state;
         p_info->signal = SIGNAL_STATE;
@@ -938,6 +1046,12 @@ static int AllCallback( vlc_object_t *p_this, const char *psz_var,
     if( !strcmp( "item-current", psz_var ) )
         info->signal = SIGNAL_ITEM_CURRENT;
 
+    else if( !strcmp( "volume-change", psz_var ) )
+        info->signal = SIGNAL_VOLUME_CHANGE;
+
+    else if( !strcmp( "volume-muted", psz_var ) )
+        info->signal = SIGNAL_VOLUME_MUTED;
+
     else if( !strcmp( "intf-change", psz_var ) )
         info->signal = SIGNAL_INTF_CHANGE;
 
@@ -963,7 +1077,6 @@ static int AllCallback( vlc_object_t *p_this, const char *psz_var,
     {
         int i_res;
         i_res = InputIntfEventCallback( p_intf, p_this, newval.i_int, info );
-
         if( VLC_SUCCESS != i_res )
         {
             vlc_mutex_unlock( &p_intf->p_sys->lock );
@@ -973,6 +1086,12 @@ static int AllCallback( vlc_object_t *p_this, const char *psz_var,
         }
     }
 
+    else if( !strcmp( "can-seek", psz_var ) )
+        info->signal = SIGNAL_CAN_SEEK;
+
+    else if( !strcmp( "can-pause", psz_var ) )
+        info->signal = SIGNAL_CAN_PAUSE;
+
     else
         assert(0);
 
@@ -1002,8 +1121,6 @@ static int StateChange( intf_thread_t *p_intf )
     if( p_intf->p_sys->b_dead )
         return VLC_SUCCESS;
 
-    UpdateCaps( p_intf );
-
     if( !p_sys->b_meta_read && p_sys->i_playing_state == 0)
     {
         p_input = playlist_CurrentInput( p_playlist );
@@ -1013,13 +1130,13 @@ static int StateChange( intf_thread_t *p_intf )
             if( p_item )
             {
                 p_sys->b_meta_read = true;
-                TrackChangeEmit( p_intf, p_item );
+                TrackChangedEmit( p_intf, p_item );
             }
             vlc_object_release( p_input );
         }
     }
 
-    StatusChangeEmit( p_intf );
+    PlayerStatusChangedEmit( p_intf );
 
     return VLC_SUCCESS;
 }
@@ -1040,6 +1157,8 @@ static int TrackChange( intf_thread_t *p_intf )
     if( p_sys->p_input )
     {
         var_DelCallback( p_sys->p_input, "intf-event", AllCallback, p_intf );
+        var_DelCallback( p_sys->p_input, "can-pause", AllCallback, p_intf );
+        var_DelCallback( p_sys->p_input, "can-seek", AllCallback, p_intf );
         vlc_object_release( p_sys->p_input );
         p_sys->p_input = NULL;
     }
@@ -1060,17 +1179,45 @@ static int TrackChange( intf_thread_t *p_intf )
     }
 
     if( input_item_IsPreparsed( p_item ) )
-    {
         p_sys->b_meta_read = true;
-        TrackChangeEmit( p_intf, p_item );
-    }
 
     p_sys->p_input = p_input;
     var_AddCallback( p_input, "intf-event", AllCallback, p_intf );
+    var_AddCallback( p_input, "can-pause", AllCallback, p_intf );
+    var_AddCallback( p_input, "can-seek", AllCallback, p_intf );
 
     return VLC_SUCCESS;
 }
 
+/**
+ * DemarshalSetPropertyValue() extracts the new property value from a
+ * org.freedesktop.DBus.Properties.Set method call message.
+ *
+ * @return int VLC_SUCCESS on success
+ * @param DBusMessage *p_msg a org.freedesktop.DBus.Properties.Set method call
+ * @param void *p_arg placeholder for the demarshalled value
+ */
+int DemarshalSetPropertyValue( DBusMessage *p_msg, void *p_arg )
+{
+    int  i_type;
+    bool b_valid_input = FALSE;
+    DBusMessageIter in_args, variant;
+    dbus_message_iter_init( p_msg, &in_args );
+
+    do
+    {
+        i_type = dbus_message_iter_get_arg_type( &in_args );
+        if( DBUS_TYPE_VARIANT == i_type )
+        {
+            dbus_message_iter_recurse( &in_args, &variant );
+            dbus_message_iter_get_basic( &variant, p_arg );
+            b_valid_input = TRUE;
+        }
+    } while( dbus_message_iter_next( &in_args ) );
+
+    return b_valid_input ? VLC_SUCCESS : VLC_EGENERIC;
+}
+
 /*****************************************************************************
  * GetInputMeta: Fill a DBusMessage with the given input item metadata
  *****************************************************************************/
@@ -1098,7 +1245,7 @@ static int TrackChange( intf_thread_t *p_intf )
     }
 
 int GetInputMeta( input_item_t* p_input,
-                        DBusMessageIter *args )
+                  DBusMessageIter *args )
 {
     DBusMessageIter dict, dict_entry, variant;
     /** The duration of the track can be expressed in second, milli-seconds and
@@ -1106,42 +1253,46 @@ int GetInputMeta( input_item_t* p_input,
     dbus_int64_t i_mtime = input_item_GetDuration( p_input );
     dbus_uint32_t i_time = i_mtime / 1000000;
     dbus_int64_t i_length = i_mtime / 1000;
+    char *psz_trackid;
+
+    if( -1 == asprintf( &psz_trackid, MPRIS_TRACKID_FORMAT, p_input->i_id ) )
+        return VLC_ENOMEM;
 
     const char* ppsz_meta_items[] =
     {
-    /* Official MPRIS metas */
-    "location", "title", "artist", "album", "tracknumber", "time", "mtime",
-    "genre", "rating", "date", "arturl",
-    "audio-bitrate", "audio-samplerate", "video-bitrate",
-    /* VLC specifics metas */
-    "audio-codec", "copyright", "description", "encodedby", "language", "length",
-    "nowplaying", "publisher", "setting", "status", "trackid", "url",
-    "video-codec"
+    "mpris:trackid", "xesam:url", "xesam:title", "xesam:artist", "xesam:album",
+    "xesam:tracknumber", "vlc:time", "mpris:length", "xesam:genre",
+    "xesam:userRating", "xesam:contentCreated", "mpris:artUrl", "mb:trackId",
+    "vlc:audio-bitrate", "vlc:audio-samplerate", "vlc:video-bitrate",
+    "vlc:audio-codec", "vlc:copyright", "xesam:comment", "vlc:encodedby",
+    "language", "vlc:length", "vlc:nowplaying", "vlc:publisher", "vlc:setting",
+    "status", "vlc:url", "vlc:video-codec"
     };
 
     dbus_message_iter_open_container( args, DBUS_TYPE_ARRAY, "{sv}", &dict );
 
-    ADD_VLC_META_STRING( 0,  URI );
-    ADD_VLC_META_STRING( 1,  Title );
-    ADD_VLC_META_STRING( 2,  Artist );
-    ADD_VLC_META_STRING( 3,  Album );
-    ADD_VLC_META_STRING( 4,  TrackNum );
-    ADD_META( 5, DBUS_TYPE_UINT32, i_time );
-    ADD_META( 6, DBUS_TYPE_UINT32, i_mtime );
-    ADD_VLC_META_STRING( 7,  Genre );
-    ADD_VLC_META_STRING( 8,  Rating );
-    ADD_VLC_META_STRING( 9,  Date );
-    ADD_VLC_META_STRING( 10, ArtURL );
-
-    ADD_VLC_META_STRING( 15, Copyright );
-    ADD_VLC_META_STRING( 16, Description );
-    ADD_VLC_META_STRING( 17, EncodedBy );
-    ADD_VLC_META_STRING( 18, Language );
-    ADD_META( 19, DBUS_TYPE_INT64, i_length );
-    ADD_VLC_META_STRING( 20, NowPlaying );
-    ADD_VLC_META_STRING( 21, Publisher );
-    ADD_VLC_META_STRING( 22, Setting );
-    ADD_VLC_META_STRING( 24, TrackID );
+    ADD_META( 0, DBUS_TYPE_OBJECT_PATH, psz_trackid );
+    ADD_VLC_META_STRING( 1,  URI );
+    ADD_VLC_META_STRING( 2,  Title );
+    ADD_VLC_META_STRING( 3,  Artist );
+    ADD_VLC_META_STRING( 4,  Album );
+    ADD_VLC_META_STRING( 5,  TrackNum );
+    ADD_META( 6, DBUS_TYPE_UINT32, i_time );
+    ADD_META( 7, DBUS_TYPE_INT64,  i_mtime );
+    ADD_VLC_META_STRING( 8,  Genre );
+    ADD_VLC_META_STRING( 9,  Rating );
+    ADD_VLC_META_STRING( 10, Date );
+    ADD_VLC_META_STRING( 11, ArtURL );
+    ADD_VLC_META_STRING( 12, TrackID );
+
+    ADD_VLC_META_STRING( 17, Copyright );
+    ADD_VLC_META_STRING( 18, Description );
+    ADD_VLC_META_STRING( 19, EncodedBy );
+    ADD_VLC_META_STRING( 20, Language );
+    ADD_META( 21, DBUS_TYPE_INT64, i_length );
+    ADD_VLC_META_STRING( 22, NowPlaying );
+    ADD_VLC_META_STRING( 23, Publisher );
+    ADD_VLC_META_STRING( 24, Setting );
     ADD_VLC_META_STRING( 25, URL );
 
     vlc_mutex_lock( &p_input->lock );
index 0a5ac8a..1230f41 100644 (file)
 #ifndef _VLC_DBUS_H
 #define _VLC_DBUS_H
 
-#define DBUS_MPRIS_BUS_NAME "org.mpris.vlc"
+#define DBUS_MPRIS_BUS_NAME "org.mpris.MediaPlayer2.vlc"
+
+static DBusHandlerResult
+MPRISEntryPoint ( DBusConnection *p_conn, DBusMessage *p_from, void *p_this );
+
+static const DBusObjectPathVTable dbus_mpris_vtable = {
+        NULL, MPRISEntryPoint, /* handler function */
+        NULL, NULL, NULL, NULL
+};
+
+#define ABS(x) ( ( x ) > 0 ? ( x ) : ( -1 * ( x ) ) )
+#define SEEK_THRESHOLD 1000 /* µsec */
 
 #endif //dbus.h
index ce9b927..250b1cf 100644 (file)
 
 #include <vlc_common.h>
 #include <vlc_interface.h>
+#include <vlc_aout.h>
 #include <dbus/dbus.h>
 
+#define DBUS_MPRIS_OBJECT_PATH "/org/mpris/MediaPlayer2"
+
 /* MACROS */
 
 #define INTF ((intf_thread_t *)p_this)
         return DBUS_HANDLER_RESULT_NEED_MEMORY
 
 #define ADD_STRING( s ) DBUS_ADD( DBUS_TYPE_STRING, s )
+#define ADD_DOUBLE( d ) DBUS_ADD( DBUS_TYPE_DOUBLE, d )
 #define ADD_BOOL( b ) DBUS_ADD( DBUS_TYPE_BOOLEAN, b )
 #define ADD_INT32( i ) DBUS_ADD( DBUS_TYPE_INT32, i )
+#define ADD_INT64( i ) DBUS_ADD( DBUS_TYPE_INT64, i )
 #define ADD_BYTE( b ) DBUS_ADD( DBUS_TYPE_BYTE, b )
 
+#define MPRIS_TRACKID_FORMAT "/org/videolan/vlc/playlist/%d"
+
 struct intf_sys_t
 {
     DBusConnection *p_conn;
     playlist_t     *p_playlist;
     bool            b_meta_read;
-    dbus_int32_t    i_caps;
+    dbus_int32_t    i_player_caps;
     dbus_int32_t    i_playing_state;
+    bool            b_can_play;
     bool            b_dead;
     vlc_array_t    *p_events;
     vlc_array_t    *p_timeouts;
@@ -94,6 +102,8 @@ struct intf_sys_t
     int             p_pipe_fds[2];
     vlc_mutex_t     lock;
     input_thread_t *p_input;
+    mtime_t         i_last_input_pos; /* Only access it from the input thread */
+    mtime_t         i_last_input_pos_event; /* idem */
     bool            b_unique;
 };
 
@@ -107,7 +117,13 @@ enum
     SIGNAL_RANDOM,
     SIGNAL_REPEAT,
     SIGNAL_LOOP,
-    SIGNAL_STATE
+    SIGNAL_STATE,
+    SIGNAL_RATE,
+    SIGNAL_SEEK,
+    SIGNAL_CAN_SEEK,
+    SIGNAL_CAN_PAUSE,
+    SIGNAL_VOLUME_CHANGE,
+    SIGNAL_VOLUME_MUTED
 };
 
 enum
@@ -118,7 +134,7 @@ enum
     PLAYBACK_STATE_STOPPED = 2
 };
 
+int DemarshalSetPropertyValue( DBusMessage *p_msg, void *p_arg );
 int GetInputMeta  ( input_item_t* p_input, DBusMessageIter *args );
-int UpdateCaps    ( intf_thread_t* );
 
 #endif //dbus-common.h
diff --git a/modules/control/dbus/dbus_introspect.h b/modules/control/dbus/dbus_introspect.h
new file mode 100644 (file)
index 0000000..f9aac13
--- /dev/null
@@ -0,0 +1,139 @@
+/*****************************************************************************
+ * dbus-introspect.h : dbus control module (mpris v2.1) - introspection data
+ *****************************************************************************
+ * Copyright © 2006-2008 Rafaël Carré
+ * Copyright © 2007-2010 Mirsal Ennaime
+ * Copyright © 2009-2010 The VideoLAN team
+ * $Id$
+ *
+ * Authors:    Mirsal Ennaime <mirsal at mirsal fr>
+ *             Rafaël Carré <funman at videolanorg>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef _VLC_DBUS_INTROSPECT_H
+#define _VLC_DBUS_INTROSPECT_H
+
+#include "dbus_common.h"
+
+/* XML data to answer org.freedesktop.DBus.Introspectable.Introspect requests */
+static const char* psz_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>\n"
+"  <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.DBus.Properties\">\n"
+"    <method name=\"Get\">\n"
+"      <arg direction=\"in\" type=\"s\"/>\n"
+"      <arg direction=\"in\" type=\"s\"/>\n"
+"      <arg direction=\"out\" type=\"v\"/>\n"
+"    </method>\n"
+"    <method name=\"Set\">\n"
+"      <arg direction=\"in\" type=\"s\"/>\n"
+"      <arg direction=\"in\" type=\"s\"/>\n"
+"      <arg direction=\"in\" type=\"v\"/>\n"
+"    </method>\n"
+"    <signal name=\"PropertiesChanged\">\n"
+"      <arg type=\"s\"/>\n"
+"      <arg type=\"a{sv}\"/>\n"
+"      <arg type=\"as\"/>\n"
+"    </signal>\n"
+"  </interface>\n"
+"  <interface name=\"org.mpris.MediaPlayer2\">\n"
+"    <property name=\"Identity\" type=\"s\" access=\"read\" />\n"
+"    <property name=\"DesktopEntry\" type=\"s\" access=\"read\" />\n"
+"    <property name=\"SupportedMimeTypes\" type=\"as\" access=\"read\" />\n"
+"    <property name=\"SupportedUriSchemes\" type=\"as\" access=\"read\" />\n"
+"    <property name=\"HasTrackList\" type=\"b\" access=\"read\" />\n"
+"    <property name=\"CanQuit\" type=\"b\" access=\"read\" />\n"
+"    <property name=\"CanRaise\" type=\"b\" access=\"read\" />\n"
+"    <method name=\"Quit\" />\n"
+"  </interface>\n"
+"  <interface name=\"org.mpris.MediaPlayer2.Player\">\n"
+"    <property name=\"Metadata\" type=\"a{sv}\" access=\"read\" />\n"
+"    <property name=\"PlaybackStatus\" type=\"s\" access=\"read\" />\n"
+"    <property name=\"LoopStatus\" type=\"s\" access=\"readwrite\" />\n"
+"    <property name=\"Volume\" type=\"d\" access=\"readwrite\" />\n"
+"    <property name=\"Shuffle\" type=\"d\" access=\"readwrite\" />\n"
+"    <property name=\"Position\" type=\"i\" access=\"read\" />\n"
+"    <property name=\"Rate\" type=\"d\" access=\"readwrite\" />\n"
+"    <property name=\"MinimumRate\" type=\"d\" access=\"readwrite\" />\n"
+"    <property name=\"MaximumRate\" type=\"d\" access=\"readwrite\" />\n"
+"    <property name=\"CanControl\" type=\"b\" access=\"read\" />\n"
+"    <property name=\"CanPlay\" type=\"b\" access=\"read\" />\n"
+"    <property name=\"CanPause\" type=\"b\" access=\"read\" />\n"
+"    <property name=\"CanSeek\" type=\"b\" access=\"read\" />\n"
+"    <method name=\"Previous\" />\n"
+"    <method name=\"Next\" />\n"
+"    <method name=\"Stop\" />\n"
+"    <method name=\"Play\" />\n"
+"    <method name=\"Pause\" />\n"
+"    <method name=\"PlayPause\" />\n"
+"    <method name=\"OpenUri\">\n"
+"      <arg type=\"s\" direction=\"in\" />\n"
+"    </method>\n"
+"    <method name=\"SetPosition\">\n"
+"      <arg type=\"s\" direction=\"in\" />\n"
+"      <arg type=\"i\" direction=\"in\" />\n"
+"    </method>\n"
+"  </interface>\n"
+"  <interface name=\"org.mpris.MediaPlayer2.TrackList\">\n"
+"    <method name=\"AddTrack\">\n"
+"      <arg type=\"s\" direction=\"in\" />\n"
+"      <arg type=\"b\" direction=\"in\" />\n"
+"      <arg type=\"i\" direction=\"out\" />\n"
+"    </method>\n"
+"    <method name=\"DelTrack\">\n"
+"      <arg type=\"i\" direction=\"in\" />\n"
+"    </method>\n"
+"    <method name=\"GetMetadata\">\n"
+"      <arg type=\"i\" direction=\"in\" />\n"
+"      <arg type=\"a{sv}\" direction=\"out\" />\n"
+"    </method>\n"
+"    <method name=\"GetCurrentTrack\">\n"
+"      <arg type=\"i\" direction=\"out\" />\n"
+"    </method>\n"
+"    <method name=\"GetLength\">\n"
+"      <arg type=\"i\" direction=\"out\" />\n"
+"    </method>\n"
+"    <method name=\"SetLoop\">\n"
+"      <arg type=\"b\" direction=\"in\" />\n"
+"    </method>\n"
+"    <method name=\"SetRandom\">\n"
+"      <arg type=\"b\" direction=\"in\" />\n"
+"    </method>\n"
+"    <signal name=\"TrackListChange\">\n"
+"      <arg type=\"i\" />\n"
+"    </signal>\n"
+"  </interface>\n"
+"</node>\n"
+;
+
+/* Handle incoming dbus messages */
+DBUS_METHOD( handle_introspect )
+{
+    VLC_UNUSED(p_this);
+    REPLY_INIT;
+    OUT_ARGUMENTS;
+    ADD_STRING( &psz_introspection_xml );
+    REPLY_SEND;
+}
+
+#endif //dbus-introspect.h
index 359ccfe..dea7851 100644 (file)
 
 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 */
+DBUS_METHOD( Position )
+{ /* returns position in microseconds */
     REPLY_INIT;
     OUT_ARGUMENTS;
+    DBusMessageIter v;
     dbus_int32_t i_pos;
 
+    if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "i", &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
     input_thread_t *p_input = playlist_CurrentInput( PL );
 
     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 );
+
+    if( !dbus_message_iter_append_basic( &v, DBUS_TYPE_INT32, &i_pos ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    if( !dbus_message_iter_close_container( &args, &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
     REPLY_SEND;
 }
 
-DBUS_METHOD( PositionSet )
-{ /* set position in milliseconds */
+DBUS_METHOD( SetPosition )
+{ /* set position in microseconds */
 
     REPLY_INIT;
-    vlc_value_t position;
     dbus_int32_t i_pos;
+    vlc_value_t position;
+    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,43 +94,47 @@ DBUS_METHOD( PositionSet )
         dbus_error_free( &error );
         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     }
+
     input_thread_t *p_input = playlist_CurrentInput( PL );
 
     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 );
+            }
+        }
+
         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 = aout_VolumeGet( PL );
-    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_int32_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_INT32, &i_step,
             DBUS_TYPE_INVALID );
 
     if( dbus_error_is_set( &error ) )
@@ -185,9 +145,70 @@ 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 );
+    input_thread_t *p_input = playlist_CurrentInput( PL );
+    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 void
+MarshalVolume( intf_thread_t *p_intf, DBusMessageIter *container )
+{
+    audio_volume_t i_vol = aout_VolumeGet( p_intf->p_sys->p_playlist );
+
+    /* A volume of 1.0 represents a sensible maximum, ie: 0dB */
+    double d_vol = (double) i_vol / ( AOUT_VOLUME_MAX >> 2 );
+
+    dbus_message_iter_append_basic( container, DBUS_TYPE_DOUBLE, &d_vol );
+}
+
+DBUS_METHOD( VolumeGet )
+{
+    REPLY_INIT;
+    OUT_ARGUMENTS;
+
+    DBusMessageIter v;
+
+    if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "d", &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    MarshalVolume( p_this, &v );
+
+    if( !dbus_message_iter_close_container( &args, &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    REPLY_SEND;
+}
+
+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;
+
+    if( d_dbus_vol > 1. )
+        d_dbus_vol = 1.;
+    else if( d_dbus_vol < 0. )
+        d_dbus_vol = 0.;
+
+    double d_vol = d_dbus_vol * AOUT_VOLUME_MAX;
+    audio_volume_t i_vol = round( d_vol );
     aout_VolumeSet( PL, i_vol );
+
     REPLY_SEND;
 }
 
@@ -212,18 +233,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 =  playlist_CurrentInput( PL );
 
-    MarshalStatus( p_this, &args );
+    if( !p_input || var_GetInteger( p_input, "state" ) != PLAYING_S )
+        playlist_Play( PL );
+
+    if( p_input )
+        vlc_object_release( p_input );
 
     REPLY_SEND;
 }
@@ -231,39 +250,43 @@ DBUS_METHOD( GetStatus )
 DBUS_METHOD( Pause )
 {
     REPLY_INIT;
-    playlist_Pause( PL );
+    input_thread_t *p_input = playlist_CurrentInput( PL );
+
+    if( p_input && var_GetInteger(p_input, "state") == PLAYING_S )
+        playlist_Pause( PL );
+
+    if( p_input )
+        vlc_object_release( p_input );
+
     REPLY_SEND;
 }
 
-DBUS_METHOD( Play )
+DBUS_METHOD( PlayPause )
 {
     REPLY_INIT;
+    input_thread_t *p_input = playlist_CurrentInput( PL );
 
-    input_thread_t *p_input =  playlist_CurrentInput( PL );
+    if( p_input && var_GetInteger(p_input, "state") == PLAYING_S )
+        playlist_Pause( 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 ) )
@@ -274,96 +297,510 @@ 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 void
+MarshalCanPlay( intf_thread_t *p_intf, DBusMessageIter *container )
 {
-    REPLY_INIT;
-    OUT_ARGUMENTS;
-    playlist_t *p_playlist = PL;
+    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 );
     PL_UNLOCK;
+
+    dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN, &b_can_play );
+}
+
+DBUS_METHOD( CanPlay )
+{
+    REPLY_INIT;
+    OUT_ARGUMENTS;
+
+    DBusMessageIter v;
+
+    if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "b", &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    MarshalCanPlay( p_this, &v );
+
+    if( !dbus_message_iter_close_container( &args, &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    REPLY_SEND;
+}
+
+static void
+MarshalCanPause( intf_thread_t *p_intf, DBusMessageIter *container )
+{
+    dbus_bool_t b_can_pause = FALSE;
+    input_thread_t *p_input;
+    p_input = playlist_CurrentInput( p_intf->p_sys->p_playlist );
+
+    if( p_input )
+    {
+        b_can_pause = var_GetBool( p_input, "can-pause" );
+        vlc_object_release( p_input );
+    }
+
+    dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
+                                    &b_can_pause );
+}
+
+DBUS_METHOD( CanPause )
+{
+    REPLY_INIT;
+    OUT_ARGUMENTS;
+
+    DBusMessageIter v;
+
+    if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "b", &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    MarshalCanPause( p_this, &v );
+
+    if( !dbus_message_iter_close_container( &args, &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
     REPLY_SEND;
 }
 
-DBUS_METHOD( GetCaps )
+DBUS_METHOD( CanControl )
 {
     REPLY_INIT;
     OUT_ARGUMENTS;
 
-    ADD_INT32( &INTF->p_sys->i_caps );
+    DBusMessageIter v;
+    dbus_bool_t b_can_control = TRUE;
+
+    if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT,
+                                           "b", &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    if( !dbus_message_iter_append_basic( &v, DBUS_TYPE_BOOLEAN,
+                                         &b_can_control ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    if( !dbus_message_iter_close_container( &args, &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
     REPLY_SEND;
 }
 
-/*****************************************************************************
- * StatusChange: Player status change signal
- *****************************************************************************/
+static void
+MarshalCanSeek( intf_thread_t *p_intf, DBusMessageIter *container )
+{
+    dbus_bool_t b_can_seek = FALSE;
+    input_thread_t *p_input;
+    p_input = playlist_CurrentInput( p_intf->p_sys->p_playlist );
 
-DBUS_SIGNAL( StatusChangeSignal )
-{ /* send the updated status info on the bus */
-    SIGNAL_INIT( DBUS_MPRIS_PLAYER_INTERFACE,
-                 DBUS_MPRIS_PLAYER_PATH,
-                 "StatusChange" );
+    if( p_input )
+    {
+        b_can_seek = var_GetBool( p_input, "can-seek" );
+        vlc_object_release( p_input );
+    }
+
+    dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN, &b_can_seek );
+}
+
+DBUS_METHOD( CanSeek )
+{
+    REPLY_INIT;
+    OUT_ARGUMENTS;
+
+    DBusMessageIter v;
+
+    if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "b", &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    MarshalCanSeek( p_this, &v );
+
+    REPLY_SEND;
+}
+
+static void
+MarshalShuffle( intf_thread_t *p_intf, DBusMessageIter *container )
+{
+    dbus_bool_t b_shuffle = var_GetBool( p_intf->p_sys->p_playlist, "random" );
+    dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN, &b_shuffle );
+}
 
+DBUS_METHOD( ShuffleGet )
+{
+    REPLY_INIT;
     OUT_ARGUMENTS;
 
-    /* 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 );
+    DBusMessageIter v;
 
-    SIGNAL_SEND;
+    if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "b", &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    MarshalShuffle( p_this, &v );
+
+    if( !dbus_message_iter_close_container( &args, &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    REPLY_SEND;
 }
 
-/*****************************************************************************
- * TrackChange: Playlist item change callback
- *****************************************************************************/
+DBUS_METHOD( ShuffleSet )
+{
+    REPLY_INIT;
+    dbus_bool_t b_shuffle;
 
-DBUS_SIGNAL( TrackChangeSignal )
-{ /* emit the metadata of the new item */
-    SIGNAL_INIT( DBUS_MPRIS_PLAYER_INTERFACE,
-                 DBUS_MPRIS_PLAYER_PATH,
-                 "TrackChange" );
+    if( VLC_SUCCESS != DemarshalSetPropertyValue( p_from, &b_shuffle ) )
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+    var_SetBool( PL, "random", ( b_shuffle == TRUE ) );
+
+    REPLY_SEND;
+}
+
+static void
+MarshalPlaybackStatus( intf_thread_t *p_intf, DBusMessageIter *container )
+{
+    input_thread_t *p_input;
+    char *psz_playback_status;
+    if( ( p_input = playlist_CurrentInput( p_intf->p_sys->p_playlist ) ) )
+    {
+        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;
+
+    dbus_message_iter_append_basic( container, DBUS_TYPE_STRING,
+                                    &psz_playback_status );
+}
 
+DBUS_METHOD( PlaybackStatus )
+{
+    REPLY_INIT;
     OUT_ARGUMENTS;
 
-    input_item_t *p_item = (input_item_t*) p_data;
-    GetInputMeta ( p_item, &args );
+    DBusMessageIter v;
 
-    SIGNAL_SEND;
+    if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "s", &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    MarshalPlaybackStatus( p_this, &v );
+
+    if( !dbus_message_iter_close_container( &args, &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    REPLY_SEND;
+}
+
+static void
+MarshalRate( intf_thread_t *p_intf, DBusMessageIter *container )
+{
+    double d_rate;
+    input_thread_t *p_input;
+    if( ( p_input = playlist_CurrentInput( p_intf->p_sys->p_playlist ) ) )
+    {
+        d_rate = var_GetFloat( p_input, "rate" );
+        vlc_object_release( (vlc_object_t*) p_input );
+    }
+    else
+        d_rate = 0.;
+
+    dbus_message_iter_append_basic( container, DBUS_TYPE_DOUBLE, &d_rate );
+}
+
+DBUS_METHOD( RateGet )
+{
+    REPLY_INIT;
+    OUT_ARGUMENTS;
+
+    DBusMessageIter v;
+
+    if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "d", &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    MarshalRate( p_this, &v );
+
+    if( !dbus_message_iter_close_container( &args, &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    REPLY_SEND;
+}
+
+DBUS_METHOD( RateSet )
+{
+    REPLY_INIT;
+
+    double d_rate;
+
+    if( VLC_SUCCESS != DemarshalSetPropertyValue( p_from, &d_rate ) )
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+    input_thread_t *p_input;
+    if( ( p_input = playlist_CurrentInput( PL ) ) )
+    {
+        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;
+}
+
+DBUS_METHOD( MinimumRate )
+{
+    REPLY_INIT;
+    OUT_ARGUMENTS;
+
+    DBusMessageIter v;
+    double d_min_rate = (double) INPUT_RATE_MIN / INPUT_RATE_DEFAULT;
+
+    if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "d", &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    if( !dbus_message_iter_append_basic( &v, DBUS_TYPE_DOUBLE, &d_min_rate ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    if( !dbus_message_iter_close_container( &args, &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    REPLY_SEND;
+}
+
+DBUS_METHOD( MaximumRate )
+{
+    REPLY_INIT;
+    OUT_ARGUMENTS;
+
+    DBusMessageIter v;
+    double d_max_rate = (double) INPUT_RATE_MAX / INPUT_RATE_DEFAULT;
+
+    if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "d", &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    if( !dbus_message_iter_append_basic( &v, DBUS_TYPE_DOUBLE, &d_max_rate ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    if( !dbus_message_iter_close_container( &args, &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    REPLY_SEND;
+}
+
+static void
+MarshalLoopStatus( intf_thread_t *p_intf, DBusMessageIter *container )
+{
+    char *psz_loop_status;
+    if( var_GetBool( p_intf->p_sys->p_playlist, "repeat" ) )
+        psz_loop_status = LOOP_STATUS_TRACK;
+    else if( var_GetBool( p_intf->p_sys->p_playlist, "loop" ) )
+        psz_loop_status = LOOP_STATUS_PLAYLIST;
+    else
+        psz_loop_status = LOOP_STATUS_NONE;
+
+    dbus_message_iter_append_basic( container, DBUS_TYPE_STRING,
+                                    &psz_loop_status );
+}
+
+DBUS_METHOD( LoopStatusGet )
+{
+    REPLY_INIT;
+    OUT_ARGUMENTS;
+
+    DBusMessageIter v;
+
+    if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "s", &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    MarshalLoopStatus( p_this, &v );
+
+    if( !dbus_message_iter_close_container( &args, &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    REPLY_SEND;
+}
+
+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;
+}
+
+DBUS_METHOD( Metadata )
+{
+    REPLY_INIT;
+    OUT_ARGUMENTS;
+
+    DBusMessageIter v, a;
+    playlist_t *p_playlist = PL;
+
+    if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT,
+                                           "a{sv}", &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    PL_LOCK;
+    playlist_item_t* p_item =  playlist_CurrentPlayingItem( p_playlist );
+
+    if( p_item )
+        GetInputMeta( p_item->p_input, &v );
+
+    PL_UNLOCK;
+
+    if( ( !p_item &&
+        ( !dbus_message_iter_open_container( &v, DBUS_TYPE_ARRAY, "{sv}", &a ) ||
+          !dbus_message_iter_close_container( &v, &a ) ) ) ||
+
+        !dbus_message_iter_close_container( &args, &v ) ) {
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+    }
+
+    REPLY_SEND;
 }
 
 /******************************************************************************
- * 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 = playlist_CurrentInput( p_intf->p_sys->p_playlist );
+
+    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_FUNC( interface, property, function ) \
+    else if( !strcmp( psz_interface_name, interface ) && \
+             !strcmp( psz_property_name,  property ) ) \
+        return function( p_conn, p_from, p_this );
+#define PROPERTY_MAPPING_END return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+DBUS_METHOD( GetProperty )
 {
-    VLC_UNUSED(p_this);
-    REPLY_INIT;
-    OUT_ARGUMENTS;
-    ADD_STRING( &psz_player_introspection_xml );
-    REPLY_SEND;
+    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 );
+
+    PROPERTY_MAPPING_BEGIN
+    PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Metadata", Metadata )
+    PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Position", Position )
+    PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "PlaybackStatus", PlaybackStatus )
+    PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "LoopStatus", LoopStatusGet )
+    PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Shuffle", ShuffleGet )
+    PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Volume", VolumeGet )
+    PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Rate", RateGet )
+    PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "MinimumRate", MinimumRate )
+    PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "MaximumRate", MaximumRate )
+    PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "CanControl", CanControl )
+    PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "CanPlay", CanPlay )
+    PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "CanPause", CanPause )
+    PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "CanSeek", CanSeek )
+    PROPERTY_MAPPING_END
+}
+
+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_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "LoopStatus", LoopStatusSet )
+    PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Shuffle",    ShuffleSet )
+    PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Volume",     VolumeSet )
+    PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Rate",       RateSet )
+    PROPERTY_MAPPING_END
 }
 
+#undef PROPERTY_MAPPING_BEGIN
+#undef PROPERTY_GET_FUNC
+#undef PROPERTY_MAPPING_END
+
 #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 )
@@ -371,25 +808,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;
 }
@@ -397,72 +831,154 @@ 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 )
+/**
+ * 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, entry, variant;
+    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" );
+
+    OUT_ARGUMENTS;
+    ADD_STRING( &psz_interface_name );
+    dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "{sv}",
+                                      &changed_properties );
+
+    i_properties = vlc_dictionary_keys_count( p_changed_properties );
+    ppsz_properties = vlc_dictionary_all_keys( p_changed_properties );
+
+    for( int i = 0; i < i_properties; i++ )
+    {
+        dbus_message_iter_open_container( &changed_properties,
+                                          DBUS_TYPE_DICT_ENTRY, NULL,
+                                          &entry );
+
+        dbus_message_iter_append_basic( &entry, DBUS_TYPE_STRING,
+                                        &ppsz_properties[i] );
+
+        if( !strcmp( ppsz_properties[i], "Metadata" ) )
+        {
+            input_thread_t *p_input;
+            p_input = playlist_CurrentInput( p_intf->p_sys->p_playlist );
+
+            dbus_message_iter_open_container( &entry,
+                                              DBUS_TYPE_VARIANT, "a{sv}",
+                                              &variant );
+
+            if( p_input )
+            {
+                input_item_t *p_item = input_GetItem( p_input );
+                GetInputMeta( p_item, &variant );
+                vlc_object_release( p_input );
+            }
+
+            dbus_message_iter_close_container( &entry, &variant );
+        }
+        else if( !strcmp( ppsz_properties[i], "PlaybackStatus" ) )
+        {
+            dbus_message_iter_open_container( &entry,
+                                              DBUS_TYPE_VARIANT, "s",
+                                              &variant );
+            MarshalPlaybackStatus( p_intf, &variant );
+            dbus_message_iter_close_container( &entry, &variant );
+        }
+        else if( !strcmp( ppsz_properties[i], "LoopStatus" ) )
+        {
+            dbus_message_iter_open_container( &entry,
+                                              DBUS_TYPE_VARIANT, "s",
+                                              &variant );
+            MarshalLoopStatus( p_intf, &variant );
+            dbus_message_iter_close_container( &entry, &variant );
+        }
+        else if( !strcmp( ppsz_properties[i], "Rate" ) )
+        {
+            dbus_message_iter_open_container( &entry,
+                                              DBUS_TYPE_VARIANT, "d",
+                                              &variant );
+            MarshalRate( p_intf, &variant );
+            dbus_message_iter_close_container( &entry, &variant );
+        }
+        else if( !strcmp( ppsz_properties[i], "Shuffle" ) )
+        {
+            dbus_message_iter_open_container( &entry,
+                                              DBUS_TYPE_VARIANT, "b",
+                                              &variant );
+            MarshalShuffle( p_intf, &variant );
+            dbus_message_iter_close_container( &entry, &variant );
+        }
+        else if( !strcmp( ppsz_properties[i], "Volume" ) )
+        {
+            dbus_message_iter_open_container( &entry,
+                                              DBUS_TYPE_VARIANT, "d",
+                                              &variant );
+            MarshalVolume( p_intf, &variant );
+            dbus_message_iter_close_container( &entry, &variant );
+        }
+        else if( !strcmp( ppsz_properties[i], "CanSeek" ) )
+        {
+            dbus_message_iter_open_container( &entry,
+                                              DBUS_TYPE_VARIANT, "b",
+                                              &variant );
+            MarshalCanSeek( p_intf, &variant );
+            dbus_message_iter_close_container( &entry, &variant );
+        }
+        else if( !strcmp( ppsz_properties[i], "CanPlay" ) )
+        {
+            dbus_message_iter_open_container( &entry,
+                                              DBUS_TYPE_VARIANT, "b",
+                                              &variant );
+            MarshalCanPlay( p_intf, &variant );
+            dbus_message_iter_close_container( &entry, &variant );
+        }
+        else if( !strcmp( ppsz_properties[i], "CanPause" ) )
+        {
+            dbus_message_iter_open_container( &entry,
+                                              DBUS_TYPE_VARIANT, "b",
+                                              &variant );
+            MarshalCanPause( p_intf, &variant );
+            dbus_message_iter_close_container( &entry, &variant );
+        }
+        dbus_message_iter_close_container( &changed_properties, &entry );
+    }
+
+    dbus_message_iter_close_container( &args, &changed_properties );
+    dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "s",
+                                      &invalidated_properties );
+    dbus_message_iter_close_container( &args, &invalidated_properties );
+
+    SIGNAL_SEND;
 }
 
 /*****************************************************************************
- * TrackChangeEmit: Emits the TrackChange signal
+ * PropertiesChangedEmit: Emits the Seeked signal
  *****************************************************************************/
-int TrackChangeEmit( intf_thread_t * p_intf, input_item_t* p_item )
+int PlayerPropertiesChangedEmit( intf_thread_t    * p_intf,
+                                 vlc_dictionary_t * p_changed_properties )
 {
     if( p_intf->p_sys->b_dead )
         return VLC_SUCCESS;
 
-    UpdateCaps( p_intf );
-    TrackChangeSignal( p_intf->p_sys->p_conn, p_item );
-    return VLC_SUCCESS;
-}
-
-/*****************************************************************************
- * MarshalStatus: Fill a DBusMessage with the current player status
- *****************************************************************************/
-
-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 */
-
-    DBusMessageIter status;
-    dbus_int32_t i_state, i_random, i_repeat, i_loop;
-    playlist_t* p_playlist = p_intf->p_sys->p_playlist;
-
-    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 );
-
-    i_random = var_CreateGetBool( p_playlist, "random" );
-
-    i_repeat = var_CreateGetBool( p_playlist, "repeat" );
-
-    i_loop = var_CreateGetBool( p_playlist, "loop" );
-
-    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 );
-
+    PropertiesChangedSignal( p_intf, p_changed_properties );
     return VLC_SUCCESS;
 }
index 2934b17..20b00de 100644 (file)
 #include <vlc_interface.h>
 #include "dbus_common.h"
 
-#define DBUS_MPRIS_PLAYER_INTERFACE    "org.freedesktop.MediaPlayer"
-#define DBUS_MPRIS_PLAYER_PATH         "/Player"
+#define DBUS_MPRIS_PLAYER_INTERFACE    "org.mpris.MediaPlayer2.Player"
+
+#define LOOP_STATUS_NONE  "None"
+#define LOOP_STATUS_TRACK "Track"
+#define LOOP_STATUS_PLAYLIST "Playlist"
+
+#define PLAYBACK_STATUS_STOPPED "Stopped"
+#define PLAYBACK_STATUS_PLAYING "Playing"
+#define PLAYBACK_STATUS_PAUSED  "Paused"
 
 /* Handle incoming dbus messages */
 DBusHandlerResult handle_player ( DBusConnection *p_conn,
                                   DBusMessage *p_from,
                                   void *p_this );
 
-static const DBusObjectPathVTable dbus_mpris_player_vtable = {
-        NULL, handle_player, /* handler function */
-        NULL, NULL, NULL, NULL
-};
-
-/* GetCaps() capabilities */
+/* Player capabilities */
 enum
 {
-     CAPS_NONE                  = 0,
-     CAPS_CAN_GO_NEXT           = 1 << 0,
-     CAPS_CAN_GO_PREV           = 1 << 1,
-     CAPS_CAN_PAUSE             = 1 << 2,
-     CAPS_CAN_PLAY              = 1 << 3,
-     CAPS_CAN_SEEK              = 1 << 4,
-     CAPS_CAN_PROVIDE_METADATA  = 1 << 5,
-     CAPS_CAN_HAS_TRACKLIST     = 1 << 6
+     PLAYER_CAPS_NONE            = 0,
+     PLAYER_CAN_GO_NEXT          = 1 << 0,
+     PLAYER_CAN_GO_PREVIOUS      = 1 << 1,
+     PLAYER_CAN_PAUSE            = 1 << 2,
+     PLAYER_CAN_PLAY             = 1 << 3,
+     PLAYER_CAN_SEEK             = 1 << 4,
+     PLAYER_CAN_PROVIDE_METADATA = 1 << 5,
+     PLAYER_CAN_PROVIDE_POSITION = 1 << 6,
+     PLAYER_CAN_REPEAT           = 1 << 7,
+     PLAYER_CAN_LOOP             = 1 << 8,
+     PLAYER_CAN_SHUFFLE          = 1 << 9,
+     PLAYER_CAN_CONTROL_RATE     = 1 << 10,
+     PLAYER_CAN_PLAY_BACKWARDS   = 1 << 11
 };
 
-int StatusChangeEmit ( intf_thread_t * );
-int CapsChangeEmit   ( intf_thread_t * );
-int TrackChangeEmit  ( intf_thread_t *, input_item_t * );
+int PlayerStatusChangedEmit     ( intf_thread_t * );
+int PlayerCapsChangedEmit ( intf_thread_t * );
+int PlayerMetadataChangedEmit( intf_thread_t*, input_item_t* );
+int TrackChangedEmit      ( intf_thread_t *, input_item_t * );
+int SeekedEmit( intf_thread_t * );
+
+int PlayerPropertiesChangedEmit( intf_thread_t *, vlc_dictionary_t * );
+
+void UpdatePlayerCaps( intf_thread_t * );
 
 #endif //dbus_player.h
index 3b49648..96f8868 100644 (file)
 #include <vlc_common.h>
 #include <vlc_interface.h>
 
+#include <unistd.h>
+#include <limits.h>
+
 #include "dbus_root.h"
 #include "dbus_common.h"
 
-/* XML data to answer org.freedesktop.DBus.Introspectable.Introspect requests */
-static const char* psz_root_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>\n"
-"  <node name=\"Player\"/>\n"
-"  <node name=\"TrackList\"/>\n"
-"  <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=\"Identity\">\n"
-"      <arg type=\"s\" direction=\"out\" />\n"
-"    </method>\n"
-"    <method name=\"MprisVersion\">\n"
-"      <arg type=\"(qq)\" direction=\"out\" />\n"
-"    </method>\n"
-"    <method name=\"Quit\">\n"
-"    </method>\n"
-"  </interface>\n"
-"</node>\n"
-;
-
 DBUS_METHOD( Identity )
 {
     VLC_UNUSED(p_this);
     REPLY_INIT;
     OUT_ARGUMENTS;
-    char *psz_identity;
 
-    if( asprintf( &psz_identity, "%s %s", PACKAGE, VERSION ) != -1 )
-    {
-        ADD_STRING( &psz_identity );
-        free( psz_identity );
-    }
-    else
+    char *psz_identity = VLC_IDENTITY;
+
+    DBusMessageIter v;
+    dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "s", &v );
+    dbus_message_iter_append_basic( &v, DBUS_TYPE_STRING, &psz_identity );
+
+    if( !dbus_message_iter_close_container( &args, &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    REPLY_SEND;
+}
+
+DBUS_METHOD( CanQuit )
+{
+    VLC_UNUSED( p_this );
+    REPLY_INIT;
+    OUT_ARGUMENTS;
+
+    const dbus_bool_t b_ret = TRUE;
+
+    DBusMessageIter v;
+    dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "s", &v );
+    dbus_message_iter_append_basic( &v, DBUS_TYPE_BOOLEAN, &b_ret );
+
+    if( !dbus_message_iter_close_container( &args, &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    REPLY_SEND;
+}
+
+DBUS_METHOD( CanRaise )
+{
+    VLC_UNUSED( p_this );
+    REPLY_INIT;
+    OUT_ARGUMENTS;
+
+    const dbus_bool_t b_ret = FALSE;
+
+    DBusMessageIter v;
+    dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "s", &v );
+    dbus_message_iter_append_basic( &v, DBUS_TYPE_BOOLEAN, &b_ret );
+
+    if( !dbus_message_iter_close_container( &args, &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    REPLY_SEND;
+}
+
+DBUS_METHOD( HasTrackList )
+{
+    VLC_UNUSED( p_this );
+    REPLY_INIT;
+    OUT_ARGUMENTS;
+
+    const dbus_bool_t b_ret = FALSE;
+
+    DBusMessageIter v;
+    dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "s", &v );
+    dbus_message_iter_append_basic( &v, DBUS_TYPE_BOOLEAN, &b_ret );
+
+    if( !dbus_message_iter_close_container( &args, &v ) )
         return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
     REPLY_SEND;
 }
 
-DBUS_METHOD( MprisVersion )
-{ /*implemented version of the mpris spec */
+DBUS_METHOD( DesktopEntry )
+{
+    VLC_UNUSED( p_this );
     REPLY_INIT;
     OUT_ARGUMENTS;
+
+    const char* psz_ret = PACKAGE;
+
+    DBusMessageIter v;
+    dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "s", &v );
+    dbus_message_iter_append_basic( &v, DBUS_TYPE_STRING, &psz_ret );
+
+    if( !dbus_message_iter_close_container( &args, &v ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    REPLY_SEND;
+}
+
+DBUS_METHOD( SupportedMimeTypes )
+{
     VLC_UNUSED( p_this );
-    dbus_uint16_t i_major = DBUS_MPRIS_VERSION_MAJOR;
-    dbus_uint16_t i_minor = DBUS_MPRIS_VERSION_MINOR;
-    DBusMessageIter version;
+    REPLY_INIT;
+    OUT_ARGUMENTS;
 
-    if( !dbus_message_iter_open_container( &args, DBUS_TYPE_STRUCT, NULL,
-            &version ) )
+    DBusMessageIter ret, v;
+    dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "s", &v );
+    size_t i_len = sizeof( ppsz_supported_mime_types ) / sizeof( char* );
+
+    if( !dbus_message_iter_open_container( &v, DBUS_TYPE_ARRAY, "s", &ret ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    for( size_t i = 0; i < i_len; ++i )
+        if( !dbus_message_iter_append_basic( &ret, DBUS_TYPE_STRING,
+                                             &ppsz_supported_mime_types[i] ) )
+            return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    if( !dbus_message_iter_close_container( &v, &ret ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    if( !dbus_message_iter_close_container( &args, &v ) )
         return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
-    if( !dbus_message_iter_append_basic( &version, DBUS_TYPE_UINT16,
-            &i_major ) )
+    REPLY_SEND;
+}
+
+DBUS_METHOD( SupportedUriSchemes )
+{
+    VLC_UNUSED( p_this );
+    REPLY_INIT;
+    OUT_ARGUMENTS;
+
+    DBusMessageIter ret, v;
+    dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "s", &v );
+    size_t i_len = sizeof( ppsz_supported_uri_schemes ) / sizeof( char* );
+
+    if( !dbus_message_iter_open_container( &v, DBUS_TYPE_ARRAY, "s", &ret ) )
         return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
-    if( !dbus_message_iter_append_basic( &version, DBUS_TYPE_UINT16,
-            &i_minor ) )
+    for( size_t i = 0; i < i_len; ++i )
+        if( !dbus_message_iter_append_basic( &ret, DBUS_TYPE_STRING,
+                                             &ppsz_supported_uri_schemes[i] ) )
+            return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    if( !dbus_message_iter_close_container( &v, &ret ) )
         return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
-    if( !dbus_message_iter_close_container( &args, &version ) )
+    if( !dbus_message_iter_close_container( &args, &v ) )
         return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
     REPLY_SEND;
 }
 
@@ -110,33 +188,67 @@ DBUS_METHOD( Quit )
     REPLY_SEND;
 }
 
-DBUS_METHOD( handle_introspect_root )
-{ /* handles introspection of root object */
-    VLC_UNUSED(p_this);
-    REPLY_INIT;
-    OUT_ARGUMENTS;
-    ADD_STRING( &psz_root_introspection_xml );
-    REPLY_SEND;
+#define PROPERTY_MAPPING_BEGIN if( 0 ) {}
+#define PROPERTY_FUNC( interface, property, function ) \
+    else if( !strcmp( psz_interface_name, interface ) && \
+             !strcmp( psz_property_name,  property ) ) \
+        return function( p_conn, p_from, p_this );
+#define PROPERTY_MAPPING_END return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+DBUS_METHOD( GetProperty )
+{
+    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 );
+
+    PROPERTY_MAPPING_BEGIN
+    PROPERTY_FUNC( DBUS_MPRIS_ROOT_INTERFACE, "Identity",            Identity )
+    PROPERTY_FUNC( DBUS_MPRIS_ROOT_INTERFACE, "DesktopEntry",        DesktopEntry )
+    PROPERTY_FUNC( DBUS_MPRIS_ROOT_INTERFACE, "SupportedMimeTypes",  SupportedMimeTypes )
+    PROPERTY_FUNC( DBUS_MPRIS_ROOT_INTERFACE, "SupportedUriSchemes", SupportedUriSchemes )
+    PROPERTY_FUNC( DBUS_MPRIS_ROOT_INTERFACE, "HasTrackList",        HasTrackList )
+    PROPERTY_FUNC( DBUS_MPRIS_ROOT_INTERFACE, "CanQuit",             CanQuit )
+    PROPERTY_FUNC( DBUS_MPRIS_ROOT_INTERFACE, "CanRaise",            CanRaise )
+    PROPERTY_MAPPING_END
 }
 
+#undef PROPERTY_MAPPING_BEGIN
+#undef PROPERTY_GET_FUNC
+#undef PROPERTY_MAPPING_END
+
+#define METHOD_MAPPING_BEGIN if( 0 ) {}
 #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 )
+#define METHOD_MAPPING_END return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
 DBusHandlerResult
 handle_root ( DBusConnection *p_conn, DBusMessage *p_from, void *p_this )
 {
-    if( dbus_message_is_method_call( p_from,
-                DBUS_INTERFACE_INTROSPECTABLE, "Introspect" ) )
-        return handle_introspect_root( p_conn, p_from, p_this );
-
-    /* here D-Bus method names are associated to an handler */
-
-    METHOD_FUNC( DBUS_MPRIS_ROOT_INTERFACE, "Identity",      Identity );
-    METHOD_FUNC( DBUS_MPRIS_ROOT_INTERFACE, "MprisVersion",  MprisVersion );
-    METHOD_FUNC( DBUS_MPRIS_ROOT_INTERFACE, "Quit",          Quit );
-
-    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    METHOD_MAPPING_BEGIN
+    METHOD_FUNC( DBUS_INTERFACE_PROPERTIES, "Get",          GetProperty );
+    METHOD_FUNC( DBUS_MPRIS_ROOT_INTERFACE, "Quit",         Quit );
+    METHOD_MAPPING_END
 }
 
+#undef METHOD_MAPPING_BEGIN
 #undef METHOD_FUNC
+#undef METHOD_MAPPING_END
index 43724cf..c23772f 100644 (file)
 
 #include "dbus_common.h"
 
-/* MPRIS VERSION */
-#define DBUS_MPRIS_VERSION_MAJOR     2
-#define DBUS_MPRIS_VERSION_MINOR     0
+#define VLC_IDENTITY _("VLC media player")
 
 /* DBUS IDENTIFIERS */
-#define DBUS_MPRIS_ROOT_INTERFACE    "org.freedesktop.MediaPlayer"
-#define DBUS_MPRIS_ROOT_PATH         "/"
+#define DBUS_MPRIS_ROOT_INTERFACE    "org.mpris.MediaPlayer2"
 
 /* Handle incoming dbus messages */
 DBusHandlerResult handle_root ( DBusConnection *p_conn,
                                 DBusMessage *p_from,
                                 void *p_this );
 
-static const DBusObjectPathVTable dbus_mpris_root_vtable = {
-        NULL, handle_root, /* handler function */
-        NULL, NULL, NULL, NULL
+static const char* ppsz_supported_uri_schemes[] = {
+    "file", "http", "https", "rtsp", "realrtsp", "pnm", "ftp", "mtp", "smb",
+    "mms", "mmsu", "mmst", "mmsh", "unsv", "itpc", "icyx", "rtmp", "rtp",
+    "dccp", "dvd", "vcd", "vcdx"
 };
 
+static const char* ppsz_supported_mime_types[] = {
+    "audio/mpeg", "audio/x-mpeg",
+    "video/mpeg", "video/x-mpeg",
+    "video/mpeg-system", "video/x-mpeg-system",
+    "video/mp4",
+    "audio/mp4",
+    "video/x-msvideo",
+    "video/quicktime",
+    "application/ogg", "application/x-ogg",
+    "video/x-ms-asf",  "video/x-ms-asf-plugin",
+    "application/x-mplayer2",
+    "video/x-ms-wmv",
+    "video/x-google-vlc-plugin",
+    "audio/wav", "audio/x-wav",
+    "audio/3gpp",
+    "video/3gpp",
+    "audio/3gpp2",
+    "video/3gpp2",
+    "video/divx",
+    "video/flv", "video/x-flv",
+    "video/x-matroska",
+    "audio/x-matroska",
+    "application/xspf+xml"
+};
+
+void UpdateRootCaps( intf_thread_t *p_intf );
+
 #endif //dbus-root.h
index 311b2d6..a945e0d 100644 (file)
 #include "dbus_tracklist.h"
 #include "dbus_common.h"
 
-
-const char* psz_tracklist_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=\"AddTrack\">\n"
-"      <arg type=\"s\" direction=\"in\" />\n"
-"      <arg type=\"b\" direction=\"in\" />\n"
-"      <arg type=\"i\" direction=\"out\" />\n"
-"    </method>\n"
-"    <method name=\"DelTrack\">\n"
-"      <arg type=\"i\" direction=\"in\" />\n"
-"    </method>\n"
-"    <method name=\"GetMetadata\">\n"
-"      <arg type=\"i\" direction=\"in\" />\n"
-"      <arg type=\"a{sv}\" direction=\"out\" />\n"
-"    </method>\n"
-"    <method name=\"GetCurrentTrack\">\n"
-"      <arg type=\"i\" direction=\"out\" />\n"
-"    </method>\n"
-"    <method name=\"GetLength\">\n"
-"      <arg type=#include <vlc_common.h>\"i\" direction=\"out\" />\n"
-"    </method>\n"
-"    <method name=\"SetLoop\">\n"
-"      <arg type=\"b\" direction=\"in\" />\n"
-"    </method>\n"
-"    <method name=\"SetRandom\">\n"
-"      <arg type=\"b\" direction=\"in\" />\n"
-"    </method>\n"
-"    <signal name=\"TrackListChange\">\n"
-"      <arg type=\"i\" />\n"
-"    </signal>\n"
-"  </interface>\n"
-"</node>\n"
-;
-
 DBUS_METHOD( AddTrack )
 { /* add the string to the playlist, and play it if the boolean is true */
     REPLY_INIT;
@@ -279,15 +237,6 @@ DBUS_SIGNAL( TrackListChangeSignal )
     SIGNAL_SEND;
 }
 
-DBUS_METHOD( handle_introspect_tracklist )
-{
-    VLC_UNUSED(p_this);
-    REPLY_INIT;
-    OUT_ARGUMENTS;
-    ADD_STRING( &psz_tracklist_introspection_xml );
-    REPLY_SEND;
-}
-
 #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 )
@@ -295,9 +244,11 @@ DBUS_METHOD( handle_introspect_tracklist )
 DBusHandlerResult
 handle_tracklist ( DBusConnection *p_conn, DBusMessage *p_from, void *p_this )
 {
-    if( dbus_message_is_method_call( p_from,
-                DBUS_INTERFACE_INTROSPECTABLE, "Introspect" ) )
-    return handle_introspect_tracklist( 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 */
 
@@ -339,7 +290,6 @@ int TrackListChangeEmit( intf_thread_t *p_intf, int signal, int i_node )
     if( p_intf->p_sys->b_dead )
         return VLC_SUCCESS;
 
-    UpdateCaps( p_intf );
     TrackListChangeSignal( p_intf->p_sys->p_conn, p_intf );
     return VLC_SUCCESS;
 }
index d8d5576..a97e30d 100644 (file)
@@ -31,8 +31,8 @@
 #include <vlc_interface.h>
 #include "dbus_common.h"
 
-#define DBUS_MPRIS_TRACKLIST_INTERFACE    "org.freedesktop.MediaPlayer"
-#define DBUS_MPRIS_TRACKLIST_PATH         "/TrackList"
+#define DBUS_MPRIS_TRACKLIST_INTERFACE    "org.mpris.MediaPlayer.TrackList"
+#define DBUS_MPRIS_TRACKLIST_PATH         "/org/mpris/MediaPlayer/TrackList"
 
 /* Handle incoming dbus messages */
 DBusHandlerResult handle_tracklist ( DBusConnection *p_conn,