+/*****************************************************************************
+ * UpdateCaps: update p_sys->i_caps
+ ****************************************************************************/
+static int UpdateCaps( intf_thread_t* p_intf, bool b_playlist_locked )
+{
+ intf_sys_t* p_sys = p_intf->p_sys;
+ dbus_int32_t i_caps = CAPS_CAN_HAS_TRACKLIST;
+ playlist_t* p_playlist = pl_Yield( p_intf );
+ if( !b_playlist_locked ) PL_LOCK;
+
+ if( p_playlist->current.i_size > 0 )
+ i_caps |= CAPS_CAN_PLAY | CAPS_CAN_GO_PREV | CAPS_CAN_GO_NEXT;
+
+ if( p_playlist->p_input )
+ {
+ /* XXX: if UpdateCaps() is called too early, these are
+ * unconditionnaly true */
+ if( var_GetBool( p_playlist->p_input, "can-pause" ) )
+ i_caps |= CAPS_CAN_PAUSE;
+ if( var_GetBool( p_playlist->p_input, "seekable" ) )
+ i_caps |= CAPS_CAN_SEEK;
+ }
+
+ if( !b_playlist_locked ) PL_UNLOCK;
+ pl_Release( p_intf );
+
+ 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;
+ CapsChangeSignal( p_intf->p_sys->p_conn, (vlc_object_t*)p_intf );
+ }
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * GetInputMeta: Fill a DBusMessage with the given input item metadata
+ *****************************************************************************/
+
+#define ADD_META( entry, type, data ) \
+ if( data ) { \
+ dbus_message_iter_open_container( &dict, DBUS_TYPE_DICT_ENTRY, \
+ NULL, &dict_entry ); \
+ dbus_message_iter_append_basic( &dict_entry, DBUS_TYPE_STRING, \
+ &ppsz_meta_items[entry] ); \
+ dbus_message_iter_open_container( &dict_entry, DBUS_TYPE_VARIANT, \
+ type##_AS_STRING, &variant ); \
+ dbus_message_iter_append_basic( &variant, \
+ type, \
+ & data ); \
+ dbus_message_iter_close_container( &dict_entry, &variant ); \
+ dbus_message_iter_close_container( &dict, &dict_entry ); }
+
+#define ADD_VLC_META_STRING( entry, item ) \
+ { \
+ char * psz = input_item_Get##item( p_input );\
+ ADD_META( entry, DBUS_TYPE_STRING, \
+ psz ); \
+ free( psz ); \
+ }
+
+static int GetInputMeta( input_item_t* p_input,
+ DBusMessageIter *args )
+{
+ DBusMessageIter dict, dict_entry, variant;
+ /* We need the track length to be expressed in milli-seconds
+ * instead of µ-seconds */
+ dbus_int64_t i_length = ( input_item_GetDuration( p_input ) / 1000 );
+
+ const char* ppsz_meta_items[] =
+ {
+ "title", "artist", "genre", "copyright", "album", "tracknum",
+ "description", "rating", "date", "setting", "url", "language",
+ "nowplaying", "publisher", "encodedby", "arturl", "trackid",
+ "status", "location", "length", "video-codec", "audio-codec",
+ "video-bitrate", "audio-bitrate", "audio-samplerate"
+ };
+
+ dbus_message_iter_open_container( args, DBUS_TYPE_ARRAY, "{sv}", &dict );
+
+ ADD_VLC_META_STRING( 0, Title );
+ ADD_VLC_META_STRING( 1, Artist );
+ ADD_VLC_META_STRING( 2, Genre );
+ ADD_VLC_META_STRING( 3, Copyright );
+ ADD_VLC_META_STRING( 4, Album );
+ ADD_VLC_META_STRING( 5, TrackNum );
+ ADD_VLC_META_STRING( 6, Description );
+ ADD_VLC_META_STRING( 7, Rating );
+ ADD_VLC_META_STRING( 8, Date );
+ ADD_VLC_META_STRING( 9, Setting );
+ ADD_VLC_META_STRING( 10, URL );
+ ADD_VLC_META_STRING( 11, Language );
+ ADD_VLC_META_STRING( 12, NowPlaying );
+ ADD_VLC_META_STRING( 13, Publisher );
+ ADD_VLC_META_STRING( 14, EncodedBy );
+ ADD_VLC_META_STRING( 15, ArtURL );
+ ADD_VLC_META_STRING( 16, TrackID );
+
+ vlc_mutex_lock( &p_input->lock );
+ if( p_input->p_meta )
+ ADD_META( 17, DBUS_TYPE_INT32, p_input->p_meta->i_status );
+ vlc_mutex_unlock( &p_input->lock );
+
+ ADD_VLC_META_STRING( 18, URI );
+ ADD_META( 19, DBUS_TYPE_INT64, i_length );
+
+ dbus_message_iter_close_container( args, &dict );
+ return VLC_SUCCESS;
+}
+
+#undef ADD_META
+#undef ADD_VLC_META_STRING
+
+/*****************************************************************************
+ * MarshalStatus: Fill a DBusMessage with the current player status
+ *****************************************************************************/
+
+static int MarshalStatus( intf_thread_t* p_intf, DBusMessageIter* args,
+ bool lock )
+{ /* 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;
+ vlc_value_t val;
+ playlist_t* p_playlist = NULL;
+ input_thread_t* p_input = NULL;
+
+ p_playlist = pl_Yield( p_intf );
+ if( lock )
+ PL_LOCK;
+
+ i_state = 2;
+
+ p_input = p_playlist->p_input;
+ if( p_input )
+ {
+ var_Get( p_input, "state", &val );
+ if( val.i_int >= END_S )
+ i_state = 2;
+ else if( val.i_int == PAUSE_S )
+ i_state = 1;
+ else if( val.i_int <= PLAYING_S )
+ i_state = 0;
+ }
+
+ i_random = var_CreateGetBool( p_playlist, "random" );
+
+ i_repeat = var_CreateGetBool( p_playlist, "repeat" );
+
+ i_loop = var_CreateGetBool( p_playlist, "loop" );
+
+ if( lock )
+ PL_UNLOCK;
+ pl_Release( p_intf );
+
+ 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 );
+
+ return VLC_SUCCESS;
+}