Line | Count | Source (jump to first uncovered line) |
1 | | /***************************************************************************** |
2 | | * vlm.c: VLM interface plugin |
3 | | ***************************************************************************** |
4 | | * Copyright (C) 2000-2005 VLC authors and VideoLAN |
5 | | * |
6 | | * Authors: Simon Latapie <garf@videolan.org> |
7 | | * Laurent Aimar <fenrir@videolan.org> |
8 | | * Gildas Bazin <gbazin@videolan.org> |
9 | | * |
10 | | * This program is free software; you can redistribute it and/or modify it |
11 | | * under the terms of the GNU Lesser General Public License as published by |
12 | | * the Free Software Foundation; either version 2.1 of the License, or |
13 | | * (at your option) any later version. |
14 | | * |
15 | | * This program is distributed in the hope that it will be useful, |
16 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | | * GNU Lesser General Public License for more details. |
19 | | * |
20 | | * You should have received a copy of the GNU Lesser General Public License |
21 | | * along with this program; if not, write to the Free Software Foundation, |
22 | | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
23 | | *****************************************************************************/ |
24 | | |
25 | | /***************************************************************************** |
26 | | * Preamble |
27 | | *****************************************************************************/ |
28 | | #ifdef HAVE_CONFIG_H |
29 | | # include "config.h" |
30 | | #endif |
31 | | |
32 | | #include <vlc_common.h> |
33 | | #include <vlc_arrays.h> |
34 | | |
35 | | #include <stdio.h> |
36 | | #include <ctype.h> /* tolower() */ |
37 | | #include <time.h> /* ctime() */ |
38 | | #include <limits.h> |
39 | | #include <assert.h> |
40 | | |
41 | | #include <vlc_vlm.h> |
42 | | #include <vlc_modules.h> |
43 | | |
44 | | #include <vlc_player.h> |
45 | | #include <vlc_stream.h> |
46 | | #include "vlm_internal.h" |
47 | | #include "vlm_event.h" |
48 | | #include <vlc_sout.h> |
49 | | #include <vlc_url.h> |
50 | | #include "../misc/threads.h" |
51 | | #include "../libvlc.h" |
52 | | |
53 | | /***************************************************************************** |
54 | | * Local prototypes. |
55 | | *****************************************************************************/ |
56 | | |
57 | | static void* Manage( void * ); |
58 | | |
59 | | static void player_on_state_changed(vlc_player_t *player, |
60 | | enum vlc_player_state new_state, void *data) |
61 | 0 | { |
62 | 0 | vlm_media_sys_t *p_media = data; |
63 | 0 | vlm_t *p_vlm = p_media->vlm; |
64 | 0 | assert( p_vlm ); |
65 | 0 | vlm_media_instance_sys_t *instance = NULL; |
66 | 0 | const char *psz_instance_name = NULL; |
67 | |
|
68 | 0 | for( int i = 0; i < p_media->i_instance; i++ ) |
69 | 0 | { |
70 | 0 | if( p_media->instance[i]->player == player ) |
71 | 0 | { |
72 | 0 | instance = p_media->instance[i]; |
73 | 0 | psz_instance_name = instance->psz_name; |
74 | 0 | break; |
75 | 0 | } |
76 | 0 | } |
77 | 0 | enum vlm_state_e vlm_state; |
78 | 0 | switch (new_state) |
79 | 0 | { |
80 | 0 | case VLC_PLAYER_STATE_STOPPED: |
81 | 0 | vlm_state = vlc_player_GetError(player) ? VLM_ERROR_S : VLM_INIT_S; |
82 | 0 | break; |
83 | 0 | case VLC_PLAYER_STATE_STARTED: |
84 | 0 | vlm_state = VLM_OPENING_S; |
85 | 0 | break; |
86 | 0 | case VLC_PLAYER_STATE_PLAYING: |
87 | 0 | vlm_state = VLM_PLAYING_S; |
88 | 0 | break; |
89 | 0 | case VLC_PLAYER_STATE_PAUSED: |
90 | 0 | vlm_state = VLM_PAUSE_S; |
91 | 0 | break; |
92 | 0 | case VLC_PLAYER_STATE_STOPPING: |
93 | 0 | vlm_state = vlc_player_GetError(player) ? VLM_ERROR_S : VLM_END_S; |
94 | 0 | if (instance != NULL) |
95 | 0 | { |
96 | 0 | vlc_mutex_lock(&p_vlm->lock); |
97 | 0 | instance->finished = true; |
98 | 0 | vlc_mutex_unlock(&p_vlm->lock); |
99 | 0 | } |
100 | |
|
101 | 0 | break; |
102 | 0 | default: |
103 | 0 | vlc_assert_unreachable(); |
104 | 0 | } |
105 | 0 | vlm_SendEventMediaInstanceState( p_vlm, p_media->cfg.id, p_media->cfg.psz_name, psz_instance_name, vlm_state ); |
106 | |
|
107 | 0 | vlc_mutex_lock( &p_vlm->lock_manage ); |
108 | 0 | p_vlm->input_state_changed = true; |
109 | 0 | vlc_cond_signal( &p_vlm->wait_manage ); |
110 | 0 | vlc_mutex_unlock( &p_vlm->lock_manage ); |
111 | 0 | } |
112 | | |
113 | | static vlc_mutex_t vlm_mutex = VLC_STATIC_MUTEX; |
114 | | |
115 | | /***************************************************************************** |
116 | | * vlm_New: |
117 | | *****************************************************************************/ |
118 | | vlm_t *vlm_New( libvlc_int_t *libvlc, const char *psz_vlmconf ) |
119 | 0 | { |
120 | 0 | vlm_t *p_vlm = NULL, **pp_vlm = &(libvlc_priv(libvlc)->p_vlm); |
121 | 0 | vlc_object_t *p_this = VLC_OBJECT(libvlc); |
122 | | |
123 | | /* Avoid multiple creation */ |
124 | 0 | vlc_mutex_lock( &vlm_mutex ); |
125 | |
|
126 | 0 | p_vlm = *pp_vlm; |
127 | 0 | if( p_vlm ) |
128 | 0 | { /* VLM already exists */ |
129 | 0 | if( likely( p_vlm->users < UINT_MAX ) ) |
130 | 0 | p_vlm->users++; |
131 | 0 | else |
132 | 0 | p_vlm = NULL; |
133 | 0 | vlc_mutex_unlock( &vlm_mutex ); |
134 | 0 | return p_vlm; |
135 | 0 | } |
136 | | |
137 | 0 | msg_Dbg( p_this, "creating VLM" ); |
138 | |
|
139 | 0 | p_vlm = vlc_custom_create( p_this, sizeof( *p_vlm ), "vlm daemon" ); |
140 | 0 | if( !p_vlm ) |
141 | 0 | { |
142 | 0 | vlc_mutex_unlock( &vlm_mutex ); |
143 | 0 | return NULL; |
144 | 0 | } |
145 | | |
146 | 0 | vlc_mutex_init( &p_vlm->lock ); |
147 | 0 | vlc_mutex_init( &p_vlm->lock_manage ); |
148 | 0 | vlc_cond_init( &p_vlm->wait_manage ); |
149 | 0 | p_vlm->users = 1; |
150 | 0 | p_vlm->input_state_changed = false; |
151 | 0 | p_vlm->exiting = false; |
152 | 0 | p_vlm->i_id = 1; |
153 | 0 | TAB_INIT( p_vlm->i_media, p_vlm->media ); |
154 | 0 | TAB_INIT( p_vlm->i_schedule, p_vlm->schedule ); |
155 | 0 | var_Create( p_vlm, "intf-event", VLC_VAR_ADDRESS ); |
156 | |
|
157 | 0 | if( vlc_clone( &p_vlm->thread, Manage, p_vlm ) ) |
158 | 0 | { |
159 | 0 | vlc_object_delete(p_vlm); |
160 | 0 | vlc_mutex_unlock( &vlm_mutex ); |
161 | 0 | return NULL; |
162 | 0 | } |
163 | | |
164 | 0 | *pp_vlm = p_vlm; /* for future reference */ |
165 | |
|
166 | 0 | vlc_mutex_unlock( &vlm_mutex ); |
167 | | |
168 | | /* Load our configuration file */ |
169 | 0 | if( psz_vlmconf != NULL ) |
170 | 0 | { |
171 | 0 | vlm_message_t *p_message = NULL; |
172 | 0 | char *psz_buffer = NULL; |
173 | |
|
174 | 0 | msg_Dbg( p_this, "loading VLM configuration" ); |
175 | 0 | if( asprintf(&psz_buffer, "load %s", psz_vlmconf ) != -1 ) |
176 | 0 | { |
177 | 0 | msg_Dbg( p_this, "%s", psz_buffer ); |
178 | 0 | if( vlm_ExecuteCommand( p_vlm, psz_buffer, &p_message ) ) |
179 | 0 | msg_Warn( p_this, "error while loading the configuration file" ); |
180 | |
|
181 | 0 | vlm_MessageDelete( p_message ); |
182 | 0 | free( psz_buffer ); |
183 | 0 | } |
184 | 0 | } |
185 | |
|
186 | 0 | return p_vlm; |
187 | 0 | } |
188 | | |
189 | | /***************************************************************************** |
190 | | * vlm_Delete: |
191 | | *****************************************************************************/ |
192 | | void vlm_Delete( vlm_t *p_vlm ) |
193 | 0 | { |
194 | | /* vlm_Delete() is serialized against itself, and against vlm_New(). |
195 | | * This mutex protects libvlc_priv->p_vlm and p_vlm->users. */ |
196 | 0 | vlc_mutex_lock( &vlm_mutex ); |
197 | 0 | assert( p_vlm->users > 0 ); |
198 | 0 | if( --p_vlm->users == 0 ) |
199 | 0 | assert( libvlc_priv(vlc_object_instance(p_vlm))->p_vlm == p_vlm ); |
200 | 0 | else |
201 | 0 | p_vlm = NULL; |
202 | | |
203 | 0 | if( p_vlm == NULL ) |
204 | 0 | { |
205 | 0 | vlc_mutex_unlock( &vlm_mutex ); |
206 | 0 | return; |
207 | 0 | } |
208 | | |
209 | | /* Destroy and release VLM */ |
210 | 0 | vlc_mutex_lock( &p_vlm->lock ); |
211 | 0 | vlm_ControlInternal( p_vlm, VLM_CLEAR_MEDIAS ); |
212 | 0 | TAB_CLEAN( p_vlm->i_media, p_vlm->media ); |
213 | |
|
214 | 0 | vlm_ControlInternal( p_vlm, VLM_CLEAR_SCHEDULES ); |
215 | 0 | TAB_CLEAN( p_vlm->i_schedule, p_vlm->schedule ); |
216 | 0 | vlc_mutex_unlock( &p_vlm->lock ); |
217 | |
|
218 | 0 | vlc_mutex_lock( &p_vlm->lock_manage ); |
219 | 0 | p_vlm->exiting = true; |
220 | 0 | vlc_cond_signal( &p_vlm->wait_manage ); |
221 | 0 | vlc_mutex_unlock( &p_vlm->lock_manage ); |
222 | |
|
223 | 0 | libvlc_priv(vlc_object_instance(p_vlm))->p_vlm = NULL; |
224 | 0 | vlc_mutex_unlock( &vlm_mutex ); |
225 | |
|
226 | 0 | vlc_join( p_vlm->thread, NULL ); |
227 | 0 | vlc_object_delete(p_vlm); |
228 | 0 | } |
229 | | |
230 | | /***************************************************************************** |
231 | | * vlm_ExecuteCommand: |
232 | | *****************************************************************************/ |
233 | | int vlm_ExecuteCommand( vlm_t *p_vlm, const char *psz_command, |
234 | | vlm_message_t **pp_message) |
235 | 0 | { |
236 | 0 | int i_result; |
237 | |
|
238 | 0 | vlc_mutex_lock( &p_vlm->lock ); |
239 | 0 | i_result = ExecuteCommand( p_vlm, psz_command, pp_message ); |
240 | 0 | vlc_mutex_unlock( &p_vlm->lock ); |
241 | |
|
242 | 0 | return i_result; |
243 | 0 | } |
244 | | |
245 | | /***************************************************************************** |
246 | | * Manage: |
247 | | *****************************************************************************/ |
248 | | static void* Manage( void* p_object ) |
249 | 0 | { |
250 | 0 | vlc_thread_set_name("vlc-vlm"); |
251 | |
|
252 | 0 | vlm_t *vlm = (vlm_t*)p_object; |
253 | 0 | time_t lastcheck; |
254 | 0 | bool exiting; |
255 | |
|
256 | 0 | time(&lastcheck); |
257 | |
|
258 | 0 | do |
259 | 0 | { |
260 | 0 | char **ppsz_scheduled_commands = NULL; |
261 | 0 | int i_scheduled_commands = 0; |
262 | | |
263 | | /* destroy the inputs that wants to die, and launch the next input */ |
264 | 0 | vlc_mutex_lock( &vlm->lock ); |
265 | 0 | for( int i = 0; i < vlm->i_media; i++ ) |
266 | 0 | { |
267 | 0 | vlm_media_sys_t *p_media = vlm->media[i]; |
268 | |
|
269 | 0 | for( int j = 0; j < p_media->i_instance; ) |
270 | 0 | { |
271 | 0 | vlm_media_instance_sys_t *p_instance = p_media->instance[j]; |
272 | |
|
273 | 0 | if (p_instance->finished) |
274 | 0 | { |
275 | 0 | int i_new_input_index; |
276 | | |
277 | | /* */ |
278 | 0 | i_new_input_index = p_instance->i_index + 1; |
279 | 0 | if( p_media->cfg.broadcast.b_loop && i_new_input_index >= p_media->cfg.i_input ) |
280 | 0 | i_new_input_index = 0; |
281 | |
|
282 | 0 | if( i_new_input_index >= p_media->cfg.i_input ) |
283 | 0 | vlm_ControlInternal( vlm, VLM_STOP_MEDIA_INSTANCE, p_media->cfg.id, p_instance->psz_name ); |
284 | 0 | else |
285 | 0 | vlm_ControlInternal( vlm, VLM_START_MEDIA_BROADCAST_INSTANCE, p_media->cfg.id, p_instance->psz_name, i_new_input_index ); |
286 | |
|
287 | 0 | j = 0; |
288 | 0 | } |
289 | 0 | else |
290 | 0 | { |
291 | 0 | j++; |
292 | 0 | } |
293 | 0 | } |
294 | 0 | } |
295 | | |
296 | | /* scheduling */ |
297 | 0 | time_t now, nextschedule = 0; |
298 | |
|
299 | 0 | time(&now); |
300 | |
|
301 | 0 | for( int i = 0; i < vlm->i_schedule; i++ ) |
302 | 0 | { |
303 | 0 | time_t real_date = vlm->schedule[i]->date; |
304 | |
|
305 | 0 | if( vlm->schedule[i]->b_enabled ) |
306 | 0 | { |
307 | 0 | bool b_now = false; |
308 | 0 | if( vlm->schedule[i]->date == 0 ) // now ! |
309 | 0 | { |
310 | 0 | vlm->schedule[i]->date = now; |
311 | 0 | real_date = now; |
312 | 0 | b_now = true; |
313 | 0 | } |
314 | 0 | else if( vlm->schedule[i]->period != 0 ) |
315 | 0 | { |
316 | 0 | int j = 0; |
317 | 0 | while( ((vlm->schedule[i]->date + j * |
318 | 0 | vlm->schedule[i]->period) <= lastcheck) && |
319 | 0 | ( vlm->schedule[i]->i_repeat > j || |
320 | 0 | vlm->schedule[i]->i_repeat < 0 ) ) |
321 | 0 | { |
322 | 0 | j++; |
323 | 0 | } |
324 | |
|
325 | 0 | real_date = vlm->schedule[i]->date + j * |
326 | 0 | vlm->schedule[i]->period; |
327 | 0 | } |
328 | |
|
329 | 0 | if( real_date <= now ) |
330 | 0 | { |
331 | 0 | if( real_date > lastcheck || b_now ) |
332 | 0 | { |
333 | 0 | for( int j = 0; j < vlm->schedule[i]->i_command; j++ ) |
334 | 0 | { |
335 | 0 | TAB_APPEND( i_scheduled_commands, |
336 | 0 | ppsz_scheduled_commands, |
337 | 0 | strdup(vlm->schedule[i]->command[j] ) ); |
338 | 0 | } |
339 | 0 | } |
340 | 0 | } |
341 | 0 | else if( nextschedule == 0 || real_date < nextschedule ) |
342 | 0 | { |
343 | 0 | nextschedule = real_date; |
344 | 0 | } |
345 | 0 | } |
346 | 0 | } |
347 | | |
348 | 0 | while( i_scheduled_commands ) |
349 | 0 | { |
350 | 0 | vlm_message_t *message = NULL; |
351 | 0 | char *psz_command = ppsz_scheduled_commands[0]; |
352 | 0 | ExecuteCommand( vlm, psz_command,&message ); |
353 | | |
354 | | /* for now, drop the message */ |
355 | 0 | vlm_MessageDelete( message ); |
356 | 0 | TAB_REMOVE( i_scheduled_commands, |
357 | 0 | ppsz_scheduled_commands, |
358 | 0 | psz_command ); |
359 | 0 | free( psz_command ); |
360 | 0 | } |
361 | |
|
362 | 0 | lastcheck = now; |
363 | 0 | vlc_mutex_unlock( &vlm->lock ); |
364 | |
|
365 | 0 | vlc_mutex_lock( &vlm->lock_manage ); |
366 | |
|
367 | 0 | while( !vlm->input_state_changed && !(exiting = vlm->exiting) ) |
368 | 0 | { |
369 | 0 | if( nextschedule ) |
370 | 0 | { |
371 | 0 | if( vlc_cond_timedwait_daytime( &vlm->wait_manage, |
372 | 0 | &vlm->lock_manage, |
373 | 0 | nextschedule ) ) |
374 | 0 | break; |
375 | 0 | } |
376 | 0 | else |
377 | 0 | vlc_cond_wait( &vlm->wait_manage, &vlm->lock_manage ); |
378 | 0 | } |
379 | 0 | vlm->input_state_changed = false; |
380 | 0 | vlc_mutex_unlock( &vlm->lock_manage ); |
381 | 0 | } |
382 | 0 | while( !exiting ); |
383 | | |
384 | 0 | return NULL; |
385 | 0 | } |
386 | | |
387 | | /* New API |
388 | | */ |
389 | | /* |
390 | | typedef struct |
391 | | { |
392 | | struct |
393 | | { |
394 | | int i_count; |
395 | | bool b_playing; |
396 | | int i_playing_index; |
397 | | } broadcast; |
398 | | |
399 | | } vlm_media_status_t; |
400 | | */ |
401 | | |
402 | | /* */ |
403 | | static vlm_media_sys_t *vlm_ControlMediaGetById( vlm_t *p_vlm, int64_t id ) |
404 | 0 | { |
405 | 0 | for( int i = 0; i < p_vlm->i_media; i++ ) |
406 | 0 | { |
407 | 0 | if( p_vlm->media[i]->cfg.id == id ) |
408 | 0 | return p_vlm->media[i]; |
409 | 0 | } |
410 | 0 | return NULL; |
411 | 0 | } |
412 | | static vlm_media_sys_t *vlm_ControlMediaGetByName( vlm_t *p_vlm, const char *psz_name ) |
413 | 0 | { |
414 | 0 | for( int i = 0; i < p_vlm->i_media; i++ ) |
415 | 0 | { |
416 | 0 | if( !strcmp( p_vlm->media[i]->cfg.psz_name, psz_name ) ) |
417 | 0 | return p_vlm->media[i]; |
418 | 0 | } |
419 | 0 | return NULL; |
420 | 0 | } |
421 | | static int vlm_MediaDescriptionCheck( vlm_t *p_vlm, vlm_media_t *p_cfg ) |
422 | 0 | { |
423 | 0 | if( !p_cfg || !p_cfg->psz_name || |
424 | 0 | !strcmp( p_cfg->psz_name, "all" ) || !strcmp( p_cfg->psz_name, "media" ) || !strcmp( p_cfg->psz_name, "schedule" ) ) |
425 | 0 | return VLC_EGENERIC; |
426 | | |
427 | 0 | for( int i = 0; i < p_vlm->i_media; i++ ) |
428 | 0 | { |
429 | 0 | if( p_vlm->media[i]->cfg.id == p_cfg->id ) |
430 | 0 | continue; |
431 | 0 | if( !strcmp( p_vlm->media[i]->cfg.psz_name, p_cfg->psz_name ) ) |
432 | 0 | return VLC_EGENERIC; |
433 | 0 | } |
434 | 0 | return VLC_SUCCESS; |
435 | 0 | } |
436 | | |
437 | | |
438 | | /* Called after a media description is changed/added */ |
439 | | static int vlm_OnMediaUpdate( vlm_t *p_vlm, vlm_media_sys_t *p_media ) |
440 | 0 | { |
441 | 0 | vlm_media_t *p_cfg = &p_media->cfg; |
442 | | |
443 | | /* TODO start media if needed */ |
444 | | |
445 | | /* TODO add support of var vlm_media_broadcast */ |
446 | |
|
447 | 0 | vlm_SendEventMediaChanged( p_vlm, p_cfg->id, p_cfg->psz_name ); |
448 | 0 | return VLC_SUCCESS; |
449 | 0 | } |
450 | | static int vlm_ControlMediaChange( vlm_t *p_vlm, vlm_media_t *p_cfg ) |
451 | 0 | { |
452 | 0 | vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, p_cfg->id ); |
453 | | |
454 | | /* */ |
455 | 0 | if( !p_media || vlm_MediaDescriptionCheck( p_vlm, p_cfg ) ) |
456 | 0 | return VLC_EGENERIC; |
457 | | |
458 | 0 | if( 0 ) |
459 | 0 | { |
460 | | /* TODO check what are the changes being done (stop instance if needed) */ |
461 | 0 | } |
462 | |
|
463 | 0 | vlm_media_Clean( &p_media->cfg ); |
464 | 0 | vlm_media_Copy( &p_media->cfg, p_cfg ); |
465 | |
|
466 | 0 | return vlm_OnMediaUpdate( p_vlm, p_media ); |
467 | 0 | } |
468 | | |
469 | | static int vlm_ControlMediaAdd( vlm_t *p_vlm, vlm_media_t *p_cfg, int64_t *p_id ) |
470 | 0 | { |
471 | 0 | vlm_media_sys_t *p_media; |
472 | |
|
473 | 0 | if( vlm_MediaDescriptionCheck( p_vlm, p_cfg ) || vlm_ControlMediaGetByName( p_vlm, p_cfg->psz_name ) ) |
474 | 0 | { |
475 | 0 | msg_Err( p_vlm, "invalid media description" ); |
476 | 0 | return VLC_EGENERIC; |
477 | 0 | } |
478 | | |
479 | 0 | p_media = malloc(sizeof(*p_media)); |
480 | 0 | if( !p_media ) |
481 | 0 | return VLC_ENOMEM; |
482 | | |
483 | 0 | p_media->vlm = p_vlm; |
484 | |
|
485 | 0 | vlm_media_Copy( &p_media->cfg, p_cfg ); |
486 | 0 | p_media->cfg.id = p_vlm->i_id++; |
487 | | /* FIXME do we do something here if enabled is true ? */ |
488 | |
|
489 | 0 | TAB_INIT( p_media->i_instance, p_media->instance ); |
490 | | |
491 | | /* */ |
492 | 0 | TAB_APPEND( p_vlm->i_media, p_vlm->media, p_media ); |
493 | | |
494 | 0 | if( p_id ) |
495 | 0 | *p_id = p_media->cfg.id; |
496 | | |
497 | | /* */ |
498 | 0 | vlm_SendEventMediaAdded( p_vlm, p_media->cfg.id, p_media->cfg.psz_name ); |
499 | 0 | return vlm_OnMediaUpdate( p_vlm, p_media ); |
500 | 0 | } |
501 | | |
502 | | static int vlm_ControlMediaDel( vlm_t *p_vlm, int64_t id ) |
503 | 0 | { |
504 | 0 | vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id ); |
505 | |
|
506 | 0 | if( !p_media ) |
507 | 0 | return VLC_EGENERIC; |
508 | | |
509 | 0 | while( p_media->i_instance > 0 ) |
510 | 0 | vlm_ControlInternal( p_vlm, VLM_STOP_MEDIA_INSTANCE, id, p_media->instance[0]->psz_name ); |
511 | | |
512 | | /* */ |
513 | 0 | vlm_SendEventMediaRemoved( p_vlm, id, p_media->cfg.psz_name ); |
514 | |
|
515 | 0 | vlm_media_Clean( &p_media->cfg ); |
516 | |
|
517 | 0 | TAB_REMOVE( p_vlm->i_media, p_vlm->media, p_media ); |
518 | 0 | free(p_media); |
519 | |
|
520 | 0 | return VLC_SUCCESS; |
521 | 0 | } |
522 | | |
523 | | static int vlm_ControlMediaGets( vlm_t *p_vlm, vlm_media_t ***ppp_dsc, int *pi_dsc ) |
524 | 0 | { |
525 | 0 | vlm_media_t **pp_dsc; |
526 | 0 | int i_dsc; |
527 | |
|
528 | 0 | TAB_INIT( i_dsc, pp_dsc ); |
529 | 0 | for( int i = 0; i < p_vlm->i_media; i++ ) |
530 | 0 | { |
531 | 0 | vlm_media_t *p_dsc = vlm_media_Duplicate( &p_vlm->media[i]->cfg ); |
532 | 0 | TAB_APPEND( i_dsc, pp_dsc, p_dsc ); |
533 | 0 | } |
534 | | |
535 | 0 | *ppp_dsc = pp_dsc; |
536 | 0 | *pi_dsc = i_dsc; |
537 | |
|
538 | 0 | return VLC_SUCCESS; |
539 | 0 | } |
540 | | static int vlm_ControlMediaClear( vlm_t *p_vlm ) |
541 | 0 | { |
542 | 0 | while( p_vlm->i_media > 0 ) |
543 | 0 | vlm_ControlMediaDel( p_vlm, p_vlm->media[0]->cfg.id ); |
544 | |
|
545 | 0 | return VLC_SUCCESS; |
546 | 0 | } |
547 | | static int vlm_ControlMediaGet( vlm_t *p_vlm, int64_t id, vlm_media_t **pp_dsc ) |
548 | 0 | { |
549 | 0 | vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id ); |
550 | 0 | if( !p_media ) |
551 | 0 | return VLC_EGENERIC; |
552 | | |
553 | 0 | *pp_dsc = vlm_media_Duplicate( &p_media->cfg ); |
554 | 0 | return VLC_SUCCESS; |
555 | 0 | } |
556 | | static int vlm_ControlMediaGetId( vlm_t *p_vlm, const char *psz_name, int64_t *p_id ) |
557 | 0 | { |
558 | 0 | vlm_media_sys_t *p_media = vlm_ControlMediaGetByName( p_vlm, psz_name ); |
559 | 0 | if( !p_media ) |
560 | 0 | return VLC_EGENERIC; |
561 | | |
562 | 0 | *p_id = p_media->cfg.id; |
563 | 0 | return VLC_SUCCESS; |
564 | 0 | } |
565 | | |
566 | | static vlm_media_instance_sys_t *vlm_ControlMediaInstanceGetByName( vlm_media_sys_t *p_media, const char *psz_id ) |
567 | 0 | { |
568 | 0 | for( int i = 0; i < p_media->i_instance; i++ ) |
569 | 0 | { |
570 | 0 | const char *psz = p_media->instance[i]->psz_name; |
571 | 0 | if( ( psz == NULL && psz_id == NULL ) || |
572 | 0 | ( psz && psz_id && !strcmp( psz, psz_id ) ) ) |
573 | 0 | return p_media->instance[i]; |
574 | 0 | } |
575 | 0 | return NULL; |
576 | 0 | } |
577 | | |
578 | | static vlm_media_instance_sys_t *vlm_MediaInstanceNew( vlm_media_sys_t *p_media, const char *psz_name ) |
579 | 0 | { |
580 | 0 | vlm_media_instance_sys_t *p_instance = calloc( 1, sizeof(vlm_media_instance_sys_t) ); |
581 | 0 | if( !p_instance ) |
582 | 0 | return NULL; |
583 | | |
584 | 0 | p_instance->psz_name = NULL; |
585 | 0 | if( psz_name ) |
586 | 0 | p_instance->psz_name = strdup( psz_name ); |
587 | |
|
588 | 0 | p_instance->p_item = input_item_New( NULL, NULL ); |
589 | 0 | if (!p_instance->p_item) |
590 | 0 | goto error; |
591 | | |
592 | 0 | p_instance->i_index = 0; |
593 | |
|
594 | 0 | p_instance->player = vlc_player_New(VLC_OBJECT(p_media->vlm), |
595 | 0 | VLC_PLAYER_LOCK_NORMAL); |
596 | 0 | if (!p_instance->player) |
597 | 0 | goto error; |
598 | | |
599 | 0 | static struct vlc_player_cbs cbs = { |
600 | 0 | .on_state_changed = player_on_state_changed, |
601 | 0 | }; |
602 | 0 | vlc_player_Lock(p_instance->player); |
603 | 0 | p_instance->listener = |
604 | 0 | vlc_player_AddListener(p_instance->player, &cbs, p_media); |
605 | 0 | vlc_player_Unlock(p_instance->player); |
606 | |
|
607 | 0 | if (!p_instance->listener) |
608 | 0 | goto error; |
609 | 0 | return p_instance; |
610 | | |
611 | 0 | error: |
612 | 0 | if (p_instance->player) |
613 | 0 | vlc_player_Delete(p_instance->player); |
614 | 0 | if (p_instance->p_item) |
615 | 0 | input_item_Release(p_instance->p_item); |
616 | 0 | free(p_instance->psz_name); |
617 | 0 | free(p_instance); |
618 | 0 | return NULL; |
619 | 0 | } |
620 | | static void vlm_MediaInstanceDelete( vlm_t *p_vlm, int64_t id, vlm_media_instance_sys_t *p_instance, vlm_media_sys_t *p_media ) |
621 | 0 | { |
622 | 0 | vlc_player_t *player = p_instance->player; |
623 | |
|
624 | 0 | vlc_player_Lock(player); |
625 | 0 | vlc_player_RemoveListener(player, p_instance->listener); |
626 | 0 | vlc_player_Stop(player); |
627 | 0 | bool had_media = vlc_player_GetCurrentMedia(player); |
628 | 0 | vlc_player_Unlock(player); |
629 | 0 | vlc_player_Delete(player); |
630 | |
|
631 | 0 | if (had_media) |
632 | 0 | vlm_SendEventMediaInstanceStopped( p_vlm, id, p_media->cfg.psz_name ); |
633 | |
|
634 | 0 | TAB_REMOVE( p_media->i_instance, p_media->instance, p_instance ); |
635 | 0 | input_item_Release( p_instance->p_item ); |
636 | 0 | free( p_instance->psz_name ); |
637 | 0 | free( p_instance ); |
638 | 0 | } |
639 | | |
640 | | |
641 | | static int vlm_ControlMediaInstanceStart( vlm_t *p_vlm, int64_t id, const char *psz_id, int i_input_index ) |
642 | 0 | { |
643 | 0 | vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id ); |
644 | 0 | vlm_media_instance_sys_t *p_instance; |
645 | |
|
646 | 0 | if( !p_media || !p_media->cfg.b_enabled || p_media->cfg.i_input <= 0 ) |
647 | 0 | return VLC_EGENERIC; |
648 | | |
649 | 0 | if( i_input_index < 0 || i_input_index >= p_media->cfg.i_input ) |
650 | 0 | return VLC_EGENERIC; |
651 | | |
652 | 0 | p_instance = vlm_ControlMediaInstanceGetByName( p_media, psz_id ); |
653 | 0 | if( !p_instance ) |
654 | 0 | { |
655 | 0 | vlm_media_t *p_cfg = &p_media->cfg; |
656 | |
|
657 | 0 | p_instance = vlm_MediaInstanceNew( p_media, psz_id ); |
658 | 0 | if( !p_instance ) |
659 | 0 | return VLC_ENOMEM; |
660 | | |
661 | 0 | if( p_cfg->psz_output != NULL ) |
662 | 0 | { |
663 | 0 | char *psz_buffer; |
664 | 0 | if( asprintf( &psz_buffer, "sout=%s", p_cfg->psz_output ) != -1 ) |
665 | 0 | { |
666 | 0 | input_item_AddOption( p_instance->p_item, psz_buffer, VLC_INPUT_OPTION_TRUSTED ); |
667 | 0 | free( psz_buffer ); |
668 | 0 | } |
669 | 0 | } |
670 | |
|
671 | 0 | for( int i = 0; i < p_cfg->i_option; i++ ) |
672 | 0 | input_item_AddOption( p_instance->p_item, p_cfg->ppsz_option[i], VLC_INPUT_OPTION_TRUSTED ); |
673 | 0 | TAB_APPEND( p_media->i_instance, p_media->instance, p_instance ); |
674 | 0 | } |
675 | | |
676 | | /* Stop old instance */ |
677 | 0 | vlc_player_t *player = p_instance->player; |
678 | 0 | vlc_player_Lock(player); |
679 | 0 | if (vlc_player_GetCurrentMedia(player)) |
680 | 0 | { |
681 | 0 | if( p_instance->i_index == i_input_index ) |
682 | 0 | { |
683 | 0 | if (vlc_player_IsPaused(player)) |
684 | 0 | vlc_player_Resume(player); |
685 | 0 | return VLC_SUCCESS; |
686 | 0 | } |
687 | | |
688 | 0 | vlc_player_Stop(player); |
689 | 0 | vlc_player_Unlock(player); |
690 | 0 | vlm_SendEventMediaInstanceStopped( p_vlm, id, p_media->cfg.psz_name ); |
691 | 0 | vlc_player_Lock(player); |
692 | 0 | } |
693 | | |
694 | | /* Start new one */ |
695 | 0 | p_instance->i_index = i_input_index; |
696 | 0 | if( strstr( p_media->cfg.ppsz_input[p_instance->i_index], "://" ) == NULL ) |
697 | 0 | { |
698 | 0 | char *psz_uri = vlc_path2uri( |
699 | 0 | p_media->cfg.ppsz_input[p_instance->i_index], NULL ); |
700 | 0 | input_item_SetURI( p_instance->p_item, psz_uri ) ; |
701 | 0 | free( psz_uri ); |
702 | 0 | } |
703 | 0 | else |
704 | 0 | input_item_SetURI( p_instance->p_item, p_media->cfg.ppsz_input[p_instance->i_index] ) ; |
705 | |
|
706 | 0 | vlc_player_SetCurrentMedia(player, p_instance->p_item); |
707 | 0 | vlc_player_Start(player); |
708 | 0 | vlc_player_Unlock(player); |
709 | 0 | p_instance->finished = false; |
710 | |
|
711 | 0 | vlm_SendEventMediaInstanceStarted( p_vlm, id, p_media->cfg.psz_name ); |
712 | |
|
713 | 0 | return VLC_SUCCESS; |
714 | 0 | } |
715 | | |
716 | | static int vlm_ControlMediaInstanceStop( vlm_t *p_vlm, int64_t id, const char *psz_id ) |
717 | 0 | { |
718 | 0 | vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id ); |
719 | 0 | vlm_media_instance_sys_t *p_instance; |
720 | |
|
721 | 0 | if( !p_media ) |
722 | 0 | return VLC_EGENERIC; |
723 | | |
724 | 0 | p_instance = vlm_ControlMediaInstanceGetByName( p_media, psz_id ); |
725 | 0 | if( !p_instance ) |
726 | 0 | return VLC_EGENERIC; |
727 | | |
728 | 0 | vlm_MediaInstanceDelete( p_vlm, id, p_instance, p_media ); |
729 | |
|
730 | 0 | return VLC_SUCCESS; |
731 | 0 | } |
732 | | static int vlm_ControlMediaInstancePause( vlm_t *p_vlm, int64_t id, const char *psz_id ) |
733 | 0 | { |
734 | 0 | vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id ); |
735 | 0 | vlm_media_instance_sys_t *p_instance; |
736 | 0 | if( !p_media ) |
737 | 0 | return VLC_EGENERIC; |
738 | | |
739 | 0 | p_instance = vlm_ControlMediaInstanceGetByName( p_media, psz_id ); |
740 | 0 | if( !p_instance ) |
741 | 0 | return VLC_EGENERIC; |
742 | | |
743 | 0 | vlc_player_Lock(p_instance->player); |
744 | 0 | vlc_player_TogglePause(p_instance->player); |
745 | 0 | vlc_player_Unlock(p_instance->player); |
746 | |
|
747 | 0 | return VLC_SUCCESS; |
748 | 0 | } |
749 | | static int vlm_ControlMediaInstanceGetTimePosition( vlm_t *p_vlm, int64_t id, const char *psz_id, int64_t *pi_time, double *pd_position ) |
750 | 0 | { |
751 | 0 | vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id ); |
752 | 0 | vlm_media_instance_sys_t *p_instance; |
753 | |
|
754 | 0 | if( !p_media ) |
755 | 0 | return VLC_EGENERIC; |
756 | | |
757 | 0 | p_instance = vlm_ControlMediaInstanceGetByName( p_media, psz_id ); |
758 | 0 | if( !p_instance ) |
759 | 0 | return VLC_EGENERIC; |
760 | | |
761 | 0 | vlc_player_Lock(p_instance->player); |
762 | 0 | if( pi_time ) |
763 | 0 | *pi_time = US_FROM_VLC_TICK(vlc_player_GetTime(p_instance->player)); |
764 | 0 | if( pd_position ) |
765 | 0 | *pd_position = vlc_player_GetPosition(p_instance->player); |
766 | 0 | vlc_player_Unlock(p_instance->player); |
767 | 0 | return VLC_SUCCESS; |
768 | 0 | } |
769 | | static int vlm_ControlMediaInstanceSetTimePosition( vlm_t *p_vlm, int64_t id, const char *psz_id, int64_t i_time, double d_position ) |
770 | 0 | { |
771 | 0 | vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id ); |
772 | 0 | vlm_media_instance_sys_t *p_instance; |
773 | |
|
774 | 0 | if( !p_media ) |
775 | 0 | return VLC_EGENERIC; |
776 | | |
777 | 0 | p_instance = vlm_ControlMediaInstanceGetByName( p_media, psz_id ); |
778 | 0 | if( !p_instance ) |
779 | 0 | return VLC_EGENERIC; |
780 | | |
781 | 0 | vlc_player_Lock(p_instance->player); |
782 | 0 | if( i_time >= 0 ) |
783 | 0 | vlc_player_SetTime(p_instance->player, VLC_TICK_FROM_US(i_time)); |
784 | 0 | else if( d_position >= 0 && d_position <= 100 ) |
785 | 0 | vlc_player_SetPosition(p_instance->player, d_position); |
786 | 0 | vlc_player_Unlock(p_instance->player); |
787 | 0 | return VLC_SUCCESS; |
788 | 0 | } |
789 | | |
790 | | static int vlm_ControlMediaInstanceGets( vlm_t *p_vlm, int64_t id, vlm_media_instance_t ***ppp_idsc, int *pi_instance ) |
791 | 0 | { |
792 | 0 | vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id ); |
793 | 0 | vlm_media_instance_t **pp_idsc; |
794 | 0 | int i_idsc; |
795 | |
|
796 | 0 | if( !p_media ) |
797 | 0 | return VLC_EGENERIC; |
798 | | |
799 | 0 | TAB_INIT( i_idsc, pp_idsc ); |
800 | 0 | for( int i = 0; i < p_media->i_instance; i++ ) |
801 | 0 | { |
802 | 0 | vlm_media_instance_sys_t *p_instance = p_media->instance[i]; |
803 | 0 | vlm_media_instance_t *p_idsc = vlm_media_instance_New(); |
804 | 0 | if( p_instance->psz_name ) |
805 | 0 | p_idsc->psz_name = strdup( p_instance->psz_name ); |
806 | 0 | vlc_player_Lock(p_instance->player); |
807 | 0 | p_idsc->i_time = US_FROM_VLC_TICK(vlc_player_GetTime(p_instance->player)); |
808 | 0 | p_idsc->i_length = US_FROM_VLC_TICK(vlc_player_GetLength(p_instance->player)); |
809 | 0 | p_idsc->d_position = vlc_player_GetPosition(p_instance->player); |
810 | 0 | p_idsc->b_paused = vlc_player_IsPaused(p_instance->player); |
811 | 0 | p_idsc->f_rate = vlc_player_GetRate(p_instance->player); |
812 | 0 | vlc_player_Unlock(p_instance->player); |
813 | |
|
814 | 0 | TAB_APPEND( i_idsc, pp_idsc, p_idsc ); |
815 | 0 | } |
816 | 0 | *ppp_idsc = pp_idsc; |
817 | 0 | *pi_instance = i_idsc; |
818 | 0 | return VLC_SUCCESS; |
819 | 0 | } |
820 | | |
821 | | static int vlm_ControlMediaInstanceClear( vlm_t *p_vlm, int64_t id ) |
822 | 0 | { |
823 | 0 | vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id ); |
824 | |
|
825 | 0 | if( !p_media ) |
826 | 0 | return VLC_EGENERIC; |
827 | | |
828 | 0 | while( p_media->i_instance > 0 ) |
829 | 0 | vlm_ControlMediaInstanceStop( p_vlm, id, p_media->instance[0]->psz_name ); |
830 | |
|
831 | 0 | return VLC_SUCCESS; |
832 | 0 | } |
833 | | |
834 | | static int vlm_ControlScheduleClear( vlm_t *p_vlm ) |
835 | 0 | { |
836 | 0 | while( p_vlm->i_schedule > 0 ) |
837 | 0 | vlm_ScheduleDelete( p_vlm, p_vlm->schedule[0] ); |
838 | |
|
839 | 0 | return VLC_SUCCESS; |
840 | 0 | } |
841 | | |
842 | | static int vlm_vaControlInternal( vlm_t *p_vlm, int i_query, va_list args ) |
843 | 0 | { |
844 | 0 | vlm_media_t *p_dsc; |
845 | 0 | vlm_media_t **pp_dsc; |
846 | 0 | vlm_media_t ***ppp_dsc; |
847 | 0 | vlm_media_instance_t ***ppp_idsc; |
848 | 0 | const char *psz_id; |
849 | 0 | int64_t *p_id; |
850 | 0 | int64_t id; |
851 | 0 | int i_int; |
852 | 0 | int *pi_int; |
853 | |
|
854 | 0 | int64_t *pi_i64; |
855 | 0 | int64_t i_i64; |
856 | 0 | double *pd_double; |
857 | 0 | double d_double; |
858 | |
|
859 | 0 | switch( i_query ) |
860 | 0 | { |
861 | | /* Media control */ |
862 | 0 | case VLM_GET_MEDIAS: |
863 | 0 | ppp_dsc = (vlm_media_t ***)va_arg( args, vlm_media_t *** ); |
864 | 0 | pi_int = (int *)va_arg( args, int * ); |
865 | 0 | return vlm_ControlMediaGets( p_vlm, ppp_dsc, pi_int ); |
866 | | |
867 | 0 | case VLM_CLEAR_MEDIAS: |
868 | 0 | return vlm_ControlMediaClear( p_vlm ); |
869 | | |
870 | 0 | case VLM_CHANGE_MEDIA: |
871 | 0 | p_dsc = (vlm_media_t*)va_arg( args, vlm_media_t * ); |
872 | 0 | return vlm_ControlMediaChange( p_vlm, p_dsc ); |
873 | | |
874 | 0 | case VLM_ADD_MEDIA: |
875 | 0 | p_dsc = (vlm_media_t*)va_arg( args, vlm_media_t * ); |
876 | 0 | p_id = (int64_t*)va_arg( args, int64_t * ); |
877 | 0 | return vlm_ControlMediaAdd( p_vlm, p_dsc, p_id ); |
878 | | |
879 | 0 | case VLM_DEL_MEDIA: |
880 | 0 | id = (int64_t)va_arg( args, int64_t ); |
881 | 0 | return vlm_ControlMediaDel( p_vlm, id ); |
882 | | |
883 | 0 | case VLM_GET_MEDIA: |
884 | 0 | id = (int64_t)va_arg( args, int64_t ); |
885 | 0 | pp_dsc = (vlm_media_t **)va_arg( args, vlm_media_t ** ); |
886 | 0 | return vlm_ControlMediaGet( p_vlm, id, pp_dsc ); |
887 | | |
888 | 0 | case VLM_GET_MEDIA_ID: |
889 | 0 | psz_id = (const char*)va_arg( args, const char * ); |
890 | 0 | p_id = (int64_t*)va_arg( args, int64_t * ); |
891 | 0 | return vlm_ControlMediaGetId( p_vlm, psz_id, p_id ); |
892 | | |
893 | | |
894 | | /* Media instance control */ |
895 | 0 | case VLM_GET_MEDIA_INSTANCES: |
896 | 0 | id = (int64_t)va_arg( args, int64_t ); |
897 | 0 | ppp_idsc = (vlm_media_instance_t ***)va_arg( args, vlm_media_instance_t *** ); |
898 | 0 | pi_int = (int *)va_arg( args, int *); |
899 | 0 | return vlm_ControlMediaInstanceGets( p_vlm, id, ppp_idsc, pi_int ); |
900 | | |
901 | 0 | case VLM_CLEAR_MEDIA_INSTANCES: |
902 | 0 | id = (int64_t)va_arg( args, int64_t ); |
903 | 0 | return vlm_ControlMediaInstanceClear( p_vlm, id ); |
904 | | |
905 | | |
906 | 0 | case VLM_START_MEDIA_BROADCAST_INSTANCE: |
907 | 0 | id = (int64_t)va_arg( args, int64_t ); |
908 | 0 | psz_id = (const char*)va_arg( args, const char* ); |
909 | 0 | i_int = (int)va_arg( args, int ); |
910 | 0 | return vlm_ControlMediaInstanceStart( p_vlm, id, psz_id, i_int ); |
911 | | |
912 | 0 | case VLM_STOP_MEDIA_INSTANCE: |
913 | 0 | id = (int64_t)va_arg( args, int64_t ); |
914 | 0 | psz_id = (const char*)va_arg( args, const char* ); |
915 | 0 | return vlm_ControlMediaInstanceStop( p_vlm, id, psz_id ); |
916 | | |
917 | 0 | case VLM_PAUSE_MEDIA_INSTANCE: |
918 | 0 | id = (int64_t)va_arg( args, int64_t ); |
919 | 0 | psz_id = (const char*)va_arg( args, const char* ); |
920 | 0 | return vlm_ControlMediaInstancePause( p_vlm, id, psz_id ); |
921 | | |
922 | 0 | case VLM_GET_MEDIA_INSTANCE_TIME: |
923 | 0 | id = (int64_t)va_arg( args, int64_t ); |
924 | 0 | psz_id = (const char*)va_arg( args, const char* ); |
925 | 0 | pi_i64 = (int64_t*)va_arg( args, int64_t * ); |
926 | 0 | return vlm_ControlMediaInstanceGetTimePosition( p_vlm, id, psz_id, pi_i64, NULL ); |
927 | 0 | case VLM_GET_MEDIA_INSTANCE_POSITION: |
928 | 0 | id = (int64_t)va_arg( args, int64_t ); |
929 | 0 | psz_id = (const char*)va_arg( args, const char* ); |
930 | 0 | pd_double = (double*)va_arg( args, double* ); |
931 | 0 | return vlm_ControlMediaInstanceGetTimePosition( p_vlm, id, psz_id, NULL, pd_double ); |
932 | | |
933 | 0 | case VLM_SET_MEDIA_INSTANCE_TIME: |
934 | 0 | id = (int64_t)va_arg( args, int64_t ); |
935 | 0 | psz_id = (const char*)va_arg( args, const char* ); |
936 | 0 | i_i64 = (int64_t)va_arg( args, int64_t); |
937 | 0 | return vlm_ControlMediaInstanceSetTimePosition( p_vlm, id, psz_id, i_i64, -1 ); |
938 | 0 | case VLM_SET_MEDIA_INSTANCE_POSITION: |
939 | 0 | id = (int64_t)va_arg( args, int64_t ); |
940 | 0 | psz_id = (const char*)va_arg( args, const char* ); |
941 | 0 | d_double = (double)va_arg( args, double ); |
942 | 0 | return vlm_ControlMediaInstanceSetTimePosition( p_vlm, id, psz_id, -1, d_double ); |
943 | | |
944 | 0 | case VLM_CLEAR_SCHEDULES: |
945 | 0 | return vlm_ControlScheduleClear( p_vlm ); |
946 | | |
947 | 0 | default: |
948 | 0 | msg_Err( p_vlm, "unknown VLM query" ); |
949 | 0 | return VLC_EGENERIC; |
950 | 0 | } |
951 | 0 | } |
952 | | |
953 | | int vlm_ControlInternal( vlm_t *p_vlm, int i_query, ... ) |
954 | 0 | { |
955 | 0 | va_list args; |
956 | 0 | int i_result; |
957 | |
|
958 | 0 | va_start( args, i_query ); |
959 | 0 | i_result = vlm_vaControlInternal( p_vlm, i_query, args ); |
960 | 0 | va_end( args ); |
961 | |
|
962 | 0 | return i_result; |
963 | 0 | } |
964 | | |
965 | | int vlm_Control( vlm_t *p_vlm, int i_query, ... ) |
966 | 0 | { |
967 | 0 | va_list args; |
968 | 0 | int i_result; |
969 | |
|
970 | 0 | va_start( args, i_query ); |
971 | |
|
972 | 0 | vlc_mutex_lock( &p_vlm->lock ); |
973 | 0 | i_result = vlm_vaControlInternal( p_vlm, i_query, args ); |
974 | 0 | vlc_mutex_unlock( &p_vlm->lock ); |
975 | |
|
976 | 0 | va_end( args ); |
977 | |
|
978 | 0 | return i_result; |
979 | 0 | } |