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

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * telepathy.c : changes Telepathy Presence information using MissionControl
  3.  *****************************************************************************
  4.  * Copyright © 2007-2009 the VideoLAN team
  5.  * $Id: 7b55a8a49ca5015f19179c3c394eb190c8f446c6 $
  6.  *
  7.  * Author: Rafaël Carré <funman@videoanorg>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #ifdef HAVE_CONFIG_H
  27. # include "config.h"
  28. #endif
  29. #include <vlc_common.h>
  30. #include <vlc_plugin.h>
  31. #include <vlc_interface.h>
  32. #include <vlc_playlist.h>
  33. #include <vlc_strings.h>
  34. #include <dbus/dbus.h>
  35. /*****************************************************************************
  36.  * intf_sys_t: description and status of log interface
  37.  *****************************************************************************/
  38. struct intf_sys_t
  39. {
  40.     char            *psz_format;
  41.     DBusConnection  *p_conn;
  42.     int             i_id;
  43.     int             i_item_changes;
  44. };
  45. /*****************************************************************************
  46.  * Local prototypes
  47.  *****************************************************************************/
  48. static int  Open    ( vlc_object_t * );
  49. static void Close   ( vlc_object_t * );
  50. static int ItemChange( vlc_object_t *, const char *,
  51.                        vlc_value_t, vlc_value_t, void * );
  52. static int StateChange( vlc_object_t *, const char *,
  53.                         vlc_value_t, vlc_value_t, void * );
  54. static int SendToTelepathy( intf_thread_t *, const char * );
  55. /*****************************************************************************
  56.  * Module descriptor
  57.  *****************************************************************************/
  58. #define FORMAT_DEFAULT "$a - $t"
  59. #define FORMAT_TEXT N_("Title format string")
  60. #define FORMAT_LONGTEXT N_("Format of the string to send to Telepathy." 
  61. "Defaults to "Artist - Title" ($a - $t). " 
  62. "You can use the following substitutions: " 
  63. "$a Artist, $b Album, $c Copyright, $d Description, $e Encoder, $g Genre, " 
  64. "$l Language, $n number, $p Now Playing, $r Rating, $s Subtitles language, " 
  65. "$t Title, $u URL, $A Date, $B Bitrate, $C Chapter, $D Duration, $F URI, " 
  66. "$I Video Title, $L Time Remaining, $N Name, $O Audio language, $P Position, " 
  67. "$R Rate, $S Sample rate, $T Time elapsed, $U Publisher, $V Volume")
  68. vlc_module_begin ()
  69.     set_category( CAT_INTERFACE )
  70.     set_subcategory( SUBCAT_INTERFACE_CONTROL )
  71.     set_shortname( "Telepathy" )
  72.     set_description( N_("Telepathy "Now Playing" (MissionControl)") )
  73.     add_string( "telepathy-format", FORMAT_DEFAULT, NULL,
  74.                 FORMAT_TEXT, FORMAT_LONGTEXT, false )
  75.     set_capability( "interface", 0 )
  76.     set_callbacks( Open, Close )
  77. vlc_module_end ()
  78. /*****************************************************************************
  79.  * Open: initialize and create stuff
  80.  *****************************************************************************/
  81. static int Open( vlc_object_t *p_this )
  82. {
  83.     intf_thread_t *p_intf = (intf_thread_t *)p_this;
  84.     playlist_t *p_playlist;
  85.     DBusError       error;
  86.     p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
  87.     if( !p_intf->p_sys )
  88.         return VLC_ENOMEM;
  89.     /* connect to the session bus */
  90.     dbus_error_init( &error );
  91.     p_intf->p_sys->p_conn = dbus_bus_get( DBUS_BUS_SESSION, &error );
  92.     if( !p_intf->p_sys->p_conn )
  93.     {
  94.         msg_Err( p_this, "Failed to connect to the DBus session daemon: %s",
  95.                 error.message );
  96.         dbus_error_free( &error );
  97.         free( p_intf->p_sys );
  98.         return VLC_EGENERIC;
  99.     }
  100.     p_intf->p_sys->psz_format = config_GetPsz( p_intf, "telepathy-format" );
  101.     if( !p_intf->p_sys->psz_format )
  102.     {
  103.         msg_Dbg( p_intf, "no format provided" );
  104.         p_intf->p_sys->psz_format = strdup( FORMAT_DEFAULT );
  105.     }
  106.     msg_Dbg( p_intf, "using format: %s", p_intf->p_sys->psz_format );
  107.     p_intf->p_sys->i_id = -1;
  108.     p_playlist = pl_Hold( p_intf );
  109.     var_AddCallback( p_playlist, "item-change", ItemChange, p_intf );
  110.     var_AddCallback( p_playlist, "item-current", ItemChange, p_intf );
  111.     pl_Release( p_intf );
  112.     return VLC_SUCCESS;
  113. }
  114. /*****************************************************************************
  115.  * Close: destroy interface stuff
  116.  *****************************************************************************/
  117. static void Close( vlc_object_t *p_this )
  118. {
  119.     intf_thread_t *p_intf = (intf_thread_t *)p_this;
  120.     playlist_t *p_playlist = pl_Hold( p_this );
  121.     input_thread_t *p_input = NULL;
  122.     var_DelCallback( p_playlist, "item-change", ItemChange, p_intf );
  123.     var_DelCallback( p_playlist, "item-current", ItemChange, p_intf );
  124.     if( (p_input = playlist_CurrentInput( p_playlist )) )
  125.     {
  126.         var_DelCallback( p_input, "state", StateChange, p_intf );
  127.         vlc_object_release( p_input );
  128.     }
  129.     pl_Release( p_this );
  130.     /* Clears the Presence message ... else it looks like we're still playing
  131.      * something although VLC (or the Telepathy plugin) is closed */
  132.     /* Do not check for VLC_ENOMEM as we're closing */
  133.     SendToTelepathy( p_intf, "" );
  134.     /* we won't use the DBus connection anymore */
  135.     dbus_connection_unref( p_intf->p_sys->p_conn );
  136.     /* Destroy structure */
  137.     free( p_intf->p_sys->psz_format );
  138.     free( p_intf->p_sys );
  139. }
  140. /*****************************************************************************
  141.  * ItemChange: Playlist item change callback
  142.  *****************************************************************************/
  143. static int ItemChange( vlc_object_t *p_this, const char *psz_var,
  144.                        vlc_value_t oldval, vlc_value_t newval, void *param )
  145. {
  146.     VLC_UNUSED(oldval);
  147.     intf_thread_t *p_intf = (intf_thread_t *)param;
  148.     playlist_t* p_playlist = (playlist_t*) p_this;
  149.     char *psz_buf = NULL;
  150.     input_thread_t *p_input;
  151.     bool b_is_item_current = !strcmp( "item-current", psz_var );
  152.     /* Don't update Telepathy presence each time an item has been preparsed */
  153.     if( b_is_item_current )
  154.     { /* stores the current input item id */
  155.         p_intf->p_sys->i_id = newval.i_int;
  156.         p_intf->p_sys->i_item_changes = 0;
  157.     }
  158.     else
  159.     {
  160.         if( newval.i_int != p_intf->p_sys->i_id ) /* "item-change" */
  161.             return VLC_SUCCESS;
  162.         /* Some variable bitrate inputs call "item-change callbacks each time
  163.          * their length is updated, that is several times per second.
  164.          * We'll limit the number of changes to 10 per input. */
  165.         if( p_intf->p_sys->i_item_changes > 10 )
  166.             return VLC_SUCCESS;
  167.         p_intf->p_sys->i_item_changes++;
  168.     }
  169.     p_input = playlist_CurrentInput( p_playlist );
  170.     if( !p_input ) return VLC_SUCCESS;
  171.     if( p_input->b_dead || !input_GetItem(p_input)->psz_name )
  172.     {
  173.         vlc_object_release( p_input );
  174.         /* Not playing anything ... */
  175.         switch( SendToTelepathy( p_intf, "" ) )
  176.         {
  177.             case VLC_ENOMEM:
  178.                 return VLC_ENOMEM;
  179.             default:
  180.                 return VLC_SUCCESS;
  181.         }
  182.     }
  183.     if( b_is_item_current )
  184.         var_AddCallback( p_input, "state", StateChange, p_intf );
  185.     /* We format the string to be displayed */
  186.     psz_buf = str_format_meta( (vlc_object_t*) p_intf,
  187.             p_intf->p_sys->psz_format );
  188.     /* We don't need the input anymore */
  189.     vlc_object_release( p_input );
  190.     if( SendToTelepathy( p_intf, psz_buf ) == VLC_ENOMEM )
  191.     {
  192.         free( psz_buf );
  193.         return VLC_ENOMEM;
  194.     }
  195.     free( psz_buf );
  196.     return VLC_SUCCESS;
  197. }
  198. /*****************************************************************************
  199.  * StateChange: State change callback
  200.  *****************************************************************************/
  201. static int StateChange( vlc_object_t *p_this, const char *psz_var,
  202.                        vlc_value_t oldval, vlc_value_t newval, void *param )
  203. {
  204.     VLC_UNUSED(p_this); VLC_UNUSED(psz_var); VLC_UNUSED(oldval);
  205.     intf_thread_t *p_intf = (intf_thread_t *)param;
  206.     if( newval.i_int >= END_S )
  207.         return SendToTelepathy( p_intf, "" );
  208.     return VLC_SUCCESS;
  209. }
  210. /*****************************************************************************
  211.  * SendToTelepathy
  212.  *****************************************************************************/
  213. static int SendToTelepathy( intf_thread_t *p_intf, const char *psz_msg )
  214. {
  215.     DBusConnection *p_conn;
  216.     DBusMessage *p_msg;
  217.     DBusMessage *p_reply;
  218.     DBusMessageIter args;
  219.     DBusError error;
  220.     dbus_error_init( &error );
  221.     dbus_uint32_t i_status;
  222.     p_conn = p_intf->p_sys->p_conn;
  223.     /* first we need to get the actual status */
  224.     p_msg = dbus_message_new_method_call(
  225.             "org.freedesktop.Telepathy.MissionControl",
  226.            "/org/freedesktop/Telepathy/MissionControl",
  227.             "org.freedesktop.Telepathy.MissionControl",
  228.             "GetPresence" );
  229.     if( !p_msg )
  230.         return VLC_ENOMEM;
  231.     p_reply = dbus_connection_send_with_reply_and_block( p_conn, p_msg,
  232.         50, &error ); /* blocks 50ms maximum */
  233.     dbus_message_unref( p_msg );
  234.     if( p_reply == NULL )
  235.     {   /* MC is not active, or too slow. Better luck next time? */
  236.         return VLC_SUCCESS;
  237.     }
  238.     /* extract the status from the reply */
  239.     if( dbus_message_get_args( p_reply, &error,
  240.             DBUS_TYPE_UINT32, &i_status,
  241.             DBUS_TYPE_INVALID ) == FALSE )
  242.     {
  243.         return VLC_ENOMEM;
  244.     }
  245.     p_msg = dbus_message_new_method_call(
  246.             "org.freedesktop.Telepathy.MissionControl",
  247.            "/org/freedesktop/Telepathy/MissionControl",
  248.             "org.freedesktop.Telepathy.MissionControl",
  249.             "SetPresence" );
  250.     if( !p_msg )
  251.         return VLC_ENOMEM;
  252.     dbus_message_iter_init_append( p_msg, &args );
  253.     /* first argument is the status */
  254.     if( !dbus_message_iter_append_basic( &args, DBUS_TYPE_UINT32, &i_status ) )
  255.     {
  256.         dbus_message_unref( p_msg );
  257.         return VLC_ENOMEM;
  258.     }
  259.     /* second argument is the message */
  260.     if( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_msg ) )
  261.     {
  262.         dbus_message_unref( p_msg );
  263.         return VLC_ENOMEM;
  264.     }
  265.     if( !dbus_connection_send( p_conn, p_msg, NULL ) )
  266.         return VLC_ENOMEM;
  267.     dbus_connection_flush( p_conn );
  268.     dbus_message_unref( p_msg );
  269.     return VLC_SUCCESS;
  270. }