1 /*****************************************************************************
2 * vlm.c: libvlc new API VLM handling functions
3 *****************************************************************************
4 * Copyright (C) 2005 the VideoLAN team
7 * Authors: Clément Stenac <zorglub@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 #include <vlc/libvlc.h>
25 #include <vlc/libvlc_vlm.h>
27 #include <vlc_input.h>
30 #include "libvlc_internal.h"
32 /* VLM events callback. Transmit to libvlc */
33 static int VlmEvent( vlc_object_t *p_this, const char * name,
34 vlc_value_t old_val, vlc_value_t newval, void *param )
36 vlm_event_t *event = (vlm_event_t*)newval.p_address;
37 libvlc_event_manager_t *p_event_manager = (libvlc_event_manager_t *) param;
38 libvlc_event_t libvlc_event;
42 VLC_UNUSED( old_val );
44 libvlc_event.u.vlm_media_event.psz_instance_name = NULL;
45 libvlc_event.u.vlm_media_event.psz_media_name = event->psz_name;
47 switch( event->i_type )
49 case VLM_EVENT_MEDIA_ADDED:
50 libvlc_event.type = libvlc_VlmMediaAdded;
52 case VLM_EVENT_MEDIA_REMOVED:
53 libvlc_event.type = libvlc_VlmMediaRemoved;
55 case VLM_EVENT_MEDIA_CHANGED:
56 libvlc_event.type = libvlc_VlmMediaChanged;
58 case VLM_EVENT_MEDIA_INSTANCE_STARTED:
59 libvlc_event.type = libvlc_VlmMediaInstanceStarted;
61 case VLM_EVENT_MEDIA_INSTANCE_STOPPED:
62 libvlc_event.type = libvlc_VlmMediaInstanceStopped;
64 case VLM_EVENT_MEDIA_INSTANCE_STATE:
65 libvlc_event.u.vlm_media_event.psz_instance_name =
66 event->psz_instance_name;
67 switch( event->input_state )
70 libvlc_event.type = libvlc_VlmMediaInstanceStatusInit;
74 libvlc_VlmMediaInstanceStatusOpening;
78 libvlc_VlmMediaInstanceStatusPlaying;
81 libvlc_event.type = libvlc_VlmMediaInstanceStatusPause;
84 libvlc_event.type = libvlc_VlmMediaInstanceStatusEnd;
87 libvlc_event.type = libvlc_VlmMediaInstanceStatusError;
96 libvlc_event_send( p_event_manager, &libvlc_event );
100 static void libvlc_vlm_release_internal( libvlc_instance_t *p_instance )
102 vlm_t *p_vlm = p_instance->libvlc_vlm.p_vlm;
103 if( !p_instance->libvlc_vlm.p_vlm )
105 /* We need to remove medias in order to receive events */
106 vlm_Control( p_vlm, VLM_CLEAR_MEDIAS );
107 vlm_Control( p_vlm, VLM_CLEAR_SCHEDULES );
109 var_DelCallback( (vlc_object_t *)p_vlm, "intf-event", VlmEvent,
110 p_instance->libvlc_vlm.p_event_manager );
111 p_instance->libvlc_vlm.pf_release = NULL;
112 libvlc_event_manager_release( p_instance->libvlc_vlm.p_event_manager );
113 p_instance->libvlc_vlm.p_event_manager = NULL;
115 p_instance->libvlc_vlm.p_vlm = NULL;
118 static int libvlc_vlm_init( libvlc_instance_t *p_instance,
119 libvlc_exception_t *p_exception )
121 if( !p_instance->libvlc_vlm.p_event_manager )
123 p_instance->libvlc_vlm.p_event_manager =
124 libvlc_event_manager_new( p_instance->libvlc_vlm.p_vlm,
125 p_instance, p_exception );
126 libvlc_event_manager_register_event_type(
127 p_instance->libvlc_vlm.p_event_manager,
128 libvlc_VlmMediaAdded, NULL );
129 libvlc_event_manager_register_event_type(
130 p_instance->libvlc_vlm.p_event_manager,
131 libvlc_VlmMediaRemoved, NULL );
132 libvlc_event_manager_register_event_type(
133 p_instance->libvlc_vlm.p_event_manager,
134 libvlc_VlmMediaChanged, NULL );
135 libvlc_event_manager_register_event_type(
136 p_instance->libvlc_vlm.p_event_manager,
137 libvlc_VlmMediaInstanceStarted, NULL );
138 libvlc_event_manager_register_event_type(
139 p_instance->libvlc_vlm.p_event_manager,
140 libvlc_VlmMediaInstanceStopped, NULL );
141 libvlc_event_manager_register_event_type(
142 p_instance->libvlc_vlm.p_event_manager,
143 libvlc_VlmMediaInstanceStatusInit, NULL );
144 libvlc_event_manager_register_event_type(
145 p_instance->libvlc_vlm.p_event_manager,
146 libvlc_VlmMediaInstanceStatusOpening, NULL );
147 libvlc_event_manager_register_event_type(
148 p_instance->libvlc_vlm.p_event_manager,
149 libvlc_VlmMediaInstanceStatusPlaying, NULL );
150 libvlc_event_manager_register_event_type(
151 p_instance->libvlc_vlm.p_event_manager,
152 libvlc_VlmMediaInstanceStatusPause, NULL );
153 libvlc_event_manager_register_event_type(
154 p_instance->libvlc_vlm.p_event_manager,
155 libvlc_VlmMediaInstanceStatusEnd, NULL );
156 libvlc_event_manager_register_event_type(
157 p_instance->libvlc_vlm.p_event_manager,
158 libvlc_VlmMediaInstanceStatusError, NULL );
161 if( !p_instance->libvlc_vlm.p_vlm )
163 p_instance->libvlc_vlm.p_vlm = vlm_New( p_instance->p_libvlc_int );
164 if( !p_instance->libvlc_vlm.p_vlm )
166 libvlc_exception_raise( p_exception,
167 "Unable to create VLM." );
170 var_AddCallback( (vlc_object_t *)p_instance->libvlc_vlm.p_vlm,
171 "intf-event", VlmEvent,
172 p_instance->libvlc_vlm.p_event_manager );
173 p_instance->libvlc_vlm.pf_release = libvlc_vlm_release_internal;
179 void libvlc_vlm_release( libvlc_instance_t *p_instance,
180 libvlc_exception_t *p_exception)
182 libvlc_vlm_release_internal( p_instance );
185 #define VLM_RET(p,ret) do { \
186 if( libvlc_vlm_init( p_instance, p_exception ) ) return ret;\
187 (p) = p_instance->libvlc_vlm.p_vlm; \
189 #define VLM(p) VLM_RET(p,)
191 static vlm_media_instance_t *
192 libvlc_vlm_get_media_instance( libvlc_instance_t *p_instance,
193 const char *psz_name, int i_minstance_idx,
194 libvlc_exception_t *p_exception )
197 vlm_media_instance_t **pp_minstance;
198 vlm_media_instance_t *p_minstance;
202 VLM_RET(p_vlm, NULL);
204 if( vlm_Control( p_vlm, VLM_GET_MEDIA_ID, psz_name, &id ) ||
205 vlm_Control( p_vlm, VLM_GET_MEDIA_INSTANCES, id, &pp_minstance,
208 libvlc_exception_raise( p_exception, "Unable to get %s instances",
213 if( i_minstance_idx >= 0 && i_minstance_idx < i_minstance )
215 p_minstance = pp_minstance[i_minstance_idx];
216 TAB_REMOVE( i_minstance, pp_minstance, p_minstance );
218 while( i_minstance > 0 )
219 vlm_media_instance_Delete( pp_minstance[--i_minstance] );
220 TAB_CLEAN( i_minstance, pp_minstance );
224 /* local function to be used in libvlc_vlm_show_media only */
225 static char* recurse_answer( vlm_message_t *p_answer, const char* psz_delim,
227 char* psz_childdelim = NULL;
228 char* psz_nametag = NULL;
229 char* psz_response = strdup( "" );
232 vlm_message_t *aw_child, **paw_child;
234 i_success = asprintf( &psz_childdelim, "%s\t", psz_delim);
236 /* starting with the children of root node */
237 if( i_success != -1 && p_answer->i_child )
239 paw_child = p_answer->child;
240 aw_child = *( paw_child );
241 /* Iterate over children */
242 for( i = 0; i < p_answer->i_child; i++ )
244 /* Spare comma if it is the last element */
246 if( i == (p_answer->i_child - 1) )
249 /* Append name of child node, if not in a list */
252 i_success = asprintf( &psz_response, "%s\"%s\": ",
253 psz_response, aw_child->psz_name );
254 if( i_success == -1 ) break;
257 /* If child node has children, */
258 if( aw_child->i_child )
260 /* If the parent node is a list (hence the child node is
261 * inside a list), create a property of its name as if it
262 * had a name value node
266 i_success = asprintf( &psz_nametag, "\"name\": \"%s\",%s",
267 aw_child->psz_name, psz_childdelim );
268 if( i_success == -1 ) break;
272 psz_nametag = strdup( "" );
274 /* If the child is a list itself, format it accordingly and
275 * recurse through the child's children, telling them that
276 * they are inside a list.
278 if( strcmp( aw_child->psz_name, "media" ) == 0 ||
279 strcmp( aw_child->psz_name, "inputs" ) == 0 ||
280 strcmp( aw_child->psz_name, "options" ) == 0 )
282 i_success = asprintf( &psz_response, "%s[%s%s%s]%c%s",
283 psz_response, psz_childdelim,
284 recurse_answer( aw_child,
286 psz_delim, c_comma, psz_delim );
287 if( i_success == -1 ) break;
289 /* Not a list, so format the child as a JSON object and
290 * recurse through the child's children
294 i_success = asprintf( &psz_response, "%s{%s%s%s%s}%c%s",
295 psz_response, psz_childdelim, psz_nametag,
296 recurse_answer( aw_child,
298 psz_delim, c_comma, psz_delim );
299 if( i_success == -1 ) break;
302 /* Otherwise - when no children are present - the node is a
303 * value node. So print the value string
307 /* If value is equivalent to NULL, print it as null */
308 if( aw_child->psz_value == NULL
309 || strcmp( aw_child->psz_value, "(null)" ) == 0 )
311 i_success = asprintf( &psz_response, "%snull%c%s",
312 psz_response, c_comma, psz_delim );
313 if( i_success == -1 )
316 /* Otherwise print the value in quotation marks */
319 i_success = asprintf( &psz_response, "%s\"%s\"%c%s",
320 psz_response, aw_child->psz_value,
321 c_comma, psz_delim );
322 if( i_success == -1 ) break;
325 /* getting next child */
327 aw_child = *( paw_child );
331 free( psz_childdelim );
332 if( i_success == -1 )
334 free( psz_response );
335 psz_response = strdup( "" );
340 const char* libvlc_vlm_show_media( libvlc_instance_t *p_instance,
341 const char *psz_name,
342 libvlc_exception_t *p_exception )
344 char *psz_message = NULL;
345 vlm_message_t *answer = NULL;
346 char *psz_response = NULL;
347 const char *psz_fmt = NULL;
348 const char *psz_delimiter = NULL;
352 VLM_RET(p_vlm, NULL);
354 if( psz_name == NULL )
356 libvlc_exception_raise( p_exception, "No media name supplied" );
358 else if( asprintf( &psz_message, "show %s", psz_name ) == -1 )
360 libvlc_exception_raise( p_exception, "Unable to call show %s",
365 vlm_ExecuteCommand( p_vlm, psz_message, &answer );
366 if( answer->psz_value )
368 libvlc_exception_raise( p_exception, "Unable to call show %s: %s",
369 psz_name, answer->psz_value );
371 else if ( answer->child ) {
372 /* in case everything was requested */
373 if ( strcmp( psz_name, "" ) == 0 )
375 psz_fmt = "{\n\t%s\n}\n";
376 psz_delimiter = "\n\t";
382 psz_delimiter = "\n";
385 if( asprintf( &psz_response, psz_fmt,
386 recurse_answer( answer, psz_delimiter, i_list ) )
389 libvlc_exception_raise( p_exception, "Error in show %s",
395 return( psz_response );
399 void libvlc_vlm_add_broadcast( libvlc_instance_t *p_instance,
400 const char *psz_name,
401 const char *psz_input,
402 const char *psz_output, int i_options,
403 const char * const *ppsz_options,
404 int b_enabled, int b_loop,
405 libvlc_exception_t *p_exception )
413 vlm_media_Init( &m );
414 m.psz_name = strdup( psz_name );
415 m.b_enabled = b_enabled;
417 m.broadcast.b_loop = b_loop;
419 TAB_APPEND( m.i_input, m.ppsz_input, strdup(psz_input) );
421 m.psz_output = strdup( psz_output );
422 for( n = 0; n < i_options; n++ )
423 TAB_APPEND( m.i_option, m.ppsz_option, strdup(ppsz_options[n]) );
425 n = vlm_Control( p_vlm, VLM_ADD_MEDIA, &m, NULL );
426 vlm_media_Clean( &m );
428 libvlc_exception_raise( p_exception, "Media %s creation failed",
432 void libvlc_vlm_add_vod( libvlc_instance_t *p_instance, const char *psz_name,
433 const char *psz_input, int i_options,
434 const char * const *ppsz_options, int b_enabled,
435 const char *psz_mux, libvlc_exception_t *p_exception )
443 vlm_media_Init( &m );
444 m.psz_name = strdup( psz_name );
445 m.b_enabled = b_enabled;
447 m.vod.psz_mux = psz_mux ? strdup( psz_mux ) : NULL;
449 TAB_APPEND( m.i_input, m.ppsz_input, strdup(psz_input) );
450 for( n = 0; n < i_options; n++ )
451 TAB_APPEND( m.i_option, m.ppsz_option, strdup(ppsz_options[n]) );
453 n = vlm_Control( p_vlm, VLM_ADD_MEDIA, &m, NULL );
454 vlm_media_Clean( &m );
456 libvlc_exception_raise( p_exception, "Media %s creation failed",
460 void libvlc_vlm_del_media( libvlc_instance_t *p_instance, const char *psz_name,
461 libvlc_exception_t *p_exception )
468 if( vlm_Control( p_vlm, VLM_GET_MEDIA_ID, psz_name, &id ) ||
469 vlm_Control( p_vlm, VLM_DEL_MEDIA, id ) )
471 libvlc_exception_raise( p_exception, "Unable to delete %s", psz_name );
475 #define VLM_CHANGE(psz_error, code ) do { \
476 vlm_media_t *p_media; \
480 if( vlm_Control( p_vlm, VLM_GET_MEDIA_ID, psz_name, &id ) || \
481 vlm_Control( p_vlm, VLM_GET_MEDIA, id, &p_media ) ) { \
482 libvlc_exception_raise( p_exception, psz_error, psz_name ); \
485 if( !p_media ) goto error; \
489 if( vlm_Control( p_vlm, VLM_CHANGE_MEDIA, p_media ) ) { \
490 vlm_media_Delete( p_media ); \
493 vlm_media_Delete( p_media ); \
496 libvlc_exception_raise( p_exception, psz_error, psz_name );\
499 void libvlc_vlm_set_enabled( libvlc_instance_t *p_instance,
500 const char *psz_name, int b_enabled,
501 libvlc_exception_t *p_exception )
503 #define VLM_CHANGE_CODE { p_media->b_enabled = b_enabled; }
504 VLM_CHANGE( "Unable to delete %s", VLM_CHANGE_CODE );
505 #undef VLM_CHANGE_CODE
508 void libvlc_vlm_set_loop( libvlc_instance_t *p_instance, const char *psz_name,
509 int b_loop, libvlc_exception_t *p_exception )
511 #define VLM_CHANGE_CODE { p_media->broadcast.b_loop = b_loop; }
512 VLM_CHANGE( "Unable to change %s loop property", VLM_CHANGE_CODE );
513 #undef VLM_CHANGE_CODE
516 void libvlc_vlm_set_mux( libvlc_instance_t *p_instance, const char *psz_name,
517 const char *psz_mux, libvlc_exception_t *p_exception )
519 #define VLM_CHANGE_CODE { if( p_media->b_vod ) { \
520 free( p_media->vod.psz_mux ); \
521 p_media->vod.psz_mux = psz_mux \
522 ? strdup( psz_mux ) : NULL; \
524 VLM_CHANGE( "Unable to change %s mux property", VLM_CHANGE_CODE );
525 #undef VLM_CHANGE_CODE
528 void libvlc_vlm_set_output( libvlc_instance_t *p_instance,
529 const char *psz_name, const char *psz_output,
530 libvlc_exception_t *p_exception )
532 #define VLM_CHANGE_CODE { free( p_media->psz_output ); \
533 p_media->psz_output = strdup( psz_output ); }
534 VLM_CHANGE( "Unable to change %s output property", VLM_CHANGE_CODE );
535 #undef VLM_CHANGE_CODE
538 void libvlc_vlm_set_input( libvlc_instance_t *p_instance,
539 const char *psz_name, const char *psz_input,
540 libvlc_exception_t *p_exception )
542 #define VLM_CHANGE_CODE { while( p_media->i_input > 0 ) \
543 free( p_media->ppsz_input[--p_media->i_input] );\
544 TAB_APPEND( p_media->i_input, p_media->ppsz_input, \
545 strdup(psz_input) ); }
546 VLM_CHANGE( "Unable to change %s input property", VLM_CHANGE_CODE );
547 #undef VLM_CHANGE_CODE
550 void libvlc_vlm_add_input( libvlc_instance_t *p_instance,
551 const char *psz_name, const char *psz_input,
552 libvlc_exception_t *p_exception )
554 #define VLM_CHANGE_CODE { TAB_APPEND( p_media->i_input, p_media->ppsz_input, \
555 strdup(psz_input) ); }
556 VLM_CHANGE( "Unable to change %s input property", VLM_CHANGE_CODE );
557 #undef VLM_CHANGE_CODE
560 void libvlc_vlm_change_media( libvlc_instance_t *p_instance,
561 const char *psz_name, const char *psz_input,
562 const char *psz_output, int i_options,
563 const char * const *ppsz_options, int b_enabled,
564 int b_loop, libvlc_exception_t *p_exception )
566 #define VLM_CHANGE_CODE { int n; \
567 p_media->b_enabled = b_enabled; \
568 p_media->broadcast.b_loop = b_loop; \
569 while( p_media->i_input > 0 ) \
570 free( p_media->ppsz_input[--p_media->i_input] ); \
572 TAB_APPEND( p_media->i_input, p_media->ppsz_input, strdup(psz_input) ); \
573 free( p_media->psz_output ); \
574 p_media->psz_output = psz_output ? strdup( psz_output ) : NULL; \
575 while( p_media->i_option > 0 ) \
576 free( p_media->ppsz_option[--p_media->i_option] ); \
577 for( n = 0; n < i_options; n++ ) \
578 TAB_APPEND( p_media->i_option, p_media->ppsz_option, \
579 strdup(ppsz_options[n]) ); \
581 VLM_CHANGE( "Unable to change %s properties", VLM_CHANGE_CODE );
582 #undef VLM_CHANGE_CODE
585 void libvlc_vlm_play_media( libvlc_instance_t *p_instance,
586 const char *psz_name,
587 libvlc_exception_t *p_exception )
594 if( vlm_Control( p_vlm, VLM_GET_MEDIA_ID, psz_name, &id ) ||
595 vlm_Control( p_vlm, VLM_START_MEDIA_BROADCAST_INSTANCE, id, NULL, 0 ) )
597 libvlc_exception_raise( p_exception, "Unable to play %s", psz_name );
601 void libvlc_vlm_stop_media( libvlc_instance_t *p_instance,
602 const char *psz_name,
603 libvlc_exception_t *p_exception )
610 if( vlm_Control( p_vlm, VLM_GET_MEDIA_ID, psz_name, &id ) ||
611 vlm_Control( p_vlm, VLM_STOP_MEDIA_INSTANCE, id, NULL ) )
613 libvlc_exception_raise( p_exception, "Unable to stop %s", psz_name );
617 void libvlc_vlm_pause_media( libvlc_instance_t *p_instance,
618 const char *psz_name,
619 libvlc_exception_t *p_exception )
626 if( vlm_Control( p_vlm, VLM_GET_MEDIA_ID, psz_name, &id ) ||
627 vlm_Control( p_vlm, VLM_PAUSE_MEDIA_INSTANCE, id, NULL ) )
629 libvlc_exception_raise( p_exception, "Unable to pause %s", psz_name );
633 void libvlc_vlm_seek_media( libvlc_instance_t *p_instance,
634 const char *psz_name, float f_percentage,
635 libvlc_exception_t *p_exception )
642 if( vlm_Control( p_vlm, VLM_GET_MEDIA_ID, psz_name, &id ) ||
643 vlm_Control( p_vlm, VLM_SET_MEDIA_INSTANCE_POSITION, id, NULL,
645 libvlc_exception_raise( p_exception, "Unable to seek %s to %f",
646 psz_name, f_percentage );
649 float libvlc_vlm_get_media_instance_position( libvlc_instance_t *p_instance,
650 const char *psz_name,
652 libvlc_exception_t *p_exception )
654 vlm_media_instance_t *p_mi;
657 p_mi = libvlc_vlm_get_media_instance( p_instance, psz_name,
658 i_instance, p_exception );
661 result = p_mi->d_position;
662 vlm_media_instance_Delete( p_mi );
667 int libvlc_vlm_get_media_instance_time( libvlc_instance_t *p_instance,
668 const char *psz_name, int i_instance,
669 libvlc_exception_t *p_exception )
671 vlm_media_instance_t *p_mi;
674 p_mi = libvlc_vlm_get_media_instance( p_instance, psz_name,
675 i_instance, p_exception );
678 result = p_mi->i_time;
679 vlm_media_instance_Delete( p_mi );
684 int libvlc_vlm_get_media_instance_length( libvlc_instance_t *p_instance,
685 const char *psz_name,
687 libvlc_exception_t *p_exception )
689 vlm_media_instance_t *p_mi;
692 p_mi = libvlc_vlm_get_media_instance( p_instance, psz_name,
693 i_instance, p_exception );
696 result = p_mi->i_length;
697 vlm_media_instance_Delete( p_mi );
702 int libvlc_vlm_get_media_instance_rate( libvlc_instance_t *p_instance,
703 const char *psz_name, int i_instance,
704 libvlc_exception_t *p_exception )
706 vlm_media_instance_t *p_mi;
709 p_mi = libvlc_vlm_get_media_instance( p_instance, psz_name,
710 i_instance, p_exception );
713 result = p_mi->i_rate;
714 vlm_media_instance_Delete( p_mi );
719 int libvlc_vlm_get_media_instance_title( libvlc_instance_t *p_instance,
720 const char *psz_name, int i_instance,
721 libvlc_exception_t *p_exception )
723 vlm_media_instance_t *p_mi;
725 p_mi = libvlc_vlm_get_media_instance( p_instance, psz_name,
726 i_instance, p_exception );
728 vlm_media_instance_Delete( p_mi );
729 return p_mi ? 0 : -1;
732 int libvlc_vlm_get_media_instance_chapter( libvlc_instance_t *p_instance,
733 const char *psz_name,
735 libvlc_exception_t *p_exception )
737 vlm_media_instance_t *p_mi;
739 p_mi = libvlc_vlm_get_media_instance( p_instance, psz_name,
740 i_instance, p_exception );
742 vlm_media_instance_Delete( p_mi );
743 return p_mi ? 0 : -1;
746 int libvlc_vlm_get_media_instance_seekable( libvlc_instance_t *p_instance,
747 const char *psz_name,
749 libvlc_exception_t *p_exception )
751 vlm_media_instance_t *p_mi;
753 p_mi = libvlc_vlm_get_media_instance( p_instance, psz_name,
754 i_instance, p_exception );
756 vlm_media_instance_Delete( p_mi );
757 return p_mi ? 0 : -1;
760 libvlc_event_manager_t * libvlc_vlm_get_event_manager( libvlc_instance_t *p_instance,
761 libvlc_exception_t *p_exception )
764 VLM_RET( p_vlm, NULL);
765 return p_instance->libvlc_vlm.p_event_manager;