demux: mp4: avoid audio cuts on seek
[vlc.git] / modules / lua / extension_thread.c
blob7db1c0ba0794fb0ba471a52bcc1d4b02725e2a9b
1 /*****************************************************************************
2 * extension_thread.c: Extensions Manager, Threads manager (no Lua here)
3 *****************************************************************************
4 * Copyright (C) 2009-2010 VideoLAN and authors
5 * $Id$
7 * Authors: Jean-Philippe André < jpeg # videolan.org >
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.
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.
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 *****************************************************************************/
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
28 #include "vlc.h"
29 #include "extension.h"
30 #include "assert.h"
32 struct thread_sys_t
34 extensions_manager_t *p_mgr;
35 extension_t *p_ext;
38 /** Thread Run */
39 static void* Run( void *data );
40 static void FreeCommands( struct command_t *command );
42 /**
43 * Activate an extension
44 * @param p_mgr This manager
45 * @param p_ext Extension to activate
46 * @return The usual VLC return codes
47 **/
48 int Activate( extensions_manager_t *p_mgr, extension_t *p_ext )
50 assert( p_ext != NULL );
52 struct extension_sys_t *p_sys = p_ext->p_sys;
53 assert( p_sys != NULL );
55 vlc_mutex_lock( &p_sys->command_lock );
56 if ( p_sys->b_activated == false )
58 /* Prepare first command */
59 assert(p_sys->command == NULL);
60 p_sys->command = calloc( 1, sizeof( struct command_t ) );
61 if( !p_sys->command )
63 vlc_mutex_unlock( &p_sys->command_lock );
64 return VLC_ENOMEM;
66 p_sys->command->i_command = CMD_ACTIVATE; /* No params */
67 if (p_sys->b_thread_running == true)
69 msg_Dbg( p_mgr, "Reactivating extension %s", p_ext->psz_title);
70 vlc_cond_signal( &p_sys->wait );
73 vlc_mutex_unlock( &p_sys->command_lock );
75 if (p_sys->b_thread_running == true)
76 return VLC_SUCCESS;
78 msg_Dbg( p_mgr, "Activating extension '%s'", p_ext->psz_title );
79 /* Start thread */
80 p_sys->b_exiting = false;
81 p_sys->b_thread_running = true;
83 if( vlc_clone( &p_sys->thread, Run, p_ext, VLC_THREAD_PRIORITY_LOW )
84 != VLC_SUCCESS )
86 p_sys->b_exiting = true;
87 p_sys->b_thread_running = false;
88 return VLC_ENOMEM;
91 return VLC_SUCCESS;
94 /** Recursively drop and free commands starting from "command" */
95 static void FreeCommands( struct command_t *command )
97 if( !command ) return;
98 struct command_t *next = command->next;
99 switch( command->i_command )
101 case CMD_ACTIVATE:
102 case CMD_DEACTIVATE:
103 case CMD_CLICK: // Arg1 must not be freed
104 break;
106 case CMD_TRIGGERMENU:
107 case CMD_PLAYING_CHANGED:
108 free( command->data[0] ); // Arg1 is int*, to free
109 break;
111 default:
112 break;
114 free( command );
115 FreeCommands( next );
118 bool QueueDeactivateCommand( extension_t *p_ext )
120 struct command_t *cmd = calloc( 1, sizeof( struct command_t ) );
121 if( unlikely( cmd == NULL ) )
122 return false;
123 /* Free the list of commands */
124 if( p_ext->p_sys->command )
125 FreeCommands( p_ext->p_sys->command->next );
127 /* Push command */
129 cmd->i_command = CMD_DEACTIVATE;
130 if( p_ext->p_sys->command )
131 p_ext->p_sys->command->next = cmd;
132 else
133 p_ext->p_sys->command = cmd;
135 vlc_cond_signal( &p_ext->p_sys->wait );
136 return true;
139 /** Deactivate this extension: pushes immediate command and drops queued */
140 int Deactivate( extensions_manager_t *p_mgr, extension_t *p_ext )
142 vlc_mutex_lock( &p_ext->p_sys->command_lock );
144 if( p_ext->p_sys->b_exiting )
146 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
147 return VLC_EGENERIC;
150 if( p_ext->p_sys->p_progress_id != NULL )
152 // Extension is stuck, kill it now
153 vlc_dialog_release( p_mgr, p_ext->p_sys->p_progress_id );
154 p_ext->p_sys->p_progress_id = NULL;
155 KillExtension( p_mgr, p_ext );
156 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
157 return VLC_SUCCESS;
160 bool b_success = QueueDeactivateCommand( p_ext );
161 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
163 return b_success ? VLC_SUCCESS : VLC_ENOMEM;
166 /* MUST be called with command_lock held */
167 void KillExtension( extensions_manager_t *p_mgr, extension_t *p_ext )
169 msg_Dbg( p_mgr, "Killing extension now" );
170 vlclua_fd_interrupt( &p_ext->p_sys->dtable );
171 p_ext->p_sys->b_activated = false;
172 p_ext->p_sys->b_exiting = true;
173 vlc_cond_signal( &p_ext->p_sys->wait );
176 /** Push a UI command */
177 int PushCommand__( extension_t *p_ext, bool b_unique, command_type_e i_command,
178 va_list args )
180 /* Create command */
181 struct command_t *cmd = calloc( 1, sizeof( struct command_t ) );
182 if( unlikely( cmd == NULL ) )
183 return VLC_ENOMEM;
184 cmd->i_command = i_command;
185 switch( i_command )
187 case CMD_CLICK:
188 cmd->data[0] = va_arg( args, void* );
189 break;
190 case CMD_TRIGGERMENU:
192 int *pi = malloc( sizeof( int ) );
193 if( !pi )
195 free( cmd );
196 return VLC_ENOMEM;
198 *pi = va_arg( args, int );
199 cmd->data[0] = pi;
201 break;
202 case CMD_PLAYING_CHANGED:
204 int *pi = malloc( sizeof( int ) );
205 if( !pi )
207 free( cmd );
208 return VLC_ENOMEM;
210 *pi = va_arg( args, int );
211 cmd->data[0] = pi;
213 break;
214 case CMD_CLOSE:
215 case CMD_SET_INPUT:
216 case CMD_UPDATE_META:
217 // Nothing to do here
218 break;
219 default:
220 msg_Dbg( p_ext->p_sys->p_mgr,
221 "Unknown command send to extension: %d", i_command );
222 break;
225 vlc_mutex_lock( &p_ext->p_sys->command_lock );
227 /* Push command to the end of the queue */
228 struct command_t *last = p_ext->p_sys->command;
229 if( !last )
231 p_ext->p_sys->command = cmd;
233 else
235 bool b_skip = false;
236 while( last->next != NULL )
238 if( b_unique && last->i_command == i_command )
240 // Do not push this 'unique' command a second time
241 b_skip = !memcmp( last->data, cmd->data, sizeof( cmd->data ) );
242 break;
244 else
246 last = last->next;
249 if( !b_skip )
251 last->next = cmd;
253 else
255 FreeCommands( cmd );
259 vlc_cond_signal( &p_ext->p_sys->wait );
260 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
261 return VLC_SUCCESS;
264 /* Thread loop */
265 static void* Run( void *data )
267 extension_t *p_ext = data;
268 extensions_manager_t *p_mgr = p_ext->p_sys->p_mgr;
270 vlc_mutex_lock( &p_ext->p_sys->command_lock );
272 while( !p_ext->p_sys->b_exiting )
274 struct command_t *cmd = p_ext->p_sys->command;
276 /* Pop command in front */
277 if( cmd == NULL )
279 vlc_cond_wait( &p_ext->p_sys->wait, &p_ext->p_sys->command_lock );
280 continue;
282 p_ext->p_sys->command = cmd->next;
283 cmd->next = NULL; /* unlink command (for FreeCommands()) */
284 // Create watch timer
285 vlc_timer_schedule( p_ext->p_sys->timer, false, WATCH_TIMER_PERIOD, 0 );
286 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
288 /* Run command */
289 vlc_mutex_lock( &p_ext->p_sys->running_lock );
290 switch( cmd->i_command )
292 case CMD_ACTIVATE:
294 if( lua_ExecuteFunction( p_mgr, p_ext, "activate", LUA_END ) < 0 )
296 msg_Err( p_mgr, "Could not activate extension!" );
297 vlc_mutex_lock( &p_ext->p_sys->command_lock );
298 QueueDeactivateCommand( p_ext );
299 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
300 break;
302 vlc_mutex_lock( &p_ext->p_sys->command_lock );
303 p_ext->p_sys->b_activated = true;
304 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
305 break;
308 case CMD_DEACTIVATE:
310 msg_Dbg( p_mgr, "Deactivating '%s'", p_ext->psz_title );
311 if( lua_ExtensionDeactivate( p_mgr, p_ext ) < 0 )
313 msg_Warn( p_mgr, "Extension '%s' did not deactivate properly",
314 p_ext->psz_title );
316 vlc_mutex_lock( &p_ext->p_sys->command_lock );
317 p_ext->p_sys->b_activated = false;
318 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
319 break;
322 case CMD_CLOSE:
324 lua_ExecuteFunction( p_mgr, p_ext, "close", LUA_END );
325 break;
328 case CMD_CLICK:
330 extension_widget_t *p_widget = cmd->data[0];
331 assert( p_widget );
332 msg_Dbg( p_mgr, "Clicking '%s': '%s'",
333 p_ext->psz_name, p_widget->psz_text );
334 if( lua_ExtensionWidgetClick( p_mgr, p_ext, p_widget ) < 0 )
336 msg_Warn( p_mgr, "Could not translate click" );
338 break;
341 case CMD_TRIGGERMENU:
343 int *pi_id = cmd->data[0];
344 assert( pi_id );
345 msg_Dbg( p_mgr, "Trigger menu %d of '%s'",
346 *pi_id, p_ext->psz_name );
347 lua_ExtensionTriggerMenu( p_mgr, p_ext, *pi_id );
348 break;
351 case CMD_SET_INPUT:
353 lua_ExecuteFunction( p_mgr, p_ext, "input_changed", LUA_END );
354 break;
357 case CMD_UPDATE_META:
359 lua_ExecuteFunction( p_mgr, p_ext, "meta_changed", LUA_END );
360 break;
363 case CMD_PLAYING_CHANGED:
365 lua_ExecuteFunction( p_mgr, p_ext, "playing_changed",
366 LUA_NUM, *((int *)cmd->data[0]), LUA_END );
367 break;
370 default:
372 msg_Dbg( p_mgr, "Unknown command in extension command queue: %d",
373 cmd->i_command );
374 break;
377 vlc_mutex_unlock( &p_ext->p_sys->running_lock );
379 FreeCommands( cmd );
381 vlc_mutex_lock( &p_ext->p_sys->command_lock );
382 // Reset watch timer and timestamp
383 if( p_ext->p_sys->p_progress_id != NULL )
385 vlc_dialog_release( p_mgr, p_ext->p_sys->p_progress_id );
386 p_ext->p_sys->p_progress_id = NULL;
388 vlc_timer_schedule( p_ext->p_sys->timer, false, 0, 0 );
391 vlc_mutex_unlock( &p_ext->p_sys->command_lock );
392 msg_Dbg( p_mgr, "Extension thread end: '%s'", p_ext->psz_title );
394 // Note: At this point, the extension should be deactivated
395 return NULL;