]> git.sesse.net Git - vlc/blob - modules/misc/inhibit.c
Yet another one from Philipp Weissenbacher.
[vlc] / modules / misc / inhibit.c
1 /*****************************************************************************
2  * inhibit.c : prevents the computer from suspending when VLC is playing
3  *****************************************************************************
4  * Copyright © 2007 Rafaël Carré
5  * $Id$
6  *
7  * Author: Rafaël Carré <funman@videolanorg>
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 /*
25  * Based on freedesktop Power Management Specification version 0.2
26  * http://people.freedesktop.org/~hughsient/temp/power-management-spec-0.2.html
27  */
28
29 /*****************************************************************************
30  * Preamble
31  *****************************************************************************/
32
33 #include <vlc/vlc.h>
34 #include <vlc_input.h>
35 #include <vlc_interface.h>
36
37 #include <dbus/dbus.h>
38
39 #define PM_SERVICE   "org.freedesktop.PowerManagement"
40 #define PM_PATH     "/org/freedesktop/PowerManagement/Inhibit"
41 #define PM_INTERFACE "org.freedesktop.PowerManagement.Inhibit"
42
43 /*****************************************************************************
44  * Local prototypes
45  *****************************************************************************/
46 static int  Activate     ( vlc_object_t * );
47 static void Deactivate   ( vlc_object_t * );
48
49 static void Run          ( intf_thread_t *p_intf );
50
51 struct intf_sys_t
52 {
53     DBusConnection  *p_conn;
54     dbus_uint32_t   i_cookie;
55 };
56
57 /*****************************************************************************
58  * Module descriptor
59  *****************************************************************************/
60 vlc_module_begin();
61     set_description( _("Power Management Inhibitor") );
62     set_capability( "interface", 0 );
63     set_callbacks( Activate, Deactivate );
64 vlc_module_end();
65
66 /*****************************************************************************
67  * Activate: initialize and create stuff
68  *****************************************************************************/
69 static int Activate( vlc_object_t *p_this )
70 {
71     intf_thread_t *p_intf = (intf_thread_t*)p_this;
72     DBusError     error;
73
74
75     p_intf->pf_run = Run;
76
77     p_intf->p_sys = (intf_sys_t *) calloc( 1, sizeof( intf_sys_t ) );
78
79     if( !p_intf->p_sys )
80         return VLC_ENOMEM;
81
82     p_intf->p_sys->i_cookie = 0;
83
84     dbus_error_init( &error );
85     p_intf->p_sys->p_conn = dbus_bus_get( DBUS_BUS_SESSION, &error );
86     if( !p_intf->p_sys->p_conn )
87     {
88         msg_Err( p_this, "Failed to connect to the D-Bus session daemon: %s",
89                 error.message );
90         dbus_error_free( &error );
91         free( p_intf->p_sys );
92         return VLC_EGENERIC;
93     }
94
95     return VLC_SUCCESS;
96 }
97
98 /*****************************************************************************
99  * Deactivate: uninitialize and cleanup
100  *****************************************************************************/
101 static void Deactivate( vlc_object_t *p_this )
102 {
103     intf_thread_t *p_intf = (intf_thread_t*)p_this;
104     dbus_connection_unref( p_intf->p_sys->p_conn );
105     free( p_intf->p_sys );
106 }
107
108 /*****************************************************************************
109  * Inhibit: Notify the power management daemon that it shouldn't suspend
110  * the computer because of inactivity
111  *
112  * returns VLC_FALSE if Out of memory, else VLC_TRUE
113  *****************************************************************************/
114 static int Inhibit( intf_thread_t *p_intf )
115 {
116     DBusConnection *p_conn;
117     DBusMessage *p_msg;
118     DBusMessageIter args;
119     DBusMessage *p_reply;
120     DBusError error;
121     dbus_error_init( &error );
122     dbus_uint32_t i_cookie;
123
124     p_conn = p_intf->p_sys->p_conn;
125
126     p_msg = dbus_message_new_method_call( PM_SERVICE, PM_PATH, PM_INTERFACE,
127                                           "Inhibit" );
128     if( !p_msg )
129         return VLC_FALSE;
130
131     dbus_message_iter_init_append( p_msg, &args );
132
133     char *psz_app = strdup( PACKAGE );
134     if( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_app ) )
135     {
136         free( psz_app );
137         dbus_message_unref( p_msg );
138         return VLC_FALSE;
139     }
140     free( psz_app );
141
142     char *psz_inhibit_reason = strdup( "Playing some media." );
143     if( !psz_inhibit_reason )
144     {
145         dbus_message_unref( p_msg );
146         return VLC_FALSE;
147     }
148     if( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING,
149                                          &psz_inhibit_reason ) )
150     {
151         free( psz_inhibit_reason );
152         dbus_message_unref( p_msg );
153         return VLC_FALSE;
154     }
155     free( psz_inhibit_reason );
156
157     p_reply = dbus_connection_send_with_reply_and_block( p_conn, p_msg,
158         50, &error ); /* blocks 50ms maximum */
159
160     dbus_message_unref( p_msg );
161     if( p_reply == NULL )
162     {   /* g-p-m is not active, or too slow. Better luck next time? */
163         return VLC_TRUE;
164     }
165
166     /* extract the cookie from the reply */
167     if( dbus_message_get_args( p_reply, &error,
168             DBUS_TYPE_UINT32, &i_cookie,
169             DBUS_TYPE_INVALID ) == FALSE )
170     {
171         return VLC_FALSE;
172     }
173
174     /* Save the cookie */
175     p_intf->p_sys->i_cookie = i_cookie;
176     return VLC_TRUE;
177 }
178
179 /*****************************************************************************
180  * UnInhibit: Notify the power management daemon that we aren't active anymore
181  *
182  * returns VLC_FALSE if Out of memory, else VLC_TRUE
183  *****************************************************************************/
184 static int UnInhibit( intf_thread_t *p_intf )
185 {
186     DBusConnection *p_conn;
187     DBusMessage *p_msg;
188     DBusMessageIter args;
189     DBusError error;
190     dbus_error_init( &error );
191     dbus_uint32_t i_cookie;
192
193     p_conn = p_intf->p_sys->p_conn;
194
195     p_msg = dbus_message_new_method_call( PM_SERVICE, PM_PATH, PM_INTERFACE,
196                                           "UnInhibit" );
197     if( !p_msg )
198         return VLC_FALSE;
199
200     dbus_message_iter_init_append( p_msg, &args );
201
202     i_cookie = p_intf->p_sys->i_cookie;
203     if( !dbus_message_iter_append_basic( &args, DBUS_TYPE_UINT32, &i_cookie ) )
204     {
205         dbus_message_unref( p_msg );
206         return VLC_FALSE;
207     }
208
209     if( !dbus_connection_send( p_conn, p_msg, NULL ) )
210         return VLC_FALSE;
211     dbus_connection_flush( p_conn );
212
213     dbus_message_unref( p_msg );
214
215     p_intf->p_sys->i_cookie = 0;
216     return VLC_TRUE;
217 }
218
219 /*****************************************************************************
220  * Run: main thread
221  *****************************************************************************/
222 static void Run( intf_thread_t *p_intf )
223 {
224     vlc_object_lock( p_intf );
225     for(;;)
226     {
227         input_thread_t *p_input;
228
229         /* Check playing state every 30 seconds */
230         if( vlc_object_timedwait( p_intf, mdate() + 30000000 ) < 0 )
231             break;
232
233         p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
234         if( p_input )
235         {
236             if( PLAYING_S == p_input->i_state && !p_intf->p_sys->i_cookie )
237             {
238                 if( !Inhibit( p_intf ) )
239                 {
240                     vlc_object_release( p_input );
241                     goto end;
242                 }
243             }
244             else if( p_intf->p_sys->i_cookie )
245             {
246                 if( !UnInhibit( p_intf ) )
247                 {
248                     vlc_object_release( p_input );
249                     goto end;
250                 }
251             }
252             vlc_object_release( p_input );
253         }
254         else if( p_intf->p_sys->i_cookie )
255         {
256             if( !UnInhibit( p_intf ) )
257                 goto end;
258         }
259     }
260
261 end:
262     vlc_object_unlock( p_intf );
263 }