dbus.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:38k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * dbus.c : D-Bus control interface
  3.  *****************************************************************************
  4.  * Copyright © 2006-2008 Rafaël Carré
  5.  * Copyright © 2007-2008 Mirsal Ennaime
  6.  * Copyright © 2009 The VideoLAN team
  7.  * $Id: 5704672cce3ce0f8e326c4bbbd40adbbf10ccf50 $
  8.  *
  9.  * Authors:    Rafaël Carré <funman at videolanorg>
  10.  *             Mirsal Ennaime <mirsal dot ennaime at gmail dot com>
  11.  *
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 2 of the License, or
  15.  * (at your option) any later version.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program; if not, write to the Free Software
  24.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  25.  *****************************************************************************/
  26. /*
  27.  * D-Bus Specification:
  28.  *      http://dbus.freedesktop.org/doc/dbus-specification.html
  29.  * D-Bus low-level C API (libdbus)
  30.  *      http://dbus.freedesktop.org/doc/dbus/api/html/index.html
  31.  *  extract:
  32.  *   "If you use this low-level API directly, you're signing up for some pain."
  33.  *
  34.  * MPRIS Specification version 1.0
  35.  *      http://wiki.xmms2.xmms.se/index.php/MPRIS
  36.  */
  37. /*****************************************************************************
  38.  * Preamble
  39.  *****************************************************************************/
  40. #ifdef HAVE_CONFIG_H
  41. # include "config.h"
  42. #endif
  43. #include <dbus/dbus.h>
  44. #include "dbus.h"
  45. #include <vlc_common.h>
  46. #include <vlc_plugin.h>
  47. #include <vlc_aout.h>
  48. #include <vlc_interface.h>
  49. #include <vlc_playlist.h>
  50. #include <math.h>
  51. #include <assert.h>
  52. /*****************************************************************************
  53.  * Local prototypes.
  54.  *****************************************************************************/
  55. static int  Open    ( vlc_object_t * );
  56. static void Close   ( vlc_object_t * );
  57. static void Run     ( intf_thread_t * );
  58. static int StateChange( intf_thread_t *, int );
  59. static int TrackChange( intf_thread_t * );
  60. static int StatusChangeEmit( intf_thread_t *);
  61. static int TrackListChangeEmit( intf_thread_t *, int, int );
  62. static int AllCallback( vlc_object_t*, const char*, vlc_value_t, vlc_value_t, void* );
  63. static int GetInputMeta ( input_item_t *, DBusMessageIter * );
  64. static int MarshalStatus ( intf_thread_t *, DBusMessageIter * );
  65. static int UpdateCaps( intf_thread_t* );
  66. /* GetCaps() capabilities */
  67. enum
  68. {
  69.      CAPS_NONE                  = 0,
  70.      CAPS_CAN_GO_NEXT           = 1 << 0,
  71.      CAPS_CAN_GO_PREV           = 1 << 1,
  72.      CAPS_CAN_PAUSE             = 1 << 2,
  73.      CAPS_CAN_PLAY              = 1 << 3,
  74.      CAPS_CAN_SEEK              = 1 << 4,
  75.      CAPS_CAN_PROVIDE_METADATA  = 1 << 5,
  76.      CAPS_CAN_HAS_TRACKLIST     = 1 << 6
  77. };
  78. // The signal that can be get from the callbacks
  79. enum
  80. {
  81.     SIGNAL_ITEM_CURRENT,
  82.     SIGNAL_INTF_CHANGE,
  83.     SIGNAL_PLAYLIST_ITEM_APPEND,
  84.     SIGNAL_PLAYLIST_ITEM_DELETED,
  85.     SIGNAL_RANDOM,
  86.     SIGNAL_REPEAT,
  87.     SIGNAL_LOOP,
  88.     SIGNAL_STATE
  89. };
  90. struct intf_sys_t
  91. {
  92.     DBusConnection *p_conn;
  93.     bool            b_meta_read;
  94.     dbus_int32_t    i_caps;
  95.     bool            b_dead;
  96.     vlc_array_t    *p_events;
  97.     vlc_mutex_t     lock;
  98. };
  99. typedef struct
  100. {
  101.     int signal;
  102.     int i_node;
  103.     int i_input_state;
  104. } callback_info_t;
  105. /*****************************************************************************
  106.  * Module descriptor
  107.  *****************************************************************************/
  108. vlc_module_begin ()
  109.     set_shortname( N_("dbus"))
  110.     set_category( CAT_INTERFACE )
  111.     set_subcategory( SUBCAT_INTERFACE_CONTROL )
  112.     set_description( N_("D-Bus control interface") )
  113.     set_capability( "interface", 0 )
  114.     set_callbacks( Open, Close )
  115. vlc_module_end ()
  116. /*****************************************************************************
  117.  * Methods
  118.  *****************************************************************************/
  119. /* Player */
  120. DBUS_METHOD( Quit )
  121. { /* exits vlc */
  122.     REPLY_INIT;
  123.     libvlc_Quit(((vlc_object_t*)p_this)->p_libvlc);
  124.     REPLY_SEND;
  125. }
  126. DBUS_METHOD( MprisVersion )
  127. { /*implemented version of the mpris spec */
  128.     REPLY_INIT;
  129.     OUT_ARGUMENTS;
  130.     VLC_UNUSED( p_this );
  131.     dbus_uint16_t i_major = VLC_MPRIS_VERSION_MAJOR;
  132.     dbus_uint16_t i_minor = VLC_MPRIS_VERSION_MINOR;
  133.     DBusMessageIter version;
  134.     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_STRUCT, NULL,
  135.             &version ) )
  136.         return DBUS_HANDLER_RESULT_NEED_MEMORY;
  137.     if( !dbus_message_iter_append_basic( &version, DBUS_TYPE_UINT16,
  138.             &i_major ) )
  139.         return DBUS_HANDLER_RESULT_NEED_MEMORY;
  140.     if( !dbus_message_iter_append_basic( &version, DBUS_TYPE_UINT16,
  141.             &i_minor ) )
  142.         return DBUS_HANDLER_RESULT_NEED_MEMORY;
  143.     if( !dbus_message_iter_close_container( &args, &version ) )
  144.         return DBUS_HANDLER_RESULT_NEED_MEMORY;
  145.     REPLY_SEND;
  146. }
  147. DBUS_METHOD( PositionGet )
  148. { /* returns position in milliseconds */
  149.     REPLY_INIT;
  150.     OUT_ARGUMENTS;
  151.     vlc_value_t position;
  152.     dbus_int32_t i_pos;
  153.     playlist_t *p_playlist = pl_Hold( ((vlc_object_t*) p_this) );
  154.     input_thread_t *p_input = playlist_CurrentInput( p_playlist );
  155.     if( !p_input )
  156.         i_pos = 0;
  157.     else
  158.     {
  159.         var_Get( p_input, "time", &position );
  160.         i_pos = position.i_time / 1000;
  161.         vlc_object_release( p_input );
  162.     }
  163.     pl_Release( ((vlc_object_t*) p_this) );
  164.     ADD_INT32( &i_pos );
  165.     REPLY_SEND;
  166. }
  167. DBUS_METHOD( PositionSet )
  168. { /* set position in milliseconds */
  169.     REPLY_INIT;
  170.     vlc_value_t position;
  171.     playlist_t* p_playlist = NULL;
  172.     dbus_int32_t i_pos;
  173.     DBusError error;
  174.     dbus_error_init( &error );
  175.     dbus_message_get_args( p_from, &error,
  176.             DBUS_TYPE_INT32, &i_pos,
  177.             DBUS_TYPE_INVALID );
  178.     if( dbus_error_is_set( &error ) )
  179.     {
  180.         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
  181.                 error.message );
  182.         dbus_error_free( &error );
  183.         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  184.     }
  185.     p_playlist = pl_Hold( ((vlc_object_t*) p_this) );
  186.     input_thread_t *p_input = playlist_CurrentInput( p_playlist );
  187.     if( p_input )
  188.     {
  189.         position.i_time = ((mtime_t)i_pos) * 1000;
  190.         var_Set( p_input, "time", position );
  191.         vlc_object_release( p_input );
  192.     }
  193.     pl_Release( ((vlc_object_t*) p_this) );
  194.     REPLY_SEND;
  195. }
  196. DBUS_METHOD( VolumeGet )
  197. { /* returns volume in percentage */
  198.     REPLY_INIT;
  199.     OUT_ARGUMENTS;
  200.     dbus_int32_t i_dbus_vol;
  201.     audio_volume_t i_vol;
  202.     /* 2nd argument of aout_VolumeGet is int32 */
  203.     aout_VolumeGet( (vlc_object_t*) p_this, &i_vol );
  204.     double f_vol = 100. * i_vol / AOUT_VOLUME_MAX;
  205.     i_dbus_vol = round( f_vol );
  206.     ADD_INT32( &i_dbus_vol );
  207.     REPLY_SEND;
  208. }
  209. DBUS_METHOD( VolumeSet )
  210. { /* set volume in percentage */
  211.     REPLY_INIT;
  212.     DBusError error;
  213.     dbus_error_init( &error );
  214.     dbus_int32_t i_dbus_vol;
  215.     audio_volume_t i_vol;
  216.     dbus_message_get_args( p_from, &error,
  217.             DBUS_TYPE_INT32, &i_dbus_vol,
  218.             DBUS_TYPE_INVALID );
  219.     if( dbus_error_is_set( &error ) )
  220.     {
  221.         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
  222.                 error.message );
  223.         dbus_error_free( &error );
  224.         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  225.     }
  226.     double f_vol = AOUT_VOLUME_MAX * i_dbus_vol / 100.;
  227.     i_vol = round( f_vol );
  228.     aout_VolumeSet( (vlc_object_t*) p_this, i_vol );
  229.     REPLY_SEND;
  230. }
  231. DBUS_METHOD( Next )
  232. { /* next playlist item */
  233.     REPLY_INIT;
  234.     playlist_t *p_playlist = pl_Hold( ((vlc_object_t*) p_this) );
  235.     playlist_Next( p_playlist );
  236.     pl_Release( ((vlc_object_t*) p_this) );
  237.     REPLY_SEND;
  238. }
  239. DBUS_METHOD( Prev )
  240. { /* previous playlist item */
  241.     REPLY_INIT;
  242.     playlist_t *p_playlist = pl_Hold( ((vlc_object_t*) p_this) );
  243.     playlist_Prev( p_playlist );
  244.     pl_Release( ((vlc_object_t*) p_this) );
  245.     REPLY_SEND;
  246. }
  247. DBUS_METHOD( Stop )
  248. { /* stop playing */
  249.     REPLY_INIT;
  250.     playlist_t *p_playlist = pl_Hold( ((vlc_object_t*) p_this) );
  251.     playlist_Stop( p_playlist );
  252.     pl_Release( ((vlc_object_t*) p_this) );
  253.     REPLY_SEND;
  254. }
  255. DBUS_METHOD( GetStatus )
  256. { /* returns the current status as a struct of 4 ints */
  257. /*
  258.     First   0 = Playing, 1 = Paused, 2 = Stopped.
  259.     Second  0 = Playing linearly , 1 = Playing randomly.
  260.     Third   0 = Go to the next element once the current has finished playing , 1 = Repeat the current element
  261.     Fourth  0 = Stop playing once the last element has been played, 1 = Never give up playing *
  262.  */
  263.     REPLY_INIT;
  264.     OUT_ARGUMENTS;
  265.     MarshalStatus( p_this, &args );
  266.     REPLY_SEND;
  267. }
  268. DBUS_METHOD( Pause )
  269. {
  270.     REPLY_INIT;
  271.     playlist_t *p_playlist = pl_Hold( (vlc_object_t*) p_this );
  272.     playlist_Pause( p_playlist );
  273.     pl_Release( (vlc_object_t*) p_this );
  274.     REPLY_SEND;
  275. }
  276. DBUS_METHOD( Play )
  277. {
  278.     REPLY_INIT;
  279.     playlist_t *p_playlist = pl_Hold( (vlc_object_t*) p_this );
  280.     input_thread_t *p_input =  playlist_CurrentInput( p_playlist );
  281.     if( p_input )
  282.     {
  283.         double i_pos = 0;
  284.         input_Control( p_input, INPUT_SET_POSITION, i_pos );
  285.         vlc_object_release( p_input );
  286.     }
  287.     else
  288.         playlist_Play( p_playlist );
  289.     pl_Release( (vlc_object_t*) p_this );
  290.     REPLY_SEND;
  291. }
  292. DBUS_METHOD( GetCurrentMetadata )
  293. {
  294.     REPLY_INIT;
  295.     OUT_ARGUMENTS;
  296.     playlist_t* p_playlist = pl_Hold( (vlc_object_t*) p_this );
  297.     PL_LOCK;
  298.     playlist_item_t* p_item =  playlist_CurrentPlayingItem( p_playlist );
  299.     if( p_item )
  300.         GetInputMeta( p_item->p_input, &args );
  301.     PL_UNLOCK;
  302.     pl_Release( (vlc_object_t*) p_this );
  303.     REPLY_SEND;
  304. }
  305. DBUS_METHOD( GetCaps )
  306. {
  307.     REPLY_INIT;
  308.     OUT_ARGUMENTS;
  309.     ADD_INT32( &((intf_thread_t*)p_this)->p_sys->i_caps );
  310.     REPLY_SEND;
  311. }
  312. /* Media Player information */
  313. DBUS_METHOD( Identity )
  314. {
  315.     VLC_UNUSED(p_this);
  316.     REPLY_INIT;
  317.     OUT_ARGUMENTS;
  318.     char *psz_identity;
  319.     if( asprintf( &psz_identity, "%s %s", PACKAGE, VERSION ) != -1 )
  320.     {
  321.         ADD_STRING( &psz_identity );
  322.         free( psz_identity );
  323.     }
  324.     else
  325.         return DBUS_HANDLER_RESULT_NEED_MEMORY;
  326.     REPLY_SEND;
  327. }
  328. /* TrackList */
  329. DBUS_METHOD( AddTrack )
  330. { /* add the string to the playlist, and play it if the boolean is true */
  331.     REPLY_INIT;
  332.     OUT_ARGUMENTS;
  333.     DBusError error;
  334.     dbus_error_init( &error );
  335.     playlist_t* p_playlist = NULL;
  336.     char *psz_mrl;
  337.     dbus_bool_t b_play;
  338.     dbus_message_get_args( p_from, &error,
  339.             DBUS_TYPE_STRING, &psz_mrl,
  340.             DBUS_TYPE_BOOLEAN, &b_play,
  341.             DBUS_TYPE_INVALID );
  342.     if( dbus_error_is_set( &error ) )
  343.     {
  344.         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
  345.                 error.message );
  346.         dbus_error_free( &error );
  347.         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  348.     }
  349.     p_playlist = pl_Hold( (vlc_object_t*) p_this );
  350.     playlist_Add( p_playlist, psz_mrl, NULL, PLAYLIST_APPEND |
  351.             ( ( b_play == TRUE ) ? PLAYLIST_GO : 0 ) ,
  352.             PLAYLIST_END, true, false );
  353.     pl_Release( (vlc_object_t*) p_this );
  354.     dbus_int32_t i_success = 0;
  355.     ADD_INT32( &i_success );
  356.     REPLY_SEND;
  357. }
  358. DBUS_METHOD( GetCurrentTrack )
  359. {
  360.     REPLY_INIT;
  361.     OUT_ARGUMENTS;
  362.     playlist_t *p_playlist = pl_Hold( (vlc_object_t*) p_this );
  363.     dbus_int32_t i_position = p_playlist->i_current_index;
  364.     pl_Release( (vlc_object_t*) p_this );
  365.     ADD_INT32( &i_position );
  366.     REPLY_SEND;
  367. }
  368. DBUS_METHOD( GetMetadata )
  369. {
  370.     REPLY_INIT;
  371.     OUT_ARGUMENTS;
  372.     DBusError error;
  373.     dbus_error_init( &error );
  374.     dbus_int32_t i_position;
  375.     playlist_t *p_playlist;
  376.     dbus_message_get_args( p_from, &error,
  377.            DBUS_TYPE_INT32, &i_position,
  378.            DBUS_TYPE_INVALID );
  379.     if( dbus_error_is_set( &error ) )
  380.     {
  381.         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
  382.                 error.message );
  383.         dbus_error_free( &error );
  384.         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  385.     }
  386.     p_playlist = pl_Hold( (vlc_object_t*) p_this );
  387.     PL_LOCK;
  388.     if( i_position < p_playlist->current.i_size )
  389.     {
  390.         GetInputMeta( p_playlist->current.p_elems[i_position]->p_input, &args );
  391.     }
  392.     PL_UNLOCK;
  393.     pl_Release( (vlc_object_t*) p_this );
  394.     REPLY_SEND;
  395. }
  396. DBUS_METHOD( GetLength )
  397. {
  398.     REPLY_INIT;
  399.     OUT_ARGUMENTS;
  400.     playlist_t *p_playlist = pl_Hold( (vlc_object_t*) p_this );
  401.     dbus_int32_t i_elements = p_playlist->current.i_size;
  402.     pl_Release( (vlc_object_t*) p_this );
  403.     ADD_INT32( &i_elements );
  404.     REPLY_SEND;
  405. }
  406. DBUS_METHOD( DelTrack )
  407. {
  408.     REPLY_INIT;
  409.     DBusError error;
  410.     dbus_error_init( &error );
  411.     dbus_int32_t i_position;
  412.     playlist_t *p_playlist;
  413.     dbus_message_get_args( p_from, &error,
  414.             DBUS_TYPE_INT32, &i_position,
  415.             DBUS_TYPE_INVALID );
  416.     if( dbus_error_is_set( &error ) )
  417.     {
  418.         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
  419.                 error.message );
  420.         dbus_error_free( &error );
  421.         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  422.     }
  423.     p_playlist = pl_Hold( (vlc_object_t*) p_this );
  424.     PL_LOCK;
  425.     if( i_position < p_playlist->current.i_size )
  426.     {
  427.         playlist_DeleteFromInput( p_playlist,
  428.             p_playlist->current.p_elems[i_position]->p_input->i_id,
  429.             pl_Locked );
  430.     }
  431.     PL_UNLOCK;
  432.     pl_Release( (vlc_object_t*) p_this );
  433.     REPLY_SEND;
  434. }
  435. DBUS_METHOD( SetLoop )
  436. {
  437.     REPLY_INIT;
  438.     OUT_ARGUMENTS;
  439.     DBusError error;
  440.     dbus_bool_t b_loop;
  441.     playlist_t* p_playlist;
  442.     dbus_error_init( &error );
  443.     dbus_message_get_args( p_from, &error,
  444.             DBUS_TYPE_BOOLEAN, &b_loop,
  445.             DBUS_TYPE_INVALID );
  446.     if( dbus_error_is_set( &error ) )
  447.     {
  448.         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
  449.                 error.message );
  450.         dbus_error_free( &error );
  451.         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  452.     }
  453.     p_playlist = pl_Hold( (vlc_object_t*) p_this );
  454.     var_SetBool( p_playlist, "loop", ( b_loop == TRUE ) );
  455.     pl_Release( ((vlc_object_t*) p_this) );
  456.     REPLY_SEND;
  457. }
  458. DBUS_METHOD( Repeat )
  459. {
  460.     REPLY_INIT;
  461.     OUT_ARGUMENTS;
  462.     DBusError error;
  463.     dbus_bool_t b_repeat;
  464.     playlist_t* p_playlist;
  465.     dbus_error_init( &error );
  466.     dbus_message_get_args( p_from, &error,
  467.             DBUS_TYPE_BOOLEAN, &b_repeat,
  468.             DBUS_TYPE_INVALID );
  469.     if( dbus_error_is_set( &error ) )
  470.     {
  471.         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
  472.                 error.message );
  473.         dbus_error_free( &error );
  474.         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  475.     }
  476.     p_playlist = pl_Hold( (vlc_object_t*) p_this );
  477.     var_SetBool( p_playlist, "repeat", ( b_repeat == TRUE ) );
  478.     pl_Release( ((vlc_object_t*) p_this) );
  479.     REPLY_SEND;
  480. }
  481. DBUS_METHOD( SetRandom )
  482. {
  483.     REPLY_INIT;
  484.     OUT_ARGUMENTS;
  485.     DBusError error;
  486.     dbus_bool_t b_random;
  487.     playlist_t* p_playlist;
  488.     dbus_error_init( &error );
  489.     dbus_message_get_args( p_from, &error,
  490.             DBUS_TYPE_BOOLEAN, &b_random,
  491.             DBUS_TYPE_INVALID );
  492.     if( dbus_error_is_set( &error ) )
  493.     {
  494.         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
  495.                 error.message );
  496.         dbus_error_free( &error );
  497.         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  498.     }
  499.     p_playlist = pl_Hold( (vlc_object_t*) p_this );
  500.     var_SetBool( p_playlist, "random", ( b_random == TRUE ) );
  501.     pl_Release( ((vlc_object_t*) p_this) );
  502.     REPLY_SEND;
  503. }
  504. /*****************************************************************************
  505.  * Introspection method
  506.  *****************************************************************************/
  507. DBUS_METHOD( handle_introspect_root )
  508. { /* handles introspection of root object */
  509.     VLC_UNUSED(p_this);
  510.     REPLY_INIT;
  511.     OUT_ARGUMENTS;
  512.     ADD_STRING( &psz_introspection_xml_data_root );
  513.     REPLY_SEND;
  514. }
  515. DBUS_METHOD( handle_introspect_player )
  516. {
  517.     VLC_UNUSED(p_this);
  518.     REPLY_INIT;
  519.     OUT_ARGUMENTS;
  520.     ADD_STRING( &psz_introspection_xml_data_player );
  521.     REPLY_SEND;
  522. }
  523. DBUS_METHOD( handle_introspect_tracklist )
  524. {
  525.     VLC_UNUSED(p_this);
  526.     REPLY_INIT;
  527.     OUT_ARGUMENTS;
  528.     ADD_STRING( &psz_introspection_xml_data_tracklist );
  529.     REPLY_SEND;
  530. }
  531. /*****************************************************************************
  532.  * handle_*: answer to incoming messages
  533.  *****************************************************************************/
  534. #define METHOD_FUNC( method, function ) 
  535.     else if( dbus_message_is_method_call( p_from, MPRIS_DBUS_INTERFACE, method ) )
  536.         return function( p_conn, p_from, p_this )
  537. DBUS_METHOD( handle_root )
  538. {
  539.     if( dbus_message_is_method_call( p_from,
  540.                 DBUS_INTERFACE_INTROSPECTABLE, "Introspect" ) )
  541.         return handle_introspect_root( p_conn, p_from, p_this );
  542.     /* here D-Bus method's names are associated to an handler */
  543.     METHOD_FUNC( "Identity",                Identity );
  544.     METHOD_FUNC( "MprisVersion",            MprisVersion );
  545.     METHOD_FUNC( "Quit",                    Quit );
  546.     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  547. }
  548. DBUS_METHOD( handle_player )
  549. {
  550.     if( dbus_message_is_method_call( p_from,
  551.                 DBUS_INTERFACE_INTROSPECTABLE, "Introspect" ) )
  552.         return handle_introspect_player( p_conn, p_from, p_this );
  553.     /* here D-Bus method's names are associated to an handler */
  554.     METHOD_FUNC( "Prev",                    Prev );
  555.     METHOD_FUNC( "Next",                    Next );
  556.     METHOD_FUNC( "Stop",                    Stop );
  557.     METHOD_FUNC( "Play",                    Play );
  558.     METHOD_FUNC( "Pause",                   Pause );
  559.     METHOD_FUNC( "Repeat",                  Repeat );
  560.     METHOD_FUNC( "VolumeSet",               VolumeSet );
  561.     METHOD_FUNC( "VolumeGet",               VolumeGet );
  562.     METHOD_FUNC( "PositionSet",             PositionSet );
  563.     METHOD_FUNC( "PositionGet",             PositionGet );
  564.     METHOD_FUNC( "GetStatus",               GetStatus );
  565.     METHOD_FUNC( "GetMetadata",             GetCurrentMetadata );
  566.     METHOD_FUNC( "GetCaps",                 GetCaps );
  567.     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  568. }
  569. DBUS_METHOD( handle_tracklist )
  570. {
  571.     if( dbus_message_is_method_call( p_from,
  572.                 DBUS_INTERFACE_INTROSPECTABLE, "Introspect" ) )
  573.     return handle_introspect_tracklist( p_conn, p_from, p_this );
  574.     /* here D-Bus method's names are associated to an handler */
  575.     METHOD_FUNC( "GetMetadata",             GetMetadata );
  576.     METHOD_FUNC( "GetCurrentTrack",         GetCurrentTrack );
  577.     METHOD_FUNC( "GetLength",               GetLength );
  578.     METHOD_FUNC( "AddTrack",                AddTrack );
  579.     METHOD_FUNC( "DelTrack",                DelTrack );
  580.     METHOD_FUNC( "SetLoop",                 SetLoop );
  581.     METHOD_FUNC( "SetRandom",               SetRandom );
  582.     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  583. }
  584. /*****************************************************************************
  585.  * Open: initialize interface
  586.  *****************************************************************************/
  587. static int Open( vlc_object_t *p_this )
  588. { /* initialisation of the connection */
  589.     intf_thread_t   *p_intf = (intf_thread_t*)p_this;
  590.     intf_sys_t      *p_sys  = malloc( sizeof( intf_sys_t ) );
  591.     playlist_t      *p_playlist;
  592.     DBusConnection  *p_conn;
  593.     DBusError       error;
  594.     if( !p_sys )
  595.         return VLC_ENOMEM;
  596.     p_sys->b_meta_read = false;
  597.     p_sys->i_caps = CAPS_NONE;
  598.     p_sys->b_dead = false;
  599.     dbus_error_init( &error );
  600.     /* connect to the session bus */
  601.     p_conn = dbus_bus_get( DBUS_BUS_SESSION, &error );
  602.     if( !p_conn )
  603.     {
  604.         msg_Err( p_this, "Failed to connect to the D-Bus session daemon: %s",
  605.                 error.message );
  606.         dbus_error_free( &error );
  607.         free( p_sys );
  608.         return VLC_EGENERIC;
  609.     }
  610.     /* register a well-known name on the bus */
  611.     dbus_bus_request_name( p_conn, VLC_MPRIS_DBUS_SERVICE, 0, &error );
  612.     if( dbus_error_is_set( &error ) )
  613.     {
  614.         msg_Err( p_this, "Error requesting service " VLC_MPRIS_DBUS_SERVICE
  615.                  ": %s", error.message );
  616.         dbus_error_free( &error );
  617.         free( p_sys );
  618.         return VLC_EGENERIC;
  619.     }
  620.     /* we register the objects */
  621.     dbus_connection_register_object_path( p_conn, MPRIS_DBUS_ROOT_PATH,
  622.             &vlc_dbus_root_vtable, p_this );
  623.     dbus_connection_register_object_path( p_conn, MPRIS_DBUS_PLAYER_PATH,
  624.             &vlc_dbus_player_vtable, p_this );
  625.     dbus_connection_register_object_path( p_conn, MPRIS_DBUS_TRACKLIST_PATH,
  626.             &vlc_dbus_tracklist_vtable, p_this );
  627.     dbus_connection_flush( p_conn );
  628.     p_intf->pf_run = Run;
  629.     p_intf->p_sys = p_sys;
  630.     p_sys->p_conn = p_conn;
  631.     p_sys->p_events = vlc_array_new();
  632.     vlc_mutex_init( &p_sys->lock );
  633.     p_playlist = pl_Hold( p_intf );
  634.     PL_LOCK;
  635.     var_AddCallback( p_playlist, "item-current", AllCallback, p_intf );
  636.     var_AddCallback( p_playlist, "intf-change", AllCallback, p_intf );
  637.     var_AddCallback( p_playlist, "playlist-item-append", AllCallback, p_intf );
  638.     var_AddCallback( p_playlist, "playlist-item-deleted", AllCallback, p_intf );
  639.     var_AddCallback( p_playlist, "random", AllCallback, p_intf );
  640.     var_AddCallback( p_playlist, "repeat", AllCallback, p_intf );
  641.     var_AddCallback( p_playlist, "loop", AllCallback, p_intf );
  642.     PL_UNLOCK;
  643.     pl_Release( p_intf );
  644.     UpdateCaps( p_intf );
  645.     return VLC_SUCCESS;
  646. }
  647. /*****************************************************************************
  648.  * Close: destroy interface
  649.  *****************************************************************************/
  650. static void Close   ( vlc_object_t *p_this )
  651. {
  652.     intf_thread_t   *p_intf     = (intf_thread_t*) p_this;
  653.     playlist_t      *p_playlist = pl_Hold( p_intf );;
  654.     input_thread_t  *p_input;
  655.     var_DelCallback( p_playlist, "item-current", AllCallback, p_intf );
  656.     var_DelCallback( p_playlist, "intf-change", AllCallback, p_intf );
  657.     var_DelCallback( p_playlist, "playlist-item-append", AllCallback, p_intf );
  658.     var_DelCallback( p_playlist, "playlist-item-deleted", AllCallback, p_intf );
  659.     var_DelCallback( p_playlist, "random", AllCallback, p_intf );
  660.     var_DelCallback( p_playlist, "repeat", AllCallback, p_intf );
  661.     var_DelCallback( p_playlist, "loop", AllCallback, p_intf );
  662.     p_input = playlist_CurrentInput( p_playlist );
  663.     if ( p_input )
  664.     {
  665.         var_DelCallback( p_input, "state", AllCallback, p_intf );
  666.         vlc_object_release( p_input );
  667.     }
  668.     pl_Release( p_intf );
  669.     dbus_connection_unref( p_intf->p_sys->p_conn );
  670.     // Free the events array
  671.     for( int i = 0; i < vlc_array_count( p_intf->p_sys->p_events ); i++ )
  672.     {
  673.         callback_info_t* info = vlc_array_item_at_index( p_intf->p_sys->p_events, i );
  674.         free( info );
  675.     }
  676.     vlc_mutex_destroy( &p_intf->p_sys->lock );
  677.     vlc_array_destroy( p_intf->p_sys->p_events );
  678.     free( p_intf->p_sys );
  679. }
  680. /*****************************************************************************
  681.  * Run: main loop
  682.  *****************************************************************************/
  683. static void Run          ( intf_thread_t *p_intf )
  684. {
  685.     for( ;; )
  686.     {
  687.         msleep( INTF_IDLE_SLEEP );
  688.         int canc = vlc_savecancel();
  689.         dbus_connection_read_write_dispatch( p_intf->p_sys->p_conn, 0 );
  690.         /* Get the list of events to process
  691.          *
  692.          * We can't keep the lock on p_intf->p_sys->p_events, else we risk a
  693.          * deadlock:
  694.          * The signal functions could lock mutex X while p_events is locked;
  695.          * While some other function in vlc (playlist) might lock mutex X
  696.          * and then set a variable which would call AllCallback(), which itself
  697.          * needs to lock p_events to add a new event.
  698.          */
  699.         vlc_mutex_lock( &p_intf->p_sys->lock );
  700.         int i_events = vlc_array_count( p_intf->p_sys->p_events );
  701.         callback_info_t* info[i_events];
  702.         for( int i = i_events - 1; i >= 0; i-- )
  703.         {
  704.             info[i] = vlc_array_item_at_index( p_intf->p_sys->p_events, i );
  705.             vlc_array_remove( p_intf->p_sys->p_events, i );
  706.         }
  707.         vlc_mutex_unlock( &p_intf->p_sys->lock );
  708.         for( int i = 0; i < i_events; i++ )
  709.         {
  710.             switch( info[i]->signal )
  711.             {
  712.             case SIGNAL_ITEM_CURRENT:
  713.                 TrackChange( p_intf );
  714.                 break;
  715.             case SIGNAL_INTF_CHANGE:
  716.             case SIGNAL_PLAYLIST_ITEM_APPEND:
  717.             case SIGNAL_PLAYLIST_ITEM_DELETED:
  718.                 TrackListChangeEmit( p_intf, info[i]->signal, info[i]->i_node );
  719.                 break;
  720.             case SIGNAL_RANDOM:
  721.             case SIGNAL_REPEAT:
  722.             case SIGNAL_LOOP:
  723.                 StatusChangeEmit( p_intf );
  724.                 break;
  725.             case SIGNAL_STATE:
  726.                 StateChange( p_intf, info[i]->i_input_state );
  727.                 break;
  728.             default:
  729.                 assert(0);
  730.             }
  731.             free( info[i] );
  732.         }
  733.         vlc_restorecancel( canc );
  734.     }
  735. }
  736. // Get all the callbacks
  737. static int AllCallback( vlc_object_t *p_this, const char *psz_var,
  738.                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
  739. {
  740.     (void)p_this;
  741.     (void)oldval;
  742.     intf_thread_t *p_intf = (intf_thread_t*)p_data;
  743.     callback_info_t *info = malloc( sizeof( callback_info_t ) );
  744.     if( !info )
  745.         return VLC_ENOMEM;
  746.     // Wich event is it ?
  747.     if( !strcmp( "item-current", psz_var ) )
  748.         info->signal = SIGNAL_ITEM_CURRENT;
  749.     else if( !strcmp( "intf-change", psz_var ) )
  750.         info->signal = SIGNAL_INTF_CHANGE;
  751.     else if( !strcmp( "playlist-item-append", psz_var ) )
  752.     {
  753.         info->signal = SIGNAL_PLAYLIST_ITEM_APPEND;
  754.         info->i_node = ((playlist_add_t*)newval.p_address)->i_node;
  755.     }
  756.     else if( !strcmp( "playlist-item-deleted", psz_var ) )
  757.         info->signal = SIGNAL_PLAYLIST_ITEM_DELETED;
  758.     else if( !strcmp( "random", psz_var ) )
  759.         info->signal = SIGNAL_RANDOM;
  760.     else if( !strcmp( "repeat", psz_var ) )
  761.         info->signal = SIGNAL_REPEAT;
  762.     else if( !strcmp( "loop", psz_var ) )
  763.         info->signal = SIGNAL_LOOP;
  764.     else if( !strcmp( "state", psz_var ) )
  765.     {
  766.         info->signal = SIGNAL_STATE;
  767.         info->i_input_state = newval.i_int;
  768.     }
  769.     else
  770.         assert(0);
  771.     // Append the event
  772.     vlc_mutex_lock( &p_intf->p_sys->lock );
  773.     vlc_array_append( p_intf->p_sys->p_events, info );
  774.     vlc_mutex_unlock( &p_intf->p_sys->lock );
  775.     return VLC_SUCCESS;
  776. }
  777. /******************************************************************************
  778.  * CapsChange: player capabilities change signal
  779.  *****************************************************************************/
  780. DBUS_SIGNAL( CapsChangeSignal )
  781. {
  782.     SIGNAL_INIT( "CapsChange" );
  783.     OUT_ARGUMENTS;
  784.     ADD_INT32( &((intf_thread_t*)p_data)->p_sys->i_caps );
  785.     SIGNAL_SEND;
  786. }
  787. /******************************************************************************
  788.  * TrackListChange: tracklist order / length change signal
  789.  *****************************************************************************/
  790. DBUS_SIGNAL( TrackListChangeSignal )
  791. { /* emit the new tracklist lengh */
  792.     SIGNAL_INIT("TrackListChange");
  793.     OUT_ARGUMENTS;
  794.     playlist_t *p_playlist = pl_Hold( (vlc_object_t*) p_data );
  795.     dbus_int32_t i_elements = p_playlist->current.i_size;
  796.     pl_Release( (vlc_object_t*) p_data );
  797.     ADD_INT32( &i_elements );
  798.     SIGNAL_SEND;
  799. }
  800. /*****************************************************************************
  801.  * TrackListChangeEmit: Emits the TrackListChange signal
  802.  *****************************************************************************/
  803. /* FIXME: It is not called on tracklist reordering */
  804. static int TrackListChangeEmit( intf_thread_t *p_intf, int signal, int i_node )
  805. {
  806.     // "playlist-item-append"
  807.     if( signal == SIGNAL_PLAYLIST_ITEM_APPEND )
  808.     {
  809.         /* don't signal when items are added/removed in p_category */
  810.         playlist_t *p_playlist = pl_Hold( p_intf );
  811.         PL_LOCK;
  812.         playlist_item_t *p_item = playlist_ItemGetById( p_playlist, i_node );
  813.         assert( p_item );
  814.         while( p_item->p_parent )
  815.             p_item = p_item->p_parent;
  816.         if( p_item == p_playlist->p_root_category )
  817.         {
  818.             PL_UNLOCK;
  819.             pl_Release( p_intf );
  820.             return VLC_SUCCESS;
  821.         }
  822.         PL_UNLOCK;
  823.         pl_Release( p_intf );
  824.     }
  825.     if( p_intf->p_sys->b_dead )
  826.         return VLC_SUCCESS;
  827.     UpdateCaps( p_intf );
  828.     TrackListChangeSignal( p_intf->p_sys->p_conn, p_intf );
  829.     return VLC_SUCCESS;
  830. }
  831. /*****************************************************************************
  832.  * TrackChange: Playlist item change callback
  833.  *****************************************************************************/
  834. DBUS_SIGNAL( TrackChangeSignal )
  835. { /* emit the metadata of the new item */
  836.     SIGNAL_INIT( "TrackChange" );
  837.     OUT_ARGUMENTS;
  838.     input_item_t *p_item = (input_item_t*) p_data;
  839.     GetInputMeta ( p_item, &args );
  840.     SIGNAL_SEND;
  841. }
  842. /*****************************************************************************
  843.  * StatusChange: Player status change signal
  844.  *****************************************************************************/
  845. DBUS_SIGNAL( StatusChangeSignal )
  846. { /* send the updated status info on the bus */
  847.     SIGNAL_INIT( "StatusChange" );
  848.     OUT_ARGUMENTS;
  849.     /* we're called from a callback of input_thread_t, so it can not be
  850.      * destroyed before we return */
  851.     MarshalStatus( (intf_thread_t*) p_data, &args );
  852.     SIGNAL_SEND;
  853. }
  854. /*****************************************************************************
  855.  * StateChange: callback on input "state"
  856.  *****************************************************************************/
  857. //static int StateChange( vlc_object_t *p_this, const char* psz_var,
  858. //            vlc_value_t oldval, vlc_value_t newval, void *p_data )
  859. static int StateChange( intf_thread_t *p_intf, int i_input_state )
  860. {
  861.     intf_sys_t          *p_sys      = p_intf->p_sys;
  862.     playlist_t          *p_playlist;
  863.     input_thread_t      *p_input;
  864.     input_item_t        *p_item;
  865.     if( p_intf->p_sys->b_dead )
  866.         return VLC_SUCCESS;
  867.     UpdateCaps( p_intf );
  868.     if( !p_sys->b_meta_read && i_input_state == PLAYING_S )
  869.     {
  870.         p_playlist = pl_Hold( p_intf );
  871.         p_input = playlist_CurrentInput( p_playlist );
  872.         if( p_input )
  873.         {
  874.             p_item = input_GetItem( p_input );
  875.             if( p_item )
  876.             {
  877.                 p_sys->b_meta_read = true;
  878.                 TrackChangeSignal( p_sys->p_conn, p_item );
  879.             }
  880.             vlc_object_release( p_input );
  881.         }
  882.         pl_Release( p_intf );
  883.     }
  884.     if( i_input_state == PLAYING_S || i_input_state == PAUSE_S ||
  885.         i_input_state == END_S )
  886.     {
  887.         StatusChangeSignal( p_sys->p_conn, p_intf );
  888.     }
  889.     return VLC_SUCCESS;
  890. }
  891. /*****************************************************************************
  892.  * StatusChangeEmit: Emits the StatusChange signal
  893.  *****************************************************************************/
  894. static int StatusChangeEmit( intf_thread_t * p_intf )
  895. {
  896.     if( p_intf->p_sys->b_dead )
  897.         return VLC_SUCCESS;
  898.     UpdateCaps( p_intf );
  899.     StatusChangeSignal( p_intf->p_sys->p_conn, p_intf );
  900.     return VLC_SUCCESS;
  901. }
  902. /*****************************************************************************
  903.  * TrackChange: callback on playlist "item-current"
  904.  *****************************************************************************/
  905. static int TrackChange( intf_thread_t *p_intf )
  906. {
  907.     intf_sys_t          *p_sys      = p_intf->p_sys;
  908.     playlist_t          *p_playlist;
  909.     input_thread_t      *p_input    = NULL;
  910.     input_item_t        *p_item     = NULL;
  911.     if( p_intf->p_sys->b_dead )
  912.         return VLC_SUCCESS;
  913.     p_sys->b_meta_read = false;
  914.     p_playlist = pl_Hold( p_intf );
  915.     p_input = playlist_CurrentInput( p_playlist );
  916.     if( !p_input )
  917.     {
  918.         pl_Release( p_intf );
  919.         return VLC_SUCCESS;
  920.     }
  921.     pl_Release( p_intf );
  922.     p_item = input_GetItem( p_input );
  923.     if( !p_item )
  924.     {
  925.         vlc_object_release( p_input );
  926.         return VLC_EGENERIC;
  927.     }
  928.     if( input_item_IsPreparsed( p_item ) )
  929.     {
  930.         p_sys->b_meta_read = true;
  931.         TrackChangeSignal( p_sys->p_conn, p_item );
  932.     }
  933.     var_AddCallback( p_input, "state", AllCallback, p_intf );
  934.     vlc_object_release( p_input );
  935.     return VLC_SUCCESS;
  936. }
  937. /*****************************************************************************
  938.  * UpdateCaps: update p_sys->i_caps
  939.  * This function have to be called with the playlist unlocked
  940.  ****************************************************************************/
  941. static int UpdateCaps( intf_thread_t* p_intf )
  942. {
  943.     intf_sys_t* p_sys = p_intf->p_sys;
  944.     dbus_int32_t i_caps = CAPS_CAN_HAS_TRACKLIST;
  945.     playlist_t* p_playlist = pl_Hold( p_intf );
  946.     PL_LOCK;
  947.     if( p_playlist->current.i_size > 0 )
  948.         i_caps |= CAPS_CAN_PLAY | CAPS_CAN_GO_PREV | CAPS_CAN_GO_NEXT;
  949.     PL_UNLOCK;
  950.     input_thread_t* p_input = playlist_CurrentInput( p_playlist );
  951.     if( p_input )
  952.     {
  953.         /* XXX: if UpdateCaps() is called too early, these are
  954.          * unconditionnaly true */
  955.         if( var_GetBool( p_input, "can-pause" ) )
  956.             i_caps |= CAPS_CAN_PAUSE;
  957.         if( var_GetBool( p_input, "can-seek" ) )
  958.             i_caps |= CAPS_CAN_SEEK;
  959.         vlc_object_release( p_input );
  960.     }
  961.     pl_Release( p_intf );
  962.     if( p_sys->b_meta_read )
  963.         i_caps |= CAPS_CAN_PROVIDE_METADATA;
  964.     if( i_caps != p_intf->p_sys->i_caps )
  965.     {
  966.         p_sys->i_caps = i_caps;
  967.         CapsChangeSignal( p_intf->p_sys->p_conn, (vlc_object_t*)p_intf );
  968.     }
  969.     return VLC_SUCCESS;
  970. }
  971. /*****************************************************************************
  972.  * GetInputMeta: Fill a DBusMessage with the given input item metadata
  973.  *****************************************************************************/
  974. #define ADD_META( entry, type, data ) 
  975.     if( data ) { 
  976.         dbus_message_iter_open_container( &dict, DBUS_TYPE_DICT_ENTRY, 
  977.                 NULL, &dict_entry ); 
  978.         dbus_message_iter_append_basic( &dict_entry, DBUS_TYPE_STRING, 
  979.                 &ppsz_meta_items[entry] ); 
  980.         dbus_message_iter_open_container( &dict_entry, DBUS_TYPE_VARIANT, 
  981.                 type##_AS_STRING, &variant ); 
  982.         dbus_message_iter_append_basic( &variant, 
  983.                 type, 
  984.                 & data ); 
  985.         dbus_message_iter_close_container( &dict_entry, &variant ); 
  986.         dbus_message_iter_close_container( &dict, &dict_entry ); }
  987. #define ADD_VLC_META_STRING( entry, item ) 
  988.     { 
  989.         char * psz = input_item_Get##item( p_input );
  990.         ADD_META( entry, DBUS_TYPE_STRING, 
  991.                   psz ); 
  992.         free( psz ); 
  993.     }
  994. static int GetInputMeta( input_item_t* p_input,
  995.                         DBusMessageIter *args )
  996. {
  997.     DBusMessageIter dict, dict_entry, variant;
  998.     /* We need the track length to be expressed in milli-seconds
  999.      * instead of µ-seconds */
  1000.     dbus_int64_t i_length = ( input_item_GetDuration( p_input ) / 1000 );
  1001.     const char* ppsz_meta_items[] =
  1002.     {
  1003.     "title", "artist", "genre", "copyright", "album", "tracknum",
  1004.     "description", "rating", "date", "setting", "url", "language",
  1005.     "nowplaying", "publisher", "encodedby", "arturl", "trackid",
  1006.     "status", "location", "length", "video-codec", "audio-codec",
  1007.     "video-bitrate", "audio-bitrate", "audio-samplerate"
  1008.     };
  1009.     dbus_message_iter_open_container( args, DBUS_TYPE_ARRAY, "{sv}", &dict );
  1010.     ADD_VLC_META_STRING( 0,  Title );
  1011.     ADD_VLC_META_STRING( 1,  Artist );
  1012.     ADD_VLC_META_STRING( 2,  Genre );
  1013.     ADD_VLC_META_STRING( 3,  Copyright );
  1014.     ADD_VLC_META_STRING( 4,  Album );
  1015.     ADD_VLC_META_STRING( 5,  TrackNum );
  1016.     ADD_VLC_META_STRING( 6,  Description );
  1017.     ADD_VLC_META_STRING( 7,  Rating );
  1018.     ADD_VLC_META_STRING( 8,  Date );
  1019.     ADD_VLC_META_STRING( 9,  Setting );
  1020.     ADD_VLC_META_STRING( 10, URL );
  1021.     ADD_VLC_META_STRING( 11, Language );
  1022.     ADD_VLC_META_STRING( 12, NowPlaying );
  1023.     ADD_VLC_META_STRING( 13, Publisher );
  1024.     ADD_VLC_META_STRING( 14, EncodedBy );
  1025.     ADD_VLC_META_STRING( 15, ArtURL );
  1026.     ADD_VLC_META_STRING( 16, TrackID );
  1027.     vlc_mutex_lock( &p_input->lock );
  1028.     if( p_input->p_meta )
  1029.         ADD_META( 17, DBUS_TYPE_INT32, p_input->p_meta->i_status );
  1030.     vlc_mutex_unlock( &p_input->lock );
  1031.     ADD_VLC_META_STRING( 18, URI );
  1032.     ADD_META( 19, DBUS_TYPE_INT64, i_length );
  1033.     dbus_message_iter_close_container( args, &dict );
  1034.     return VLC_SUCCESS;
  1035. }
  1036. #undef ADD_META
  1037. #undef ADD_VLC_META_STRING
  1038. /*****************************************************************************
  1039.  * MarshalStatus: Fill a DBusMessage with the current player status
  1040.  *****************************************************************************/
  1041. static int MarshalStatus( intf_thread_t* p_intf, DBusMessageIter* args )
  1042. { /* This is NOT the right way to do that, it would be better to sore
  1043.      the status information in p_sys and update it on change, thus
  1044.      avoiding a long lock */
  1045.     DBusMessageIter status;
  1046.     dbus_int32_t i_state, i_random, i_repeat, i_loop;
  1047.     vlc_value_t val;
  1048.     playlist_t* p_playlist = NULL;
  1049.     input_thread_t* p_input = NULL;
  1050.     p_playlist = pl_Hold( p_intf );
  1051.     i_state = 2;
  1052.     p_input = playlist_CurrentInput( p_playlist );
  1053.     if( p_input )
  1054.     {
  1055.         var_Get( p_input, "state", &val );
  1056.         if( val.i_int >= END_S )
  1057.             i_state = 2;
  1058.         else if( val.i_int == PAUSE_S )
  1059.             i_state = 1;
  1060.         else if( val.i_int <= PLAYING_S )
  1061.             i_state = 0;
  1062.         vlc_object_release( p_input );
  1063.     }
  1064.     i_random = var_CreateGetBool( p_playlist, "random" );
  1065.     i_repeat = var_CreateGetBool( p_playlist, "repeat" );
  1066.     i_loop = var_CreateGetBool( p_playlist, "loop" );
  1067.     pl_Release( p_intf );
  1068.     dbus_message_iter_open_container( args, DBUS_TYPE_STRUCT, NULL, &status );
  1069.     dbus_message_iter_append_basic( &status, DBUS_TYPE_INT32, &i_state );
  1070.     dbus_message_iter_append_basic( &status, DBUS_TYPE_INT32, &i_random );
  1071.     dbus_message_iter_append_basic( &status, DBUS_TYPE_INT32, &i_repeat );
  1072.     dbus_message_iter_append_basic( &status, DBUS_TYPE_INT32, &i_loop );
  1073.     dbus_message_iter_close_container( args, &status );
  1074.     return VLC_SUCCESS;
  1075. }