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 )