Commit 79a45df7 authored by Mirsal Ennaime's avatar Mirsal Ennaime Committed by Jean-Baptiste Kempf

Reorganize the dbus control module code

 * Split the module source code into several files

Functionality is unchanged, but the result is more maintainable.
Signed-off-by: default avatarJean-Baptiste Kempf <jb@videolan.org>
parent 597e38cb
...@@ -4746,6 +4746,7 @@ AC_CONFIG_FILES([ ...@@ -4746,6 +4746,7 @@ AC_CONFIG_FILES([
modules/codec/wmafixed/Makefile modules/codec/wmafixed/Makefile
modules/control/Makefile modules/control/Makefile
modules/control/http/Makefile modules/control/http/Makefile
modules/control/dbus/Makefile
modules/control/globalhotkeys/Makefile modules/control/globalhotkeys/Makefile
modules/demux/Makefile modules/demux/Makefile
modules/demux/asf/Makefile modules/demux/asf/Makefile
......
SUBDIRS = http globalhotkeys SUBDIRS = http globalhotkeys dbus
SOURCES_gestures = gestures.c SOURCES_gestures = gestures.c
SOURCES_netsync = netsync.c SOURCES_netsync = netsync.c
SOURCES_ntservice = ntservice.c SOURCES_ntservice = ntservice.c
SOURCES_hotkeys = hotkeys.c SOURCES_hotkeys = hotkeys.c
SOURCES_lirc = lirc.c SOURCES_lirc = lirc.c
SOURCES_oldrc = rc.c SOURCES_oldrc = rc.c
SOURCES_dbus = dbus.c dbus.h
if HAVE_DARWIN if HAVE_DARWIN
motion_extra = unimotion.c unimotion.h motion_extra = unimotion.c unimotion.h
else else
......
SOURCES_dbus = \
dbus.c \
dbus.h \
dbus_common.h \
dbus_root.h \
dbus_root.c \
dbus_player.h \
dbus_player.c \
dbus_tracklist.h \
dbus_tracklist.c \
$(NULL)
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* dbus.c : D-Bus control interface * dbus.c : D-Bus control interface
***************************************************************************** *****************************************************************************
* Copyright © 2006-2008 Rafaël Carré * Copyright © 2006-2008 Rafaël Carré
* Copyright © 2007-2008 Mirsal Ennaime * Copyright © 2007-2010 Mirsal Ennaime
* Copyright © 2009 The VideoLAN team * Copyright © 2009-2010 The VideoLAN team
* $Id$ * $Id$
* *
* Authors: Rafaël Carré <funman at videolanorg> * Authors: Rafaël Carré <funman at videolanorg>
...@@ -46,16 +46,17 @@ ...@@ -46,16 +46,17 @@
#include <dbus/dbus.h> #include <dbus/dbus.h>
#include "dbus.h" #include "dbus.h"
#include "dbus_common.h"
#include "dbus_root.h"
#include "dbus_player.h"
#include "dbus_tracklist.h"
#include <vlc_common.h> #include <vlc_common.h>
#include <vlc_plugin.h> #include <vlc_plugin.h>
#include <vlc_aout.h>
#include <vlc_interface.h> #include <vlc_interface.h>
#include <vlc_playlist.h> #include <vlc_playlist.h>
#include <vlc_meta.h> #include <vlc_meta.h>
#include <math.h>
#include <assert.h> #include <assert.h>
/***************************************************************************** /*****************************************************************************
...@@ -68,54 +69,8 @@ static void Run ( intf_thread_t * ); ...@@ -68,54 +69,8 @@ static void Run ( intf_thread_t * );
static int StateChange( intf_thread_t *, int ); static int StateChange( intf_thread_t *, int );
static int TrackChange( intf_thread_t * ); static int TrackChange( intf_thread_t * );
static int StatusChangeEmit( intf_thread_t *);
static int TrackListChangeEmit( intf_thread_t *, int, int );
static int AllCallback( vlc_object_t*, const char*, vlc_value_t, vlc_value_t, void* ); static int AllCallback( vlc_object_t*, const char*, vlc_value_t, vlc_value_t, void* );
static int GetInputMeta ( input_item_t *, DBusMessageIter * );
static int MarshalStatus ( intf_thread_t *, DBusMessageIter * );
static int UpdateCaps( intf_thread_t* );
/* GetCaps() 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
};
// The signal that can be get from the callbacks
enum
{
SIGNAL_ITEM_CURRENT,
SIGNAL_INTF_CHANGE,
SIGNAL_PLAYLIST_ITEM_APPEND,
SIGNAL_PLAYLIST_ITEM_DELETED,
SIGNAL_RANDOM,
SIGNAL_REPEAT,
SIGNAL_LOOP,
SIGNAL_STATE
};
struct intf_sys_t
{
DBusConnection *p_conn;
playlist_t *p_playlist;
bool b_meta_read;
dbus_int32_t i_caps;
bool b_dead;
vlc_array_t *p_events;
vlc_mutex_t lock;
input_thread_t *p_input;
bool b_unique;
};
typedef struct typedef struct
{ {
int signal; int signal;
...@@ -123,10 +78,6 @@ typedef struct ...@@ -123,10 +78,6 @@ typedef struct
int i_input_state; int i_input_state;
} callback_info_t; } callback_info_t;
#define INTF ((intf_thread_t *)p_this)
#define PL (INTF->p_sys->p_playlist)
/***************************************************************************** /*****************************************************************************
* Module descriptor * Module descriptor
*****************************************************************************/ *****************************************************************************/
...@@ -146,554 +97,6 @@ vlc_module_begin () ...@@ -146,554 +97,6 @@ vlc_module_begin ()
DBUS_UNIQUE_TEXT, DBUS_UNIQUE_LONGTEXT, true ) DBUS_UNIQUE_TEXT, DBUS_UNIQUE_LONGTEXT, true )
vlc_module_end () vlc_module_end ()
/*****************************************************************************
* Methods
*****************************************************************************/
/* Player */
DBUS_METHOD( Quit )
{ /* exits vlc */
REPLY_INIT;
libvlc_Quit(INTF->p_libvlc);
REPLY_SEND;
}
DBUS_METHOD( MprisVersion )
{ /*implemented version of the mpris spec */
REPLY_INIT;
OUT_ARGUMENTS;
VLC_UNUSED( p_this );
dbus_uint16_t i_major = VLC_MPRIS_VERSION_MAJOR;
dbus_uint16_t i_minor = VLC_MPRIS_VERSION_MINOR;
DBusMessageIter version;
if( !dbus_message_iter_open_container( &args, DBUS_TYPE_STRUCT, NULL,
&version ) )
return DBUS_HANDLER_RESULT_NEED_MEMORY;
if( !dbus_message_iter_append_basic( &version, DBUS_TYPE_UINT16,
&i_major ) )
return DBUS_HANDLER_RESULT_NEED_MEMORY;
if( !dbus_message_iter_append_basic( &version, DBUS_TYPE_UINT16,
&i_minor ) )
return DBUS_HANDLER_RESULT_NEED_MEMORY;
if( !dbus_message_iter_close_container( &args, &version ) )
return DBUS_HANDLER_RESULT_NEED_MEMORY;
REPLY_SEND;
}
DBUS_METHOD( PositionGet )
{ /* returns position in milliseconds */
REPLY_INIT;
OUT_ARGUMENTS;
dbus_int32_t i_pos;
input_thread_t *p_input = playlist_CurrentInput( PL );
if( !p_input )
i_pos = 0;
else
{
i_pos = var_GetTime( p_input, "time" ) / 1000;
vlc_object_release( p_input );
}
ADD_INT32( &i_pos );
REPLY_SEND;
}
DBUS_METHOD( PositionSet )
{ /* set position in milliseconds */
REPLY_INIT;
vlc_value_t position;
dbus_int32_t i_pos;
DBusError error;
dbus_error_init( &error );
dbus_message_get_args( p_from, &error,
DBUS_TYPE_INT32, &i_pos,
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;
}
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 );
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 */
REPLY_INIT;
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_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;
}
double f_vol = AOUT_VOLUME_MAX * i_dbus_vol / 100.;
i_vol = round( f_vol );
aout_VolumeSet( PL, i_vol );
REPLY_SEND;
}
DBUS_METHOD( Next )
{ /* next playlist item */
REPLY_INIT;
playlist_Next( PL );
REPLY_SEND;
}
DBUS_METHOD( Prev )
{ /* previous playlist item */
REPLY_INIT;
playlist_Prev( PL );
REPLY_SEND;
}
DBUS_METHOD( Stop )
{ /* stop playing */
REPLY_INIT;
playlist_Stop( PL );
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 *
*/
REPLY_INIT;
OUT_ARGUMENTS;
MarshalStatus( p_this, &args );
REPLY_SEND;
}
DBUS_METHOD( Pause )
{
REPLY_INIT;
playlist_Pause( PL );
REPLY_SEND;
}
DBUS_METHOD( Play )
{
REPLY_INIT;
input_thread_t *p_input = playlist_CurrentInput( 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( GetCurrentMetadata )
{
REPLY_INIT;
OUT_ARGUMENTS;
playlist_t *p_playlist = PL;
PL_LOCK;
playlist_item_t* p_item = playlist_CurrentPlayingItem( p_playlist );
if( p_item )
GetInputMeta( p_item->p_input, &args );
PL_UNLOCK;
REPLY_SEND;
}
DBUS_METHOD( GetCaps )
{
REPLY_INIT;
OUT_ARGUMENTS;
ADD_INT32( &INTF->p_sys->i_caps );
REPLY_SEND;
}
/* Media Player information */
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
return DBUS_HANDLER_RESULT_NEED_MEMORY;
REPLY_SEND;
}
/* TrackList */
DBUS_METHOD( AddTrack )
{ /* add the string to the playlist, and play it if the boolean is true */
REPLY_INIT;
OUT_ARGUMENTS;
DBusError error;
dbus_error_init( &error );
char *psz_mrl;
dbus_bool_t b_play;
dbus_message_get_args( p_from, &error,
DBUS_TYPE_STRING, &psz_mrl,
DBUS_TYPE_BOOLEAN, &b_play,
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;
}
playlist_Add( PL, psz_mrl, NULL, PLAYLIST_APPEND |
( ( b_play == TRUE ) ? PLAYLIST_GO : 0 ) ,
PLAYLIST_END, true, false );
dbus_int32_t i_success = 0;
ADD_INT32( &i_success );
REPLY_SEND;
}
DBUS_METHOD( GetCurrentTrack )
{
REPLY_INIT;
OUT_ARGUMENTS;
playlist_t *p_playlist = PL;
PL_LOCK;
dbus_int32_t i_position = PL->i_current_index;
PL_UNLOCK;
ADD_INT32( &i_position );
REPLY_SEND;
}
DBUS_METHOD( GetMetadata )
{
REPLY_INIT;
OUT_ARGUMENTS;
DBusError error;
dbus_error_init( &error );
dbus_int32_t i_position;
playlist_t *p_playlist = PL;
dbus_message_get_args( p_from, &error,
DBUS_TYPE_INT32, &i_position,
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;
}
PL_LOCK;
if( i_position < p_playlist->current.i_size )
{
GetInputMeta( p_playlist->current.p_elems[i_position]->p_input, &args );
}
PL_UNLOCK;
REPLY_SEND;
}
DBUS_METHOD( GetLength )
{
REPLY_INIT;
OUT_ARGUMENTS;
playlist_t *p_playlist = PL;
PL_LOCK;
dbus_int32_t i_elements = PL->current.i_size;
PL_UNLOCK;
ADD_INT32( &i_elements );
REPLY_SEND;
}
DBUS_METHOD( DelTrack )
{
REPLY_INIT;
DBusError error;
dbus_error_init( &error );
dbus_int32_t i_position;
playlist_t *p_playlist = PL;
dbus_message_get_args( p_from, &error,
DBUS_TYPE_INT32, &i_position,
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;
}
PL_LOCK;
if( i_position < p_playlist->current.i_size )
{
playlist_DeleteFromInput( p_playlist,
p_playlist->current.p_elems[i_position]->p_input,
pl_Locked );
}
PL_UNLOCK;
REPLY_SEND;
}
DBUS_METHOD( SetLoop )
{
REPLY_INIT;
OUT_ARGUMENTS;
DBusError error;
dbus_bool_t b_loop;
dbus_error_init( &error );
dbus_message_get_args( p_from, &error,
DBUS_TYPE_BOOLEAN, &b_loop,
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;
}
var_SetBool( PL, "loop", ( b_loop == TRUE ) );
REPLY_SEND;
}
DBUS_METHOD( Repeat )
{
REPLY_INIT;
OUT_ARGUMENTS;
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_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;
}
var_SetBool( PL, "repeat", ( b_repeat == TRUE ) );
REPLY_SEND;
}
DBUS_METHOD( SetRandom )
{
REPLY_INIT;
OUT_ARGUMENTS;
DBusError error;
dbus_bool_t b_random;
dbus_error_init( &error );
dbus_message_get_args( p_from, &error,
DBUS_TYPE_BOOLEAN, &b_random,
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;
}
var_SetBool( PL, "random", ( b_random == TRUE ) );
REPLY_SEND;
}
/*****************************************************************************
* Introspection method
*****************************************************************************/
DBUS_METHOD( handle_introspect_root )
{ /* handles introspection of root object */
VLC_UNUSED(p_this);
REPLY_INIT;
OUT_ARGUMENTS;
ADD_STRING( &psz_introspection_xml_data_root );
REPLY_SEND;
}
DBUS_METHOD( handle_introspect_player )
{
VLC_UNUSED(p_this);
REPLY_INIT;
OUT_ARGUMENTS;
ADD_STRING( &psz_introspection_xml_data_player );
REPLY_SEND;
}
DBUS_METHOD( handle_introspect_tracklist )
{
VLC_UNUSED(p_this);
REPLY_INIT;
OUT_ARGUMENTS;
ADD_STRING( &psz_introspection_xml_data_tracklist );
REPLY_SEND;
}
/*****************************************************************************
* handle_*: answer to incoming messages
*****************************************************************************/
#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 )
DBUS_METHOD( handle_root )
{
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's names are associated to an handler */
METHOD_FUNC( MPRIS_DBUS_ROOT_INTERFACE, "Identity", Identity );
METHOD_FUNC( MPRIS_DBUS_ROOT_INTERFACE, "MprisVersion", MprisVersion );
METHOD_FUNC( MPRIS_DBUS_ROOT_INTERFACE, "Quit", Quit );
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
DBUS_METHOD( handle_player )
{
if( dbus_message_is_method_call( p_from,
DBUS_INTERFACE_INTROSPECTABLE, "Introspect" ) )
return handle_introspect_player( p_conn, p_from, p_this );
/* here D-Bus method's names are associated to an handler */
METHOD_FUNC( MPRIS_DBUS_PLAYER_INTERFACE, "Prev", Prev );
METHOD_FUNC( MPRIS_DBUS_PLAYER_INTERFACE, "Next", Next );
METHOD_FUNC( MPRIS_DBUS_PLAYER_INTERFACE, "Stop", Stop );
METHOD_FUNC( MPRIS_DBUS_PLAYER_INTERFACE, "Play", Play );
METHOD_FUNC( MPRIS_DBUS_PLAYER_INTERFACE, "Pause", Pause );
METHOD_FUNC( MPRIS_DBUS_PLAYER_INTERFACE, "Repeat", Repeat );
METHOD_FUNC( MPRIS_DBUS_PLAYER_INTERFACE, "VolumeSet", VolumeSet );
METHOD_FUNC( MPRIS_DBUS_PLAYER_INTERFACE, "VolumeGet", VolumeGet );
METHOD_FUNC( MPRIS_DBUS_PLAYER_INTERFACE, "PositionSet", PositionSet );
METHOD_FUNC( MPRIS_DBUS_PLAYER_INTERFACE, "PositionGet", PositionGet );
METHOD_FUNC( MPRIS_DBUS_PLAYER_INTERFACE, "GetStatus", GetStatus );
METHOD_FUNC( MPRIS_DBUS_PLAYER_INTERFACE, "GetMetadata", GetCurrentMetadata );
METHOD_FUNC( MPRIS_DBUS_PLAYER_INTERFACE, "GetCaps", GetCaps );
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
DBUS_METHOD( handle_tracklist )
{
if( dbus_message_is_method_call( p_from,
DBUS_INTERFACE_INTROSPECTABLE, "Introspect" ) )
return handle_introspect_tracklist( p_conn, p_from, p_this );
/* here D-Bus method's names are associated to an handler */
METHOD_FUNC( MPRIS_DBUS_TRACKLIST_INTERFACE, "GetMetadata", GetMetadata );
METHOD_FUNC( MPRIS_DBUS_TRACKLIST_INTERFACE, "GetCurrentTrack", GetCurrentTrack );
METHOD_FUNC( MPRIS_DBUS_TRACKLIST_INTERFACE, "GetLength", GetLength );
METHOD_FUNC( MPRIS_DBUS_TRACKLIST_INTERFACE, "AddTrack", AddTrack );
METHOD_FUNC( MPRIS_DBUS_TRACKLIST_INTERFACE, "DelTrack", DelTrack );
METHOD_FUNC( MPRIS_DBUS_TRACKLIST_INTERFACE, "SetLoop", SetLoop );
METHOD_FUNC( MPRIS_DBUS_TRACKLIST_INTERFACE, "SetRandom", SetRandom );
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
/***************************************************************************** /*****************************************************************************
* Open: initialize interface * Open: initialize interface
*****************************************************************************/ *****************************************************************************/
...@@ -719,7 +122,7 @@ static int Open( vlc_object_t *p_this ) ...@@ -719,7 +122,7 @@ static int Open( vlc_object_t *p_this )
if( p_sys->b_unique ) if( p_sys->b_unique )
{ {
if( asprintf( &psz_service_name, "%s-%d", if( asprintf( &psz_service_name, "%s-%d",
VLC_MPRIS_DBUS_SERVICE, getpid() ) < 0 ) DBUS_MPRIS_BUS_NAME, getpid() ) < 0 )
{ {
free( p_sys ); free( p_sys );
return VLC_ENOMEM; return VLC_ENOMEM;
...@@ -727,7 +130,7 @@ static int Open( vlc_object_t *p_this ) ...@@ -727,7 +130,7 @@ static int Open( vlc_object_t *p_this )
} }
else else
{ {
psz_service_name = strdup(VLC_MPRIS_DBUS_SERVICE); psz_service_name = strdup(DBUS_MPRIS_BUS_NAME);
} }
dbus_error_init( &error ); dbus_error_init( &error );
...@@ -758,12 +161,12 @@ static int Open( vlc_object_t *p_this ) ...@@ -758,12 +161,12 @@ static int Open( vlc_object_t *p_this )
free( psz_service_name ); free( psz_service_name );
/* we register the objects */ /* we register the objects */
dbus_connection_register_object_path( p_conn, MPRIS_DBUS_ROOT_PATH, dbus_connection_register_object_path( p_conn, DBUS_MPRIS_ROOT_PATH,
&vlc_dbus_root_vtable, p_this ); &dbus_mpris_root_vtable, p_this );
dbus_connection_register_object_path( p_conn, MPRIS_DBUS_PLAYER_PATH, dbus_connection_register_object_path( p_conn, DBUS_MPRIS_PLAYER_PATH,
&vlc_dbus_player_vtable, p_this ); &dbus_mpris_player_vtable, p_this );
dbus_connection_register_object_path( p_conn, MPRIS_DBUS_TRACKLIST_PATH, dbus_connection_register_object_path( p_conn, DBUS_MPRIS_TRACKLIST_PATH,
&vlc_dbus_tracklist_vtable, p_this ); &dbus_mpris_tracklist_vtable, p_this );
dbus_connection_flush( p_conn ); dbus_connection_flush( p_conn );
...@@ -888,6 +291,44 @@ static void Run ( intf_thread_t *p_intf ) ...@@ -888,6 +291,44 @@ static void Run ( intf_thread_t *p_intf )
} }
} }
/*****************************************************************************
* 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;
}
// Get all the callbacks // Get all the callbacks
static int AllCallback( vlc_object_t *p_this, const char *psz_var, static int AllCallback( vlc_object_t *p_this, const char *psz_var,
...@@ -934,109 +375,6 @@ static int AllCallback( vlc_object_t *p_this, const char *psz_var, ...@@ -934,109 +375,6 @@ static int AllCallback( vlc_object_t *p_this, const char *psz_var,
return VLC_SUCCESS; return VLC_SUCCESS;
} }
/******************************************************************************
* CapsChange: player capabilities change signal
*****************************************************************************/
DBUS_SIGNAL( CapsChangeSignal )
{
SIGNAL_INIT( MPRIS_DBUS_PLAYER_INTERFACE,
MPRIS_DBUS_PLAYER_PATH,
"CapsChange" );
OUT_ARGUMENTS;
ADD_INT32( &((intf_thread_t*)p_data)->p_sys->i_caps );
SIGNAL_SEND;
}
/******************************************************************************
* TrackListChange: tracklist order / length change signal
*****************************************************************************/
DBUS_SIGNAL( TrackListChangeSignal )
{ /* emit the new tracklist lengh */
SIGNAL_INIT( MPRIS_DBUS_TRACKLIST_INTERFACE,
MPRIS_DBUS_TRACKLIST_PATH,
"TrackListChange");
OUT_ARGUMENTS;
playlist_t *p_playlist = ((intf_thread_t*)p_data)->p_sys->p_playlist;
PL_LOCK;
dbus_int32_t i_elements = p_playlist->current.i_size;
PL_UNLOCK;
ADD_INT32( &i_elements );
SIGNAL_SEND;
}
/*****************************************************************************
* TrackListChangeEmit: Emits the TrackListChange signal
*****************************************************************************/
/* FIXME: It is not called on tracklist reordering */
static int TrackListChangeEmit( intf_thread_t *p_intf, int signal, int i_node )
{
// "playlist-item-append"
if( signal == SIGNAL_PLAYLIST_ITEM_APPEND )
{
/* don't signal when items are added/removed in p_category */
playlist_t *p_playlist = p_intf->p_sys->p_playlist;
PL_LOCK;
playlist_item_t *p_item = playlist_ItemGetById( p_playlist, i_node );
assert( p_item );
while( p_item->p_parent )
p_item = p_item->p_parent;
if( p_item == p_playlist->p_root_category )
{
PL_UNLOCK;
return VLC_SUCCESS;
}
PL_UNLOCK;
}
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;
}
/*****************************************************************************
* TrackChange: Playlist item change callback
*****************************************************************************/
DBUS_SIGNAL( TrackChangeSignal )
{ /* emit the metadata of the new item */
SIGNAL_INIT( MPRIS_DBUS_PLAYER_INTERFACE,
MPRIS_DBUS_PLAYER_PATH,
"TrackChange" );
OUT_ARGUMENTS;
input_item_t *p_item = (input_item_t*) p_data;
GetInputMeta ( p_item, &args );
SIGNAL_SEND;
}
/*****************************************************************************
* StatusChange: Player status change signal
*****************************************************************************/
DBUS_SIGNAL( StatusChangeSignal )
{ /* send the updated status info on the bus */
SIGNAL_INIT( MPRIS_DBUS_PLAYER_INTERFACE,
MPRIS_DBUS_PLAYER_PATH,
"StatusChange" );
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 );
SIGNAL_SEND;
}
/***************************************************************************** /*****************************************************************************
* StateChange: callback on input "state" * StateChange: callback on input "state"
*****************************************************************************/ *****************************************************************************/
...@@ -1063,7 +401,7 @@ static int StateChange( intf_thread_t *p_intf, int i_input_state ) ...@@ -1063,7 +401,7 @@ static int StateChange( intf_thread_t *p_intf, int i_input_state )
if( p_item ) if( p_item )
{ {
p_sys->b_meta_read = true; p_sys->b_meta_read = true;
TrackChangeSignal( p_sys->p_conn, p_item ); TrackChangeEmit( p_intf, p_item );
} }
vlc_object_release( p_input ); vlc_object_release( p_input );
} }
...@@ -1072,25 +410,12 @@ static int StateChange( intf_thread_t *p_intf, int i_input_state ) ...@@ -1072,25 +410,12 @@ static int StateChange( intf_thread_t *p_intf, int i_input_state )
if( i_input_state == PLAYING_S || i_input_state == PAUSE_S || if( i_input_state == PLAYING_S || i_input_state == PAUSE_S ||
i_input_state == END_S ) i_input_state == END_S )
{ {
StatusChangeSignal( p_sys->p_conn, p_intf ); StatusChangeEmit( p_intf );
} }
return VLC_SUCCESS; return VLC_SUCCESS;
} }
/*****************************************************************************
* StatusChangeEmit: Emits the StatusChange signal
*****************************************************************************/
static int StatusChangeEmit( 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 );
return VLC_SUCCESS;
}
/***************************************************************************** /*****************************************************************************
* TrackChange: callback on playlist "item-current" * TrackChange: callback on playlist "item-current"
*****************************************************************************/ *****************************************************************************/
...@@ -1129,7 +454,7 @@ static int TrackChange( intf_thread_t *p_intf ) ...@@ -1129,7 +454,7 @@ static int TrackChange( intf_thread_t *p_intf )
if( input_item_IsPreparsed( p_item ) ) if( input_item_IsPreparsed( p_item ) )
{ {
p_sys->b_meta_read = true; p_sys->b_meta_read = true;
TrackChangeSignal( p_sys->p_conn, p_item ); TrackChangeEmit( p_intf, p_item );
} }
p_sys->p_input = p_input; p_sys->p_input = p_input;
...@@ -1138,45 +463,6 @@ static int TrackChange( intf_thread_t *p_intf ) ...@@ -1138,45 +463,6 @@ static int TrackChange( intf_thread_t *p_intf )
return VLC_SUCCESS; return VLC_SUCCESS;
} }
/*****************************************************************************
* UpdateCaps: update p_sys->i_caps
* This function have to be called with the playlist unlocked
****************************************************************************/
static 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;
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 * GetInputMeta: Fill a DBusMessage with the given input item metadata
*****************************************************************************/ *****************************************************************************/
...@@ -1203,7 +489,7 @@ static int UpdateCaps( intf_thread_t* p_intf ) ...@@ -1203,7 +489,7 @@ static int UpdateCaps( intf_thread_t* p_intf )
free( psz ); \ free( psz ); \
} }
static int GetInputMeta( input_item_t* p_input, int GetInputMeta( input_item_t* p_input,
DBusMessageIter *args ) DBusMessageIter *args )
{ {
DBusMessageIter dict, dict_entry, variant; DBusMessageIter dict, dict_entry, variant;
...@@ -1265,48 +551,4 @@ static int GetInputMeta( input_item_t* p_input, ...@@ -1265,48 +551,4 @@ static int GetInputMeta( input_item_t* p_input,
#undef ADD_META #undef ADD_META
#undef ADD_VLC_META_STRING #undef ADD_VLC_META_STRING
/*****************************************************************************
* 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;
int i_val;
playlist_t* p_playlist = p_intf->p_sys->p_playlist;
input_thread_t* p_input = NULL;
i_state = 2;
p_input = playlist_CurrentInput( p_playlist );
if( p_input )
{
i_val = var_GetInteger( p_input, "state" );
if( i_val >= END_S )
i_state = 2;
else if( i_val == PAUSE_S )
i_state = 1;
else if( i_val <= PLAYING_S )
i_state = 0;
vlc_object_release( p_input );
}
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 );
return VLC_SUCCESS;
}
/*****************************************************************************
* dbus.h : D-Bus control interface
*****************************************************************************
* Copyright © 2006-2008 Rafaël Carré
* Copyright © 2007-2010 Mirsal Ennaime
* Copyright © 2009-2010 The VideoLAN team
* $Id$
*
* Authors: Rafaël Carré <funman at videolanorg>
* Mirsal ENNAIME <mirsal dot ennaime at gmail dot com>
*
* 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_H
#define _VLC_DBUS_H
#define DBUS_MPRIS_BUS_NAME "org.mpris.vlc"
#endif //dbus.h
/*****************************************************************************
* dbus-common.h : Common header for D-Bus control modules
*****************************************************************************
* Copyright © 2006-2008 Rafaël Carré
* Copyright © 2007-2010 Mirsal Ennaime
* Copyright © 2009-2010 The VideoLAN team
* $Id$
*
* Authors: Mirsal ENNAIME <mirsal dot ennaime at gmail dot com>
*
* 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_COMMON_H
#define _VLC_DBUS_COMMON_H
#include <vlc_common.h>
#include <vlc_interface.h>
#include <dbus/dbus.h>
/* MACROS */
#define INTF ((intf_thread_t *)p_this)
#define PL (INTF->p_sys->p_playlist)
#define DBUS_METHOD( method_function ) \
static DBusHandlerResult method_function \
( DBusConnection *p_conn, DBusMessage *p_from, void *p_this )
#define DBUS_SIGNAL( signal_function ) \
static DBusHandlerResult signal_function \
( DBusConnection *p_conn, void *p_data )
#define REPLY_INIT \
DBusMessage* p_msg = dbus_message_new_method_return( p_from ); \
if( !p_msg ) return DBUS_HANDLER_RESULT_NEED_MEMORY; \
#define REPLY_SEND \
if( !dbus_connection_send( p_conn, p_msg, NULL ) ) \
return DBUS_HANDLER_RESULT_NEED_MEMORY; \
dbus_connection_flush( p_conn ); \
dbus_message_unref( p_msg ); \
return DBUS_HANDLER_RESULT_HANDLED
#define SIGNAL_INIT( interface, path, signal ) \
DBusMessage *p_msg = dbus_message_new_signal( path, \
interface, signal ); \
if( !p_msg ) return DBUS_HANDLER_RESULT_NEED_MEMORY; \
#define SIGNAL_SEND \
if( !dbus_connection_send( p_conn, p_msg, NULL ) ) \
return DBUS_HANDLER_RESULT_NEED_MEMORY; \
dbus_message_unref( p_msg ); \
dbus_connection_flush( p_conn ); \
return DBUS_HANDLER_RESULT_HANDLED
#define OUT_ARGUMENTS \
DBusMessageIter args; \
dbus_message_iter_init_append( p_msg, &args )
#define DBUS_ADD( dbus_type, value ) \
if( !dbus_message_iter_append_basic( &args, dbus_type, value ) ) \
return DBUS_HANDLER_RESULT_NEED_MEMORY
#define ADD_STRING( s ) DBUS_ADD( DBUS_TYPE_STRING, s )
#define ADD_BOOL( b ) DBUS_ADD( DBUS_TYPE_BOOLEAN, b )
#define ADD_INT32( i ) DBUS_ADD( DBUS_TYPE_INT32, i )
#define ADD_BYTE( b ) DBUS_ADD( DBUS_TYPE_BYTE, b )
struct intf_sys_t
{
DBusConnection *p_conn;
playlist_t *p_playlist;
bool b_meta_read;
dbus_int32_t i_caps;
bool b_dead;
vlc_array_t *p_events;
vlc_mutex_t lock;
input_thread_t *p_input;
bool b_unique;
};
enum
{
SIGNAL_ITEM_CURRENT,
SIGNAL_INTF_CHANGE,
SIGNAL_PLAYLIST_ITEM_APPEND,
SIGNAL_PLAYLIST_ITEM_DELETED,
SIGNAL_RANDOM,
SIGNAL_REPEAT,
SIGNAL_LOOP,
SIGNAL_STATE
};
int GetInputMeta ( input_item_t* p_input, DBusMessageIter *args );
int UpdateCaps ( intf_thread_t* );
#endif //dbus-common.h
/*****************************************************************************
* dbus-player.h : dbus control module (mpris v1.0) - /Player object
*****************************************************************************
* Copyright © 2006-2008 Rafaël Carré
* Copyright © 2007-2010 Mirsal Ennaime
* Copyright © 2009-2010 The VideoLAN team
* $Id$
*
* Authors: Mirsal ENNAIME <mirsal dot ennaime at gmail dot com>
*
* 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.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_playlist.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 );
if( !p_input )
i_pos = 0;
else
{
i_pos = var_GetTime( p_input, "time" ) / 1000;
vlc_object_release( p_input );
}
ADD_INT32( &i_pos );
REPLY_SEND;
}
DBUS_METHOD( PositionSet )
{ /* set position in milliseconds */
REPLY_INIT;
vlc_value_t position;
dbus_int32_t i_pos;
DBusError error;
dbus_error_init( &error );
dbus_message_get_args( p_from, &error,
DBUS_TYPE_INT32, &i_pos,
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;
}
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 );
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 */
REPLY_INIT;
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_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;
}
double f_vol = AOUT_VOLUME_MAX * i_dbus_vol / 100.;
i_vol = round( f_vol );
aout_VolumeSet( PL, i_vol );
REPLY_SEND;
}
DBUS_METHOD( Next )
{ /* next playlist item */
REPLY_INIT;
playlist_Next( PL );
REPLY_SEND;
}
DBUS_METHOD( Prev )
{ /* previous playlist item */
REPLY_INIT;
playlist_Prev( PL );
REPLY_SEND;
}
DBUS_METHOD( Stop )
{ /* stop playing */
REPLY_INIT;
playlist_Stop( PL );
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 *
*/
REPLY_INIT;
OUT_ARGUMENTS;
MarshalStatus( p_this, &args );
REPLY_SEND;
}
DBUS_METHOD( Pause )
{
REPLY_INIT;
playlist_Pause( PL );
REPLY_SEND;
}
DBUS_METHOD( Play )
{
REPLY_INIT;
input_thread_t *p_input = playlist_CurrentInput( 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 )
{
REPLY_INIT;
OUT_ARGUMENTS;
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_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;
}
var_SetBool( PL, "repeat", ( b_repeat == TRUE ) );
REPLY_SEND;
}
DBUS_METHOD( GetCurrentMetadata )
{
REPLY_INIT;
OUT_ARGUMENTS;
playlist_t *p_playlist = PL;
PL_LOCK;
playlist_item_t* p_item = playlist_CurrentPlayingItem( p_playlist );
if( p_item )
GetInputMeta( p_item->p_input, &args );
PL_UNLOCK;
REPLY_SEND;
}
DBUS_METHOD( GetCaps )
{
REPLY_INIT;
OUT_ARGUMENTS;
ADD_INT32( &INTF->p_sys->i_caps );
REPLY_SEND;
}
/*****************************************************************************
* StatusChange: Player status change signal
*****************************************************************************/
DBUS_SIGNAL( StatusChangeSignal )
{ /* send the updated status info on the bus */
SIGNAL_INIT( DBUS_MPRIS_PLAYER_INTERFACE,
DBUS_MPRIS_PLAYER_PATH,
"StatusChange" );
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 );
SIGNAL_SEND;
}
/*****************************************************************************
* TrackChange: Playlist item change callback
*****************************************************************************/
DBUS_SIGNAL( TrackChangeSignal )
{ /* emit the metadata of the new item */
SIGNAL_INIT( DBUS_MPRIS_PLAYER_INTERFACE,
DBUS_MPRIS_PLAYER_PATH,
"TrackChange" );
OUT_ARGUMENTS;
input_item_t *p_item = (input_item_t*) p_data;
GetInputMeta ( p_item, &args );
SIGNAL_SEND;
}
/******************************************************************************
* CapsChange: player capabilities change signal
*****************************************************************************/
DBUS_SIGNAL( CapsChangeSignal )
{
SIGNAL_INIT( DBUS_MPRIS_PLAYER_INTERFACE,
DBUS_MPRIS_PLAYER_PATH,
"CapsChange" );
OUT_ARGUMENTS;
ADD_INT32( &((intf_thread_t*)p_data)->p_sys->i_caps );
SIGNAL_SEND;
}
DBUS_METHOD( handle_introspect_player )
{
VLC_UNUSED(p_this);
REPLY_INIT;
OUT_ARGUMENTS;
ADD_STRING( &psz_player_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 )
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 );
/* 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 );
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
#undef METHOD_FUNC
/*****************************************************************************
* StatusChangeEmit: Emits the StatusChange signal
*****************************************************************************/
int StatusChangeEmit( 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 );
return VLC_SUCCESS;
}
/*****************************************************************************
* CapsChangeEmit: Emits the CapsChange signal
*****************************************************************************/
int CapsChangeEmit( intf_thread_t * p_intf )
{
if( p_intf->p_sys->b_dead )
return VLC_SUCCESS;
CapsChangeSignal( p_intf->p_sys->p_conn, p_intf );
return VLC_SUCCESS;
}
/*****************************************************************************
* 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;
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;
int i_val;
playlist_t* p_playlist = p_intf->p_sys->p_playlist;
input_thread_t* p_input = NULL;
i_state = 2;
p_input = playlist_CurrentInput( p_playlist );
if( p_input )
{
i_val = var_GetInteger( p_input, "state" );
if( i_val >= END_S )
i_state = 2;
else if( i_val == PAUSE_S )
i_state = 1;
else if( i_val <= PLAYING_S )
i_state = 0;
vlc_object_release( p_input );
}
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 );
return VLC_SUCCESS;
}
/*****************************************************************************
* dbus-player.h : dbus control module (mpris v1.0) - /Player object
*****************************************************************************
* Copyright © 2006-2008 Rafaël Carré
* Copyright © 2007-2010 Mirsal Ennaime
* Copyright © 2009-2010 The VideoLAN team
* $Id$
*
* Authors: Mirsal ENNAIME <mirsal dot ennaime at gmail dot com>
*
* 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_PLAYER_H
#define _VLC_DBUS_PLAYER_H
#include <vlc_interface.h>
#include "dbus_common.h"
#define DBUS_MPRIS_PLAYER_INTERFACE "org.freedesktop.MediaPlayer"
#define DBUS_MPRIS_PLAYER_PATH "/Player"
/* 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 */
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
};
int StatusChangeEmit ( intf_thread_t * );
int CapsChangeEmit ( intf_thread_t * );
int TrackChangeEmit ( intf_thread_t *, input_item_t * );
#endif //dbus_player.h
/*****************************************************************************
* dbus-root.c : dbus control module (mpris v1.0) - root object
*****************************************************************************
* Copyright © 2006-2008 Rafaël Carré
* Copyright © 2007-2010 Mirsal Ennaime
* Copyright © 2009-2010 The VideoLAN team
* $Id$
*
* Authors: Mirsal ENNAIME <mirsal dot ennaime at gmail dot com>
*
* 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.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_interface.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
return DBUS_HANDLER_RESULT_NEED_MEMORY;
REPLY_SEND;
}
DBUS_METHOD( MprisVersion )
{ /*implemented version of the mpris spec */
REPLY_INIT;
OUT_ARGUMENTS;
VLC_UNUSED( p_this );
dbus_uint16_t i_major = DBUS_MPRIS_VERSION_MAJOR;
dbus_uint16_t i_minor = DBUS_MPRIS_VERSION_MINOR;
DBusMessageIter version;
if( !dbus_message_iter_open_container( &args, DBUS_TYPE_STRUCT, NULL,
&version ) )
return DBUS_HANDLER_RESULT_NEED_MEMORY;
if( !dbus_message_iter_append_basic( &version, DBUS_TYPE_UINT16,
&i_major ) )
return DBUS_HANDLER_RESULT_NEED_MEMORY;
if( !dbus_message_iter_append_basic( &version, DBUS_TYPE_UINT16,
&i_minor ) )
return DBUS_HANDLER_RESULT_NEED_MEMORY;
if( !dbus_message_iter_close_container( &args, &version ) )
return DBUS_HANDLER_RESULT_NEED_MEMORY;
REPLY_SEND;
}
DBUS_METHOD( Quit )
{ /* exits vlc */
REPLY_INIT;
libvlc_Quit(INTF->p_libvlc);
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 METHOD_FUNC( interface, method, function ) \
else if( dbus_message_is_method_call( p_from, interface, method ) )\
return function( p_conn, p_from, p_this )
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;
}
#undef METHOD_FUNC
/*****************************************************************************
* dbus-root.h : dbus control module (mpris v1.0) - root object
*****************************************************************************
* Copyright © 2006-2008 Rafaël Carré
* Copyright © 2007-2010 Mirsal Ennaime
* Copyright © 2009-2010 The VideoLAN team
* $Id$
*
* Authors: Mirsal ENNAIME <mirsal dot ennaime at gmail dot com>
*
* 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_ROOT_H
#define _VLC_DBUS_ROOT_H
#include "dbus_common.h"
/* MPRIS VERSION */
#define DBUS_MPRIS_VERSION_MAJOR 2
#define DBUS_MPRIS_VERSION_MINOR 0
/* DBUS IDENTIFIERS */
#define DBUS_MPRIS_ROOT_INTERFACE "org.freedesktop.MediaPlayer"
#define DBUS_MPRIS_ROOT_PATH "/"
/* 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
};
#endif //dbus-root.h
/*****************************************************************************
* dbus-tracklist.c : dbus control module (mpris v1.0) - /TrackList object
*****************************************************************************
* Copyright © 2006-2008 Rafaël Carré
* Copyright © 2007-2010 Mirsal Ennaime
* Copyright © 2009-2010 The VideoLAN team
* $Id$
*
* Authors: Mirsal ENNAIME <mirsal dot ennaime at gmail dot com>
*
* 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.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_playlist.h>
#include <assert.h>
#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;
OUT_ARGUMENTS;
DBusError error;
dbus_error_init( &error );
char *psz_mrl;
dbus_bool_t b_play;
dbus_message_get_args( p_from, &error,
DBUS_TYPE_STRING, &psz_mrl,
DBUS_TYPE_BOOLEAN, &b_play,
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;
}
playlist_Add( PL, psz_mrl, NULL, PLAYLIST_APPEND |
( ( b_play == TRUE ) ? PLAYLIST_GO : 0 ) ,
PLAYLIST_END, true, false );
dbus_int32_t i_success = 0;
ADD_INT32( &i_success );
REPLY_SEND;
}
DBUS_METHOD( GetCurrentTrack )
{
REPLY_INIT;
OUT_ARGUMENTS;
playlist_t *p_playlist = PL;
PL_LOCK;
dbus_int32_t i_position = PL->i_current_index;
PL_UNLOCK;
ADD_INT32( &i_position );
REPLY_SEND;
}
DBUS_METHOD( GetMetadata )
{
REPLY_INIT;
OUT_ARGUMENTS;
DBusError error;
dbus_error_init( &error );
dbus_int32_t i_position;
playlist_t *p_playlist = PL;
dbus_message_get_args( p_from, &error,
DBUS_TYPE_INT32, &i_position,
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;
}
PL_LOCK;
if( i_position < p_playlist->current.i_size )
{
GetInputMeta( p_playlist->current.p_elems[i_position]->p_input, &args );
}
PL_UNLOCK;
REPLY_SEND;
}
DBUS_METHOD( GetLength )
{
REPLY_INIT;
OUT_ARGUMENTS;
playlist_t *p_playlist = PL;
PL_LOCK;
dbus_int32_t i_elements = PL->current.i_size;
PL_UNLOCK;
ADD_INT32( &i_elements );
REPLY_SEND;
}
DBUS_METHOD( DelTrack )
{
REPLY_INIT;
DBusError error;
dbus_error_init( &error );
dbus_int32_t i_position;
playlist_t *p_playlist = PL;
dbus_message_get_args( p_from, &error,
DBUS_TYPE_INT32, &i_position,
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;
}
PL_LOCK;
if( i_position < p_playlist->current.i_size )
{
playlist_DeleteFromInput( p_playlist,
p_playlist->current.p_elems[i_position]->p_input,
pl_Locked );
}
PL_UNLOCK;
REPLY_SEND;
}
DBUS_METHOD( SetLoop )
{
REPLY_INIT;
OUT_ARGUMENTS;
DBusError error;
dbus_bool_t b_loop;
dbus_error_init( &error );
dbus_message_get_args( p_from, &error,
DBUS_TYPE_BOOLEAN, &b_loop,
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;
}
var_SetBool( PL, "loop", ( b_loop == TRUE ) );
REPLY_SEND;
}
DBUS_METHOD( SetRandom )
{
REPLY_INIT;
OUT_ARGUMENTS;
DBusError error;
dbus_bool_t b_random;
dbus_error_init( &error );
dbus_message_get_args( p_from, &error,
DBUS_TYPE_BOOLEAN, &b_random,
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;
}
var_SetBool( PL, "random", ( b_random == TRUE ) );
REPLY_SEND;
}
/******************************************************************************
* TrackListChange: tracklist order / length change signal
*****************************************************************************/
DBUS_SIGNAL( TrackListChangeSignal )
{ /* emit the new tracklist lengh */
SIGNAL_INIT( DBUS_MPRIS_TRACKLIST_INTERFACE,
DBUS_MPRIS_TRACKLIST_PATH,
"TrackListChange");
OUT_ARGUMENTS;
playlist_t *p_playlist = ((intf_thread_t*)p_data)->p_sys->p_playlist;
PL_LOCK;
dbus_int32_t i_elements = p_playlist->current.i_size;
PL_UNLOCK;
ADD_INT32( &i_elements );
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 )
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 );
/* here D-Bus method names are associated to an handler */
METHOD_FUNC( DBUS_MPRIS_TRACKLIST_INTERFACE, "GetMetadata", GetMetadata );
METHOD_FUNC( DBUS_MPRIS_TRACKLIST_INTERFACE, "GetCurrentTrack", GetCurrentTrack );
METHOD_FUNC( DBUS_MPRIS_TRACKLIST_INTERFACE, "GetLength", GetLength );
METHOD_FUNC( DBUS_MPRIS_TRACKLIST_INTERFACE, "AddTrack", AddTrack );
METHOD_FUNC( DBUS_MPRIS_TRACKLIST_INTERFACE, "DelTrack", DelTrack );
METHOD_FUNC( DBUS_MPRIS_TRACKLIST_INTERFACE, "SetLoop", SetLoop );
METHOD_FUNC( DBUS_MPRIS_TRACKLIST_INTERFACE, "SetRandom", SetRandom );
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
/*****************************************************************************
* TrackListChangeEmit: Emits the TrackListChange signal
*****************************************************************************/
/* FIXME: It is not called on tracklist reordering */
int TrackListChangeEmit( intf_thread_t *p_intf, int signal, int i_node )
{
// "playlist-item-append"
if( signal == SIGNAL_PLAYLIST_ITEM_APPEND )
{
/* don't signal when items are added/removed in p_category */
playlist_t *p_playlist = p_intf->p_sys->p_playlist;
PL_LOCK;
playlist_item_t *p_item = playlist_ItemGetById( p_playlist, i_node );
assert( p_item );
while( p_item->p_parent )
p_item = p_item->p_parent;
if( p_item == p_playlist->p_root_category )
{
PL_UNLOCK;
return VLC_SUCCESS;
}
PL_UNLOCK;
}
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;
}
#undef METHOD_FUNC
/*****************************************************************************
* dbus-tracklist.h : dbus control module (mpris v1.0) - /TrackList object
*****************************************************************************
* Copyright © 2006-2008 Rafaël Carré
* Copyright © 2007-2010 Mirsal Ennaime
* Copyright © 2009-2010 The VideoLAN team
* $Id$
*
* Authors: Mirsal ENNAIME <mirsal dot ennaime at gmail dot com>
*
* 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_TRACKLIST_H
#define _VLC_DBUS_TRACKLIST_H
#include <vlc_common.h>
#include <vlc_interface.h>
#include "dbus_common.h"
#define DBUS_MPRIS_TRACKLIST_INTERFACE "org.freedesktop.MediaPlayer"
#define DBUS_MPRIS_TRACKLIST_PATH "/TrackList"
/* Handle incoming dbus messages */
DBusHandlerResult handle_tracklist ( DBusConnection *p_conn,
DBusMessage *p_from,
void *p_this );
static const DBusObjectPathVTable dbus_mpris_tracklist_vtable = {
NULL, handle_tracklist, /* handler function */
NULL, NULL, NULL, NULL
};
int TrackListChangeEmit( intf_thread_t *, int, int );
#endif //dbus_tracklist.h
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment