2 * client.c -- Valerie client demo
3 * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
4 * Author: Charles Yates <charles.yates@pandora.be>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program 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
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 /* System header files */
26 /* Application header files */
30 /** Clip navigation enumeration.
40 /** Function prototype for menu handling.
43 typedef valerie_error_code (*demo_function
)( dv_demo
);
45 /** The menu structure.
54 demo_function function
;
58 *dv_demo_menu
, dv_demo_menu_t
;
60 /** Forward reference to menu runner.
63 extern valerie_error_code
dv_demo_run_menu( dv_demo
, dv_demo_menu
);
65 /** Foward references.
68 extern valerie_error_code
dv_demo_list_nodes( dv_demo
);
69 extern valerie_error_code
dv_demo_add_unit( dv_demo
);
70 extern valerie_error_code
dv_demo_select_unit( dv_demo
);
71 extern valerie_error_code
dv_demo_execute( dv_demo
);
72 extern valerie_error_code
dv_demo_load( dv_demo
);
73 extern valerie_error_code
dv_demo_transport( dv_demo
);
74 static void *dv_demo_status_thread( void * );
76 /** Connected menu definition.
79 dv_demo_menu_t connected_menu
=
83 { "Add Unit", dv_demo_add_unit
},
84 { "Select Unit", dv_demo_select_unit
},
85 { "Command Shell", dv_demo_execute
},
90 /** Initialise the demo structure.
93 dv_demo
dv_demo_init( valerie_parser parser
)
95 dv_demo
this = malloc( sizeof( dv_demo_t
) );
99 memset( this, 0, sizeof( dv_demo_t
) );
100 strcpy( this->last_directory
, "/" );
101 for ( index
= 0; index
< 4; index
++ )
103 this->queues
[ index
].unit
= index
;
104 this->queues
[ index
].position
= -1;
106 this->parser
= parser
;
111 /** Display a status record.
114 void dv_demo_show_status( dv_demo demo
, valerie_status status
)
116 if ( status
->unit
== demo
->selected_unit
&& demo
->showing
)
118 char temp
[ 1024 ] = "";
120 sprintf( temp
, "U%d ", demo
->selected_unit
);
122 switch( status
->status
)
125 strcat( temp
, "offline " );
128 strcat( temp
, "undefined " );
130 case unit_not_loaded
:
131 strcat( temp
, "unloaded " );
134 strcat( temp
, "stopped " );
137 strcat( temp
, "playing " );
140 strcat( temp
, "paused " );
142 case unit_disconnected
:
143 strcat( temp
, "disconnect" );
146 strcat( temp
, "unknown " );
150 sprintf( temp
+ strlen( temp
), " %9d %9d %9d ", status
->in
, status
->position
, status
->out
);
151 strcat( temp
, status
->clip
);
153 printf( "%-80.80s\r", temp
);
158 /** Determine action to carry out as dictated by the client unit queue.
161 void dv_demo_queue_action( dv_demo demo
, valerie_status status
)
163 dv_demo_queue queue
= &demo
->queues
[ status
->unit
];
165 /* SPECIAL CASE STATUS NOTIFICATIONS TO IGNORE */
167 /* When we've issued a LOAD on the previous notification, then ignore this one. */
174 if ( queue
->mode
&& status
->status
!= unit_offline
&& queue
->head
!= queue
->tail
)
176 if ( ( status
->position
>= status
->out
&& status
->speed
> 0 ) || status
->status
== unit_not_loaded
)
178 queue
->position
= ( queue
->position
+ 1 ) % 50;
179 if ( queue
->position
== queue
->tail
)
180 queue
->position
= queue
->head
;
181 valerie_unit_load( demo
->dv_status
, status
->unit
, queue
->list
[ queue
->position
] );
182 if ( status
->status
== unit_not_loaded
)
183 valerie_unit_play( demo
->dv
, queue
->unit
);
186 else if ( ( status
->position
<= status
->in
&& status
->speed
< 0 ) || status
->status
== unit_not_loaded
)
188 if ( queue
->position
== -1 )
189 queue
->position
= queue
->head
;
190 valerie_unit_load( demo
->dv_status
, status
->unit
, queue
->list
[ queue
->position
] );
191 if ( status
->status
== unit_not_loaded
)
192 valerie_unit_play( demo
->dv
, queue
->unit
);
193 queue
->position
= ( queue
->position
- 1 ) % 50;
202 static void *dv_demo_status_thread( void *arg
)
205 valerie_status_t status
;
206 valerie_notifier notifier
= valerie_get_notifier( demo
->dv_status
);
208 while ( !demo
->terminated
)
210 if ( valerie_notifier_wait( notifier
, &status
) != -1 )
212 dv_demo_queue_action( demo
, &status
);
213 dv_demo_show_status( demo
, &status
);
214 if ( status
.status
== unit_disconnected
)
215 demo
->disconnected
= 1;
222 /** Turn on/off status display.
225 void dv_demo_change_status( dv_demo demo
, int flag
)
227 if ( demo
->disconnected
&& flag
)
229 valerie_error_code error
= valerie_connect( demo
->dv
);
230 if ( error
== valerie_ok
)
231 demo
->disconnected
= 0;
238 valerie_status_t status
;
239 valerie_notifier notifier
= valerie_get_notifier( demo
->dv
);
240 valerie_notifier_get( notifier
, &status
, demo
->selected_unit
);
242 dv_demo_show_status( demo
, &status
);
247 printf( "%-80.80s\r", " " );
255 valerie_error_code
dv_demo_add_unit( dv_demo demo
)
257 valerie_error_code error
= valerie_ok
;
258 valerie_nodes nodes
= valerie_nodes_init( demo
->dv
);
259 valerie_units units
= valerie_units_init( demo
->dv
);
261 if ( valerie_nodes_count( nodes
) != -1 && valerie_units_count( units
) != -1 )
264 valerie_node_entry_t node
;
265 valerie_unit_entry_t unit
;
269 printf( "Select a Node\n\n" );
271 for ( node_index
= 0; node_index
< valerie_nodes_count( nodes
); node_index
++ )
273 valerie_nodes_get( nodes
, node_index
, &node
);
274 printf( "%d: %s - %s ", node_index
+ 1, node
.guid
, node
.name
);
275 for ( unit_index
= 0; unit_index
< valerie_units_count( units
); unit_index
++ )
277 valerie_units_get( units
, unit_index
, &unit
);
278 if ( !strcmp( unit
.guid
, node
.guid
) )
279 printf( "[U%d] ", unit
.unit
);
284 printf( "0. Exit\n\n" );
288 while ( ( pressed
= get_keypress( ) ) != '0' )
290 node_index
= pressed
- '1';
291 if ( node_index
>= 0 && node_index
< valerie_nodes_count( nodes
) )
294 printf( "%c\n\n", pressed
);
295 valerie_nodes_get( nodes
, node_index
, &node
);
296 if ( valerie_unit_add( demo
->dv
, node
.guid
, &unit
) == valerie_ok
)
298 printf( "Unit added as U%d\n", unit
);
299 demo
->selected_unit
= unit
;
304 valerie_response response
= valerie_get_last_response( demo
->dv
);
305 printf( "Failed to add unit:\n\n" );
306 for( index
= 1; index
< valerie_response_count( response
) - 1; index
++ )
307 printf( "%s\n", valerie_response_get_line( response
, index
) );
310 wait_for_any_key( NULL
);
321 printf( "Invalid response from the server.\n\n" );
322 wait_for_any_key( NULL
);
325 valerie_nodes_close( nodes
);
326 valerie_units_close( units
);
334 valerie_error_code
dv_demo_select_unit( dv_demo demo
)
339 while ( !terminated
)
341 valerie_units units
= valerie_units_init( demo
->dv
);
343 if ( valerie_units_count( units
) > 0 )
345 valerie_unit_entry_t unit
;
351 printf( "Select a Unit\n\n" );
353 for ( index
= 0; index
< valerie_units_count( units
); index
++ )
355 valerie_units_get( units
, index
, &unit
);
356 printf( "%d: U%d - %s [%s]\n", index
+ 1,
359 unit
.online ?
"online" : "offline" );
361 printf( "0: Exit\n\n" );
363 printf( "Unit [%d]: ", demo
->selected_unit
+ 1 );
367 key
= get_keypress( );
370 key
= demo
->selected_unit
+ '1';
374 if ( key
>= '1' && key
< '1' + valerie_units_count( units
) )
376 demo
->selected_unit
= key
- '1';
377 printf( "%c\n\n", key
);
378 dv_demo_load( demo
);
392 else if ( valerie_units_count( units
) == 0 )
394 printf( "No units added - add a unit first\n\n" );
395 dv_demo_add_unit( demo
);
399 printf( "Unable to obtain Unit List.\n" );
403 valerie_units_close( units
);
409 /** Execute an arbitrary command.
412 valerie_error_code
dv_demo_execute( dv_demo demo
)
414 valerie_error_code error
= valerie_ok
;
415 char command
[ 10240 ];
418 printf( "Miracle Shell\n" );
419 printf( "Enter an empty command to exit.\n\n" );
421 while ( !terminated
)
424 printf( "Command> " );
426 if ( chomp( io_get_string( command
, 10240, "" ) ) != NULL
)
428 if ( strcmp( command
, "" ) )
431 valerie_response response
= NULL
;
432 error
= valerie_execute( demo
->dv
, 10240, command
);
434 response
= valerie_get_last_response( demo
->dv
);
435 for ( index
= 0; index
< valerie_response_count( response
); index
++ )
437 char *line
= valerie_response_get_line( response
, index
);
438 printf( "%4d: %s\n", index
, line
);
451 /** Add a file to the queue.
454 valerie_error_code
dv_demo_queue_add( dv_demo demo
, dv_demo_queue queue
, char *file
)
456 valerie_status_t status
;
457 valerie_notifier notifier
= valerie_get_notifier( demo
->dv
);
459 if ( ( queue
->tail
+ 1 ) % 50 == queue
->head
)
460 queue
->head
= ( queue
->head
+ 1 ) % 50;
461 strcpy( queue
->list
[ queue
->tail
], file
);
462 queue
->tail
= ( queue
->tail
+ 1 ) % 50;
464 valerie_notifier_get( notifier
, &status
, queue
->unit
);
465 valerie_notifier_put( notifier
, &status
);
470 /** Basic queue maintenance and status reports.
473 valerie_error_code
dv_demo_queue_maintenance( dv_demo demo
, dv_demo_queue queue
)
475 printf( "Queue Maintenance for Unit %d\n\n", queue
->unit
);
480 printf( "Activate queueing? [Y] " );
481 ch
= get_keypress( );
482 if ( ch
== 'y' || ch
== 'Y' || ch
== '\r' )
490 int last_position
= -2;
494 while ( !terminated
)
496 int first
= ( queue
->position
+ 1 ) % 50;
499 if ( first
== queue
->tail
)
500 index
= first
= queue
->head
;
502 if ( queue
->head
== queue
->tail
)
504 if ( last_position
== -2 )
506 printf( "Queue is empty\n" );
508 printf( "0 = exit, t = turn off queueing\n\n" );
512 else if ( last_position
!= queue
->position
)
514 printf( "Order of play\n\n" );
518 printf( "%c%02d: %s\n", index
== first ?
'*' : ' ', index
, queue
->list
[ index
] + 1 );
519 index
= ( index
+ 1 ) % 50;
520 if ( index
== queue
->tail
)
523 while( index
!= first
);
526 printf( "0 = exit, t = turn off queueing, c = clear queue\n\n" );
527 last_position
= queue
->position
;
530 dv_demo_change_status( demo
, 1 );
532 switch( term_read( ) )
544 queue
->head
= queue
->tail
= 0;
545 queue
->position
= -1;
550 dv_demo_change_status( demo
, 0 );
559 /** Load a file to the selected unit. Horrible function - sorry :-/. Not a good
563 valerie_error_code
dv_demo_load( dv_demo demo
)
565 valerie_error_code error
= valerie_ok
;
570 strcpy( demo
->current_directory
, demo
->last_directory
);
574 while ( !terminated
)
576 valerie_dir dir
= valerie_dir_init( demo
->dv
, demo
->current_directory
);
578 if ( valerie_dir_count( dir
) == -1 )
580 printf( "Invalid directory - retrying %s\n", demo
->last_directory
);
581 valerie_dir_close( dir
);
582 dir
= valerie_dir_init( demo
->dv
, demo
->last_directory
);
583 if ( valerie_dir_count( dir
) == -1 )
585 printf( "Invalid directory - going back to /\n" );
586 valerie_dir_close( dir
);
587 dir
= valerie_dir_init( demo
->dv
, "/" );
588 strcpy( demo
->current_directory
, "/" );
592 strcpy( demo
->current_directory
, demo
->last_directory
);
596 terminated
= valerie_dir_count( dir
) == -1;
605 end
= valerie_dir_count( dir
);
607 strcpy( demo
->last_directory
, demo
->current_directory
);
609 while ( !selected
&& !terminated
)
611 valerie_dir_entry_t entry
;
616 char *action
= "Load & Play";
617 if ( demo
->queues
[ demo
->selected_unit
].mode
)
619 printf( "%s from %s\n\n", action
, demo
->current_directory
);
620 if ( strcmp( demo
->current_directory
, "/" ) )
621 printf( "-: Parent directory\n" );
622 for ( index
= start
; index
< end
&& ( index
- start
) < max
; index
++ )
624 valerie_dir_get( dir
, index
, &entry
);
625 printf( "%d: %s\n", index
- start
+ 1, entry
.name
);
627 while ( ( index
++ % 9 ) != 0 )
630 if ( start
+ max
< end
)
631 printf( "space = more files" );
632 else if ( end
> max
)
633 printf( "space = return to start of list" );
635 printf( ", b = previous files" );
637 printf( "0 = abort, t = transport, x = execute command, q = queue maintenance\n\n" );
641 dv_demo_change_status( demo
, 1 );
643 pressed
= term_read( );
652 refresh
= start
- max
>= 0;
657 refresh
= start
+ max
< end
;
662 else if ( end
> max
)
669 if ( strcmp( demo
->current_directory
, "/" ) )
672 ( *strrchr( demo
->current_directory
, '/' ) ) = '\0';
673 ( *( strrchr( demo
->current_directory
, '/' ) + 1 ) ) = '\0';
677 dv_demo_change_status( demo
, 0 );
679 dv_demo_transport( demo
);
684 dv_demo_change_status( demo
, 0 );
686 dv_demo_execute( demo
);
691 dv_demo_change_status( demo
, 0 );
693 dv_demo_queue_maintenance( demo
, &demo
->queues
[ demo
->selected_unit
] );
698 if ( pressed
>= '1' && pressed
<= '9' )
700 if ( ( start
+ pressed
- '1' ) < end
)
702 valerie_dir_get( dir
, start
+ pressed
- '1', &entry
);
704 strcat( demo
->current_directory
, entry
.name
);
710 dv_demo_change_status( demo
, 0 );
713 valerie_dir_close( dir
);
716 if ( !terminated
&& demo
->current_directory
[ strlen( demo
->current_directory
) - 1 ] != '/' )
718 if ( demo
->queues
[ demo
->selected_unit
].mode
== 0 )
720 error
= valerie_unit_load( demo
->dv
, demo
->selected_unit
, demo
->current_directory
);
721 valerie_unit_play( demo
->dv
, demo
->selected_unit
);
725 dv_demo_queue_add( demo
, &demo
->queues
[ demo
->selected_unit
], demo
->current_directory
);
726 printf( "File %s added to queue.\n", demo
->current_directory
);
728 strcpy( demo
->current_directory
, demo
->last_directory
);
743 /** Set the in point of the clip on the select unit.
746 valerie_error_code
dv_demo_set_in( dv_demo demo
)
749 valerie_status_t status
;
750 valerie_notifier notifier
= valerie_parser_get_notifier( demo
->parser
);
751 valerie_notifier_get( notifier
, &status
, demo
->selected_unit
);
752 position
= status
.position
;
753 return valerie_unit_set_in( demo
->dv
, demo
->selected_unit
, position
);
756 /** Set the out point of the clip on the selected unit.
759 valerie_error_code
dv_demo_set_out( dv_demo demo
)
762 valerie_status_t status
;
763 valerie_notifier notifier
= valerie_parser_get_notifier( demo
->parser
);
764 valerie_notifier_get( notifier
, &status
, demo
->selected_unit
);
765 position
= status
.position
;
766 return valerie_unit_set_out( demo
->dv
, demo
->selected_unit
, position
);
769 /** Clear the in and out points on the selected unit.
772 valerie_error_code
dv_demo_clear_in_out( dv_demo demo
)
774 return valerie_unit_clear_in_out( demo
->dv
, demo
->selected_unit
);
777 /** Goto a user specified frame on the selected unit.
780 valerie_error_code
dv_demo_goto( dv_demo demo
)
784 if ( get_int( &frame
, 0 ) )
785 return valerie_unit_goto( demo
->dv
, demo
->selected_unit
, frame
);
789 /** Manipulate playback on the selected unit.
792 valerie_error_code
dv_demo_transport( dv_demo demo
)
794 valerie_error_code error
= valerie_ok
;
797 valerie_status_t status
;
798 valerie_notifier notifier
= valerie_get_notifier( demo
->dv
);
800 while ( !terminated
)
804 printf( " +----+ +------+ +----+ +------+ +---+ +-----+ +------+ +-----+ +---+ \n" );
805 printf( " |1=-5| |2=-2.5| |3=-1| |4=-0.5| |5=1| |6=0.5| |7=1.25| |8=2.5| |9=5| \n" );
806 printf( " +----+ +------+ +----+ +------+ +---+ +-----+ +------+ +-----+ +---+ \n" );
808 printf( "+----------------------------------------------------------------------+\n" );
809 printf( "| 0 = quit, x = eXecute, 'space' = pause |\n" );
810 printf( "| g = goto a frame, q = queue maintenance |\n" );
811 printf( "| h = step -1, j = end of clip, k = start of clip, l = step 1 |\n" );
812 printf( "| eof handling: p = pause, r = repeat, t = terminate |\n" );
813 printf( "| i = set in point, o = set out point, c = clear in/out |\n" );
814 printf( "| u = use point settings, d = don't use point settings |\n" );
815 printf( "+----------------------------------------------------------------------+\n" );
821 dv_demo_change_status( demo
, 1 );
823 switch( term_read( ) )
831 error
= valerie_unit_pause( demo
->dv
, demo
->selected_unit
);
834 error
= valerie_unit_play_at_speed( demo
->dv
, demo
->selected_unit
, -5000 );
837 error
= valerie_unit_play_at_speed( demo
->dv
, demo
->selected_unit
, -2500 );
840 error
= valerie_unit_play_at_speed( demo
->dv
, demo
->selected_unit
, -1000 );
843 error
= valerie_unit_play_at_speed( demo
->dv
, demo
->selected_unit
, -500 );
846 error
= valerie_unit_play( demo
->dv
, demo
->selected_unit
);
849 error
= valerie_unit_play_at_speed( demo
->dv
, demo
->selected_unit
, 500 );
852 error
= valerie_unit_play_at_speed( demo
->dv
, demo
->selected_unit
, 1250 );
855 error
= valerie_unit_play_at_speed( demo
->dv
, demo
->selected_unit
, 2500 );
858 error
= valerie_unit_play_at_speed( demo
->dv
, demo
->selected_unit
, 5000 );
861 error
= valerie_unit_goto( demo
->dv
, demo
->selected_unit
, 0 );
864 error
= valerie_unit_step( demo
->dv
, demo
->selected_unit
, -1 );
867 valerie_notifier_get( notifier
, &status
, demo
->selected_unit
);
868 error
= valerie_unit_goto( demo
->dv
, demo
->selected_unit
, status
.tail_out
);
871 valerie_notifier_get( notifier
, &status
, demo
->selected_unit
);
872 error
= valerie_unit_goto( demo
->dv
, demo
->selected_unit
, status
.in
);
875 error
= valerie_unit_step( demo
->dv
, demo
->selected_unit
, 1 );
878 error
= valerie_unit_set( demo
->dv
, demo
->selected_unit
, "eof", "pause" );
881 error
= valerie_unit_set( demo
->dv
, demo
->selected_unit
, "eof", "loop" );
884 error
= valerie_unit_set( demo
->dv
, demo
->selected_unit
, "eof", "stop" );
887 error
= dv_demo_set_in( demo
);
890 error
= dv_demo_set_out( demo
);
893 dv_demo_change_status( demo
, 0 );
895 error
= dv_demo_goto( demo
);
899 error
= dv_demo_clear_in_out( demo
);
902 error
= valerie_unit_set( demo
->dv
, demo
->selected_unit
, "points", "use" );
905 error
= valerie_unit_set( demo
->dv
, demo
->selected_unit
, "points", "ignore" );
908 dv_demo_change_status( demo
, 0 );
910 dv_demo_execute( demo
);
914 dv_demo_change_status( demo
, 0 );
916 dv_demo_queue_maintenance( demo
, &demo
->queues
[ demo
->selected_unit
] );
921 dv_demo_change_status( demo
, 0 );
929 /** Recursive menu execution.
932 valerie_error_code
dv_demo_run_menu( dv_demo demo
, dv_demo_menu menu
)
934 char *items
= "123456789abcdefghijklmnopqrstuvwxyz";
935 int refresh_menu
= 1;
938 int item_selected
= 0;
947 printf( "%s\n\n", menu
->description
);
948 for ( index
= 0; menu
->array
[ index
].option
!= NULL
; index
++ )
949 printf( "%c: %s\n", items
[ index
], menu
->array
[ index
].option
);
950 printf( "0: Exit\n\n" );
951 printf( "Select Option: " );
956 key
= get_keypress( );
958 if ( demo
->disconnected
&& key
!= '0' )
960 valerie_error_code error
= valerie_connect( demo
->dv
);
961 if ( error
== valerie_ok
)
962 demo
->disconnected
= 0;
967 if ( !demo
->disconnected
|| key
== '0' )
969 item_selected
= strchr( items
, key
) - items
;
973 printf( "%c\n\n", key
);
976 else if ( item_selected
>= 0 && item_selected
< item_count
)
978 printf( "%c\n\n", key
);
979 menu
->array
[ item_selected
].function( demo
);
992 /** Entry point for main menu.
995 void dv_demo_run( dv_demo
this )
997 this->dv
= valerie_init( this->parser
);
998 this->dv_status
= valerie_init( this->parser
);
999 if ( valerie_connect( this->dv
) == valerie_ok
)
1001 pthread_create( &this->thread
, NULL
, dv_demo_status_thread
, this );
1002 dv_demo_run_menu( this, &connected_menu
);
1003 this->terminated
= 1;
1004 pthread_join( this->thread
, NULL
);
1005 this->terminated
= 0;
1009 printf( "Unable to connect." );
1010 wait_for_any_key( "" );
1013 valerie_close( this->dv_status
);
1014 valerie_close( this->dv
);
1016 printf( "Demo Exit.\n" );
1019 /** Close the demo structure.
1022 void dv_demo_close( dv_demo demo
)