2 * valerie.c -- High Level Client API for miracle
3 * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
4 * Author: Charles Yates <charles.yates@pandora.be>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 /* System header files */
27 /* Application header files */
29 #include "valerie_tokeniser.h"
30 #include "valerie_util.h"
32 /** Initialise the valerie structure.
35 valerie
valerie_init( valerie_parser parser
)
37 valerie
this = malloc( sizeof( valerie_t
) );
40 memset( this, 0, sizeof( valerie_t
) );
41 this->parser
= parser
;
46 /** Set the response structure associated to the last command.
49 static void valerie_set_last_response( valerie
this, valerie_response response
)
53 if ( this->last_response
!= NULL
)
54 valerie_response_close( this->last_response
);
55 this->last_response
= response
;
59 /** Connect to the parser.
62 valerie_error_code
valerie_connect( valerie
this )
64 valerie_error_code error
= valerie_server_unavailable
;
65 valerie_response response
= valerie_parser_connect( this->parser
);
66 if ( response
!= NULL
)
68 valerie_set_last_response( this, response
);
69 if ( valerie_response_get_error_code( response
) == 100 )
75 /** Interpret a non-context sensitive error code.
78 static valerie_error_code
valerie_get_error_code( valerie
this, valerie_response response
)
80 valerie_error_code error
= valerie_server_unavailable
;
81 switch( valerie_response_get_error_code( response
) )
84 error
= valerie_server_unavailable
;
87 error
= valerie_no_response
;
95 error
= valerie_invalid_command
;
98 error
= valerie_server_timeout
;
101 error
= valerie_missing_argument
;
104 error
= valerie_unit_unavailable
;
107 error
= valerie_invalid_file
;
111 error
= valerie_unknown_error
;
117 /** Execute a command.
120 valerie_error_code
valerie_execute( valerie
this, size_t size
, char *format
, ... )
122 valerie_error_code error
= valerie_server_unavailable
;
123 char *command
= malloc( size
);
124 if ( this != NULL
&& command
!= NULL
)
127 va_start( list
, format
);
128 if ( vsnprintf( command
, size
, format
, list
) != 0 )
130 valerie_response response
= valerie_parser_execute( this->parser
, command
);
131 valerie_set_last_response( this, response
);
132 error
= valerie_get_error_code( this, response
);
136 error
= valerie_invalid_command
;
142 error
= valerie_malloc_failed
;
148 /** Execute a command.
151 valerie_error_code
valerie_push( valerie
this, mlt_service service
, size_t size
, char *format
, ... )
153 valerie_error_code error
= valerie_server_unavailable
;
154 char *command
= malloc( size
);
155 if ( this != NULL
&& command
!= NULL
)
158 va_start( list
, format
);
159 if ( vsnprintf( command
, size
, format
, list
) != 0 )
161 valerie_response response
= valerie_parser_push( this->parser
, command
, service
);
162 valerie_set_last_response( this, response
);
163 error
= valerie_get_error_code( this, response
);
167 error
= valerie_invalid_command
;
173 error
= valerie_malloc_failed
;
179 /** Set a global property.
182 valerie_error_code
valerie_set( valerie
this, char *property
, char *value
)
184 return valerie_execute( this, 1024, "SET %s=%s", property
, value
);
187 /** Get a global property.
190 valerie_error_code
valerie_get( valerie
this, char *property
, char *value
, int length
)
192 valerie_error_code error
= valerie_execute( this, 1024, "GET %s", property
);
193 if ( error
== valerie_ok
)
195 valerie_response response
= valerie_get_last_response( this );
196 strncpy( value
, valerie_response_get_line( response
, 1 ), length
);
204 valerie_error_code
valerie_run( valerie
this, char *file
)
206 return valerie_execute( this, 10240, "RUN \"%s\"", file
);
212 valerie_error_code
valerie_unit_add( valerie
this, char *guid
, int *unit
)
214 valerie_error_code error
= valerie_execute( this, 1024, "UADD %s", guid
);
215 if ( error
== valerie_ok
)
217 int length
= valerie_response_count( this->last_response
);
218 char *line
= valerie_response_get_line( this->last_response
, length
- 1 );
219 if ( line
== NULL
|| sscanf( line
, "U%d", unit
) != 1 )
220 error
= valerie_unit_creation_failed
;
224 if ( error
== valerie_unknown_error
)
225 error
= valerie_unit_creation_failed
;
230 /** Load a file on the specified unit.
233 valerie_error_code
valerie_unit_load( valerie
this, int unit
, char *file
)
235 return valerie_execute( this, 10240, "LOAD U%d \"%s\"", unit
, file
);
238 static void valerie_interpret_clip_offset( char *output
, valerie_clip_offset offset
, int clip
)
242 case valerie_absolute
:
243 sprintf( output
, "%d", clip
);
245 case valerie_relative
:
247 sprintf( output
, "%d", clip
);
249 sprintf( output
, "+%d", clip
);
254 /** Load a file on the specified unit with the specified in/out points.
257 valerie_error_code
valerie_unit_load_clipped( valerie
this, int unit
, char *file
, int32_t in
, int32_t out
)
259 return valerie_execute( this, 10240, "LOAD U%d \"%s\" %d %d", unit
, file
, in
, out
);
262 /** Load a file on the specified unit at the end of the current pump.
265 valerie_error_code
valerie_unit_load_back( valerie
this, int unit
, char *file
)
267 return valerie_execute( this, 10240, "LOAD U%d \"!%s\"", unit
, file
);
270 /** Load a file on the specified unit at the end of the pump with the specified in/out points.
273 valerie_error_code
valerie_unit_load_back_clipped( valerie
this, int unit
, char *file
, int32_t in
, int32_t out
)
275 return valerie_execute( this, 10240, "LOAD U%d \"!%s\" %d %d", unit
, file
, in
, out
);
278 /** Append a file on the specified unit.
281 valerie_error_code
valerie_unit_append( valerie
this, int unit
, char *file
, int32_t in
, int32_t out
)
283 return valerie_execute( this, 10240, "APND U%d \"%s\" %d %d", unit
, file
, in
, out
);
286 /** Push a service on to a unit.
289 valerie_error_code
valerie_unit_push( valerie
this, int unit
, char *command
, mlt_service service
)
291 return valerie_push( this, service
, 10240, "PUSH U%d %s", unit
, command
);
294 /** Clean the unit - this function removes all but the currently playing clip.
297 valerie_error_code
valerie_unit_clean( valerie
this, int unit
)
299 return valerie_execute( this, 1024, "CLEAN U%d", unit
);
302 /** Clear the unit - this function removes all clips.
305 valerie_error_code
valerie_unit_clear( valerie
this, int unit
)
307 return valerie_execute( this, 1024, "CLEAR U%d", unit
);
310 /** Move clips on the units playlist.
313 valerie_error_code
valerie_unit_clip_move( valerie
this, int unit
, valerie_clip_offset src_offset
, int src
, valerie_clip_offset dest_offset
, int dest
)
317 valerie_interpret_clip_offset( temp1
, src_offset
, src
);
318 valerie_interpret_clip_offset( temp2
, dest_offset
, dest
);
319 return valerie_execute( this, 1024, "MOVE U%d %s %s", unit
, temp1
, temp2
);
322 /** Remove clip at the specified position.
325 valerie_error_code
valerie_unit_clip_remove( valerie
this, int unit
, valerie_clip_offset offset
, int clip
)
328 valerie_interpret_clip_offset( temp
, offset
, clip
);
329 return valerie_execute( this, 1024, "REMOVE U%d %s", unit
, temp
);
332 /** Remove the currently playing clip.
335 valerie_error_code
valerie_unit_remove_current_clip( valerie
this, int unit
)
337 return valerie_execute( this, 1024, "REMOVE U%d", unit
);
340 /** Insert clip at the specified position.
343 valerie_error_code
valerie_unit_clip_insert( valerie
this, int unit
, valerie_clip_offset offset
, int clip
, char *file
, int32_t in
, int32_t out
)
346 valerie_interpret_clip_offset( temp
, offset
, clip
);
347 return valerie_execute( this, 1024, "INSERT U%d \"%s\" %s %d %d", unit
, file
, temp
, in
, out
);
350 /** Play the unit at normal speed.
353 valerie_error_code
valerie_unit_play( valerie
this, int unit
)
355 return valerie_execute( this, 1024, "PLAY U%d 1000", unit
);
358 /** Play the unit at specified speed.
361 valerie_error_code
valerie_unit_play_at_speed( valerie
this, int unit
, int speed
)
363 return valerie_execute( this, 10240, "PLAY U%d %d", unit
, speed
);
366 /** Stop playback on the specified unit.
369 valerie_error_code
valerie_unit_stop( valerie
this, int unit
)
371 return valerie_execute( this, 1024, "STOP U%d", unit
);
374 /** Pause playback on the specified unit.
377 valerie_error_code
valerie_unit_pause( valerie
this, int unit
)
379 return valerie_execute( this, 1024, "PAUSE U%d", unit
);
382 /** Rewind the specified unit.
385 valerie_error_code
valerie_unit_rewind( valerie
this, int unit
)
387 return valerie_execute( this, 1024, "REW U%d", unit
);
390 /** Fast forward the specified unit.
393 valerie_error_code
valerie_unit_fast_forward( valerie
this, int unit
)
395 return valerie_execute( this, 1024, "FF U%d", unit
);
398 /** Step by the number of frames on the specified unit.
401 valerie_error_code
valerie_unit_step( valerie
this, int unit
, int32_t step
)
403 return valerie_execute( this, 1024, "STEP U%d %d", unit
, step
);
406 /** Goto the specified frame on the specified unit.
409 valerie_error_code
valerie_unit_goto( valerie
this, int unit
, int32_t position
)
411 return valerie_execute( this, 1024, "GOTO U%d %d", unit
, position
);
414 /** Goto the specified frame in the clip on the specified unit.
417 valerie_error_code
valerie_unit_clip_goto( valerie
this, int unit
, valerie_clip_offset offset
, int clip
, int32_t position
)
420 valerie_interpret_clip_offset( temp
, offset
, clip
);
421 return valerie_execute( this, 1024, "GOTO U%d %d %s", unit
, position
, temp
);
424 /** Set the in point of the loaded file on the specified unit.
427 valerie_error_code
valerie_unit_set_in( valerie
this, int unit
, int32_t in
)
429 return valerie_execute( this, 1024, "SIN U%d %d", unit
, in
);
432 /** Set the in point of the clip on the specified unit.
435 valerie_error_code
valerie_unit_clip_set_in( valerie
this, int unit
, valerie_clip_offset offset
, int clip
, int32_t in
)
438 valerie_interpret_clip_offset( temp
, offset
, clip
);
439 return valerie_execute( this, 1024, "SIN U%d %d %s", unit
, in
, temp
);
442 /** Set the out point of the loaded file on the specified unit.
445 valerie_error_code
valerie_unit_set_out( valerie
this, int unit
, int32_t out
)
447 return valerie_execute( this, 1024, "SOUT U%d %d", unit
, out
);
450 /** Set the out point of the clip on the specified unit.
453 valerie_error_code
valerie_unit_clip_set_out( valerie
this, int unit
, valerie_clip_offset offset
, int clip
, int32_t in
)
456 valerie_interpret_clip_offset( temp
, offset
, clip
);
457 return valerie_execute( this, 1024, "SOUT U%d %d %s", unit
, in
, temp
);
460 /** Clear the in point of the loaded file on the specified unit.
463 valerie_error_code
valerie_unit_clear_in( valerie
this, int unit
)
465 return valerie_execute( this, 1024, "SIN U%d -1", unit
);
468 /** Clear the out point of the loaded file on the specified unit.
471 valerie_error_code
valerie_unit_clear_out( valerie
this, int unit
)
473 return valerie_execute( this, 1024, "SOUT U%d -1", unit
);
476 /** Clear the in and out points on the loaded file on the specified unit.
479 valerie_error_code
valerie_unit_clear_in_out( valerie
this, int unit
)
481 valerie_error_code error
= valerie_unit_clear_out( this, unit
);
482 if ( error
== valerie_ok
)
483 error
= valerie_unit_clear_in( this, unit
);
487 /** Set a unit configuration property.
490 valerie_error_code
valerie_unit_set( valerie
this, int unit
, char *name
, char *value
)
492 return valerie_execute( this, 1024, "USET U%d %s=%s", unit
, name
, value
);
495 /** Get a unit configuration property.
498 valerie_error_code
valerie_unit_get( valerie
this, int unit
, char *name
)
500 return valerie_execute( this, 1024, "UGET U%d %s", unit
, name
);
503 /** Get a units status.
506 valerie_error_code
valerie_unit_status( valerie
this, int unit
, valerie_status status
)
508 valerie_error_code error
= valerie_execute( this, 1024, "USTA U%d", unit
);
509 int error_code
= valerie_response_get_error_code( this->last_response
);
511 memset( status
, 0, sizeof( valerie_status_t
) );
513 if ( error_code
== 202 && valerie_response_count( this->last_response
) == 2 )
514 valerie_status_parse( status
, valerie_response_get_line( this->last_response
, 1 ) );
515 else if ( error_code
== 403 )
516 status
->status
= unit_undefined
;
521 /** Transfer the current settings of unit src to unit dest.
524 valerie_error_code
valerie_unit_transfer( valerie
this, int src
, int dest
)
526 return valerie_execute( this, 1024, "XFER U%d U%d", src
, dest
);
529 /** Obtain the parsers notifier.
532 valerie_notifier
valerie_get_notifier( valerie
this )
535 return valerie_parser_get_notifier( this->parser
);
540 /** List the contents of the specified directory.
543 valerie_dir
valerie_dir_init( valerie
this, char *directory
)
545 valerie_dir dir
= malloc( sizeof( valerie_dir_t
) );
548 memset( dir
, 0, sizeof( valerie_dir_t
) );
549 dir
->directory
= strdup( directory
);
550 dir
->response
= valerie_parser_executef( this->parser
, "CLS \"%s\"", directory
);
555 /** Return the error code associated to the dir.
558 valerie_error_code
valerie_dir_get_error_code( valerie_dir dir
)
561 return valerie_get_error_code( NULL
, dir
->response
);
563 return valerie_malloc_failed
;
566 /** Get a particular file entry in the directory.
569 valerie_error_code
valerie_dir_get( valerie_dir dir
, int index
, valerie_dir_entry entry
)
571 valerie_error_code error
= valerie_ok
;
572 memset( entry
, 0, sizeof( valerie_dir_entry_t
) );
573 if ( index
< valerie_dir_count( dir
) )
575 char *line
= valerie_response_get_line( dir
->response
, index
+ 1 );
576 valerie_tokeniser tokeniser
= valerie_tokeniser_init( );
577 valerie_tokeniser_parse_new( tokeniser
, line
, " " );
579 if ( valerie_tokeniser_count( tokeniser
) > 0 )
581 valerie_util_strip( valerie_tokeniser_get_string( tokeniser
, 0 ), '\"' );
582 strcpy( entry
->full
, dir
->directory
);
583 if ( entry
->full
[ strlen( entry
->full
) - 1 ] != '/' )
584 strcat( entry
->full
, "/" );
585 strcpy( entry
->name
, valerie_tokeniser_get_string( tokeniser
, 0 ) );
586 strcat( entry
->full
, entry
->name
);
588 switch ( valerie_tokeniser_count( tokeniser
) )
594 entry
->size
= strtoull( valerie_tokeniser_get_string( tokeniser
, 1 ), NULL
, 10 );
597 error
= valerie_invalid_file
;
601 valerie_tokeniser_close( tokeniser
);
606 /** Get the number of entries in the directory
609 int valerie_dir_count( valerie_dir dir
)
611 if ( dir
!= NULL
&& valerie_response_count( dir
->response
) >= 2 )
612 return valerie_response_count( dir
->response
) - 2;
617 /** Close the directory structure.
620 void valerie_dir_close( valerie_dir dir
)
624 free( dir
->directory
);
625 valerie_response_close( dir
->response
);
630 /** List the playlist of the specified unit.
633 valerie_list
valerie_list_init( valerie
this, int unit
)
635 valerie_list list
= calloc( 1, sizeof( valerie_list_t
) );
638 list
->response
= valerie_parser_executef( this->parser
, "LIST U%d", unit
);
639 if ( valerie_response_count( list
->response
) >= 2 )
640 list
->generation
= atoi( valerie_response_get_line( list
->response
, 1 ) );
645 /** Return the error code associated to the list.
648 valerie_error_code
valerie_list_get_error_code( valerie_list list
)
651 return valerie_get_error_code( NULL
, list
->response
);
653 return valerie_malloc_failed
;
656 /** Get a particular file entry in the list.
659 valerie_error_code
valerie_list_get( valerie_list list
, int index
, valerie_list_entry entry
)
661 valerie_error_code error
= valerie_ok
;
662 memset( entry
, 0, sizeof( valerie_list_entry_t
) );
663 if ( index
< valerie_list_count( list
) )
665 char *line
= valerie_response_get_line( list
->response
, index
+ 2 );
666 valerie_tokeniser tokeniser
= valerie_tokeniser_init( );
667 valerie_tokeniser_parse_new( tokeniser
, line
, " " );
669 if ( valerie_tokeniser_count( tokeniser
) > 0 )
671 entry
->clip
= atoi( valerie_tokeniser_get_string( tokeniser
, 0 ) );
672 valerie_util_strip( valerie_tokeniser_get_string( tokeniser
, 1 ), '\"' );
673 strcpy( entry
->full
, valerie_tokeniser_get_string( tokeniser
, 1 ) );
674 entry
->in
= atol( valerie_tokeniser_get_string( tokeniser
, 2 ) );
675 entry
->out
= atol( valerie_tokeniser_get_string( tokeniser
, 3 ) );
676 entry
->max
= atol( valerie_tokeniser_get_string( tokeniser
, 4 ) );
677 entry
->size
= atol( valerie_tokeniser_get_string( tokeniser
, 5 ) );
678 entry
->fps
= atof( valerie_tokeniser_get_string( tokeniser
, 6 ) );
680 valerie_tokeniser_close( tokeniser
);
685 /** Get the number of entries in the list
688 int valerie_list_count( valerie_list list
)
690 if ( list
!= NULL
&& valerie_response_count( list
->response
) >= 3 )
691 return valerie_response_count( list
->response
) - 3;
696 /** Close the list structure.
699 void valerie_list_close( valerie_list list
)
703 valerie_response_close( list
->response
);
708 /** List the currently connected nodes.
711 valerie_nodes
valerie_nodes_init( valerie
this )
713 valerie_nodes nodes
= malloc( sizeof( valerie_nodes_t
) );
716 memset( nodes
, 0, sizeof( valerie_nodes_t
) );
717 nodes
->response
= valerie_parser_executef( this->parser
, "NLS" );
722 /** Return the error code associated to the nodes list.
725 valerie_error_code
valerie_nodes_get_error_code( valerie_nodes nodes
)
728 return valerie_get_error_code( NULL
, nodes
->response
);
730 return valerie_malloc_failed
;
733 /** Get a particular node entry.
736 valerie_error_code
valerie_nodes_get( valerie_nodes nodes
, int index
, valerie_node_entry entry
)
738 valerie_error_code error
= valerie_ok
;
739 memset( entry
, 0, sizeof( valerie_node_entry_t
) );
740 if ( index
< valerie_nodes_count( nodes
) )
742 char *line
= valerie_response_get_line( nodes
->response
, index
+ 1 );
743 valerie_tokeniser tokeniser
= valerie_tokeniser_init( );
744 valerie_tokeniser_parse_new( tokeniser
, line
, " " );
746 if ( valerie_tokeniser_count( tokeniser
) == 3 )
748 entry
->node
= atoi( valerie_tokeniser_get_string( tokeniser
, 0 ) );
749 strncpy( entry
->guid
, valerie_tokeniser_get_string( tokeniser
, 1 ), sizeof( entry
->guid
) );
750 valerie_util_strip( valerie_tokeniser_get_string( tokeniser
, 2 ), '\"' );
751 strncpy( entry
->name
, valerie_tokeniser_get_string( tokeniser
, 2 ), sizeof( entry
->name
) );
754 valerie_tokeniser_close( tokeniser
);
759 /** Get the number of nodes
762 int valerie_nodes_count( valerie_nodes nodes
)
764 if ( nodes
!= NULL
&& valerie_response_count( nodes
->response
) >= 2 )
765 return valerie_response_count( nodes
->response
) - 2;
770 /** Close the nodes structure.
773 void valerie_nodes_close( valerie_nodes nodes
)
777 valerie_response_close( nodes
->response
);
782 /** List the currently defined units.
785 valerie_units
valerie_units_init( valerie
this )
787 valerie_units units
= malloc( sizeof( valerie_units_t
) );
790 memset( units
, 0, sizeof( valerie_units_t
) );
791 units
->response
= valerie_parser_executef( this->parser
, "ULS" );
796 /** Return the error code associated to the nodes list.
799 valerie_error_code
valerie_units_get_error_code( valerie_units units
)
802 return valerie_get_error_code( NULL
, units
->response
);
804 return valerie_malloc_failed
;
807 /** Get a particular unit entry.
810 valerie_error_code
valerie_units_get( valerie_units units
, int index
, valerie_unit_entry entry
)
812 valerie_error_code error
= valerie_ok
;
813 memset( entry
, 0, sizeof( valerie_unit_entry_t
) );
814 if ( index
< valerie_units_count( units
) )
816 char *line
= valerie_response_get_line( units
->response
, index
+ 1 );
817 valerie_tokeniser tokeniser
= valerie_tokeniser_init( );
818 valerie_tokeniser_parse_new( tokeniser
, line
, " " );
820 if ( valerie_tokeniser_count( tokeniser
) == 4 )
822 entry
->unit
= atoi( valerie_tokeniser_get_string( tokeniser
, 0 ) + 1 );
823 entry
->node
= atoi( valerie_tokeniser_get_string( tokeniser
, 1 ) );
824 strncpy( entry
->guid
, valerie_tokeniser_get_string( tokeniser
, 2 ), sizeof( entry
->guid
) );
825 entry
->online
= atoi( valerie_tokeniser_get_string( tokeniser
, 3 ) );
828 valerie_tokeniser_close( tokeniser
);
833 /** Get the number of units
836 int valerie_units_count( valerie_units units
)
838 if ( units
!= NULL
&& valerie_response_count( units
->response
) >= 2 )
839 return valerie_response_count( units
->response
) - 2;
844 /** Close the units structure.
847 void valerie_units_close( valerie_units units
)
851 valerie_response_close( units
->response
);
856 /** Get the response of the last command executed.
859 valerie_response
valerie_get_last_response( valerie
this )
861 return this->last_response
;
864 /** Obtain a printable message associated to the error code provided.
867 char *valerie_error_description( valerie_error_code error
)
869 char *msg
= "Unrecognised error";
875 case valerie_malloc_failed
:
876 msg
= "Memory allocation error";
878 case valerie_unknown_error
:
879 msg
= "Unknown error";
881 case valerie_no_response
:
882 msg
= "No response obtained";
884 case valerie_invalid_command
:
885 msg
= "Invalid command";
887 case valerie_server_timeout
:
888 msg
= "Communications with server timed out";
890 case valerie_missing_argument
:
891 msg
= "Missing argument";
893 case valerie_server_unavailable
:
894 msg
= "Unable to communicate with server";
896 case valerie_unit_creation_failed
:
897 msg
= "Unit creation failed";
899 case valerie_unit_unavailable
:
900 msg
= "Unit unavailable";
902 case valerie_invalid_file
:
903 msg
= "Invalid file";
905 case valerie_invalid_position
:
906 msg
= "Invalid position";
912 /** Close the valerie structure.
915 void valerie_close( valerie
this )
919 valerie_set_last_response( this, NULL
);