]> git.sesse.net Git - mlt/blob - src/miracle/miracle_commands.c
8a492d1ae9e20b1845ed1c391a9abffeadde1970
[mlt] / src / miracle / miracle_commands.c
1 /*
2  * global_commands.c
3  * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
4  * Author: Dan Dennedy <dan@dennedy.org>
5  *
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.
10  *
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.
15  *
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.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/poll.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <dirent.h>
34 #include <pthread.h>
35
36 #include "dvunit.h"
37 #include "global_commands.h"
38 #include "raw1394util.h"
39 #include <libavc1394/rom1394.h>
40 #include "log.h"
41
42 static dv_unit g_units[MAX_UNITS];
43
44
45 /** Return the dv_unit given a numeric index.
46 */
47
48 dv_unit dv1394d_get_unit( int n )
49 {
50         if (n < MAX_UNITS)
51                 return g_units[n];
52         else
53                 return NULL;
54 }
55
56 /** Destroy the dv_unit given its numeric index.
57 */
58
59 void dv1394d_delete_unit( int n )
60 {
61         if (n < MAX_UNITS)
62         {
63                 dv_unit unit = dv1394d_get_unit(n);
64                 if (unit != NULL)
65                 {
66                         dv_unit_close( unit );
67                         g_units[ n ] = NULL;
68                         dv1394d_log( LOG_NOTICE, "Deleted unit U%d.", n ); 
69                 }
70         }
71 }
72
73 /** Destroy all allocated units on the server.
74 */
75
76 void dv1394d_delete_all_units( void )
77 {
78         int i;
79         for (i = 0; i < MAX_UNITS; i++)
80                 if ( dv1394d_get_unit(i) != NULL )
81                 {
82                         dv_unit_close( dv1394d_get_unit(i) );
83                         dv1394d_log( LOG_NOTICE, "Deleted unit U%d.", i ); 
84                 }
85 }
86
87 /** Add a DV virtual vtr to the server.
88 */
89 response_codes dv1394d_add_unit( command_argument cmd_arg )
90 {
91         int i;
92         int channel = -1;
93         char *guid_str = (char*) cmd_arg->argument;
94         octlet_t guid;
95         uint32_t guid_hi;
96         uint32_t guid_lo;
97         
98         sscanf( guid_str, "%08x%08x", &guid_hi, &guid_lo );
99         guid = (octlet_t)guid_hi << 32 | (octlet_t) guid_lo;
100
101         if ( dv_tokeniser_count( cmd_arg->tokeniser ) == 3 )
102                 channel = atoi( dv_tokeniser_get_string( cmd_arg->tokeniser, 2 ) );
103
104         /* make sure unit does not already exit */
105         for (i = 0; i < MAX_UNITS; i++)
106         {
107                 if (g_units[i] != NULL)
108                         if ( dv_unit_get_guid( g_units[i] ) == guid )
109                         {
110                                 dv_response_printf( cmd_arg->response, 1024, "a unit already exists for that node\n\n" );
111                                 return RESPONSE_ERROR;
112                         }
113         }
114         
115         for (i = 0; i < MAX_UNITS; i++)
116         {
117                 if (g_units[i] == NULL)
118                 {
119                 
120                         g_units[ i ] = dv_unit_init( guid, channel );
121                         if ( g_units[ i ] == NULL )
122                         {
123                                 dv_response_printf( cmd_arg->response, 1024, "failed to allocate unit\n" );
124                                 return RESPONSE_ERROR;
125                         }
126                         g_units[ i ]->unit = i;
127                         dv_unit_set_notifier( g_units[ i ], dv_parser_get_notifier( cmd_arg->parser ), cmd_arg->root_dir );
128
129                         dv1394d_log( LOG_NOTICE, "added unit %d to send to node %d over channel %d", 
130                                 i, dv_unit_get_nodeid( g_units[i] ), dv_unit_get_channel( g_units[i] ) );
131                         dv_response_printf( cmd_arg->response, 10, "U%1d\n\n", i );
132                         return RESPONSE_SUCCESS_N;
133                 }
134         }
135         
136         dv_response_printf( cmd_arg->response, 1024, "no more units can be created\n\n" );
137
138         return RESPONSE_ERROR;
139 }
140
141
142 /** List all AV/C nodes on the bus.
143 */
144 response_codes dv1394d_list_nodes( command_argument cmd_arg )
145 {
146         response_codes error = RESPONSE_SUCCESS_N;
147         raw1394handle_t handle;
148         int i, j;
149         char line[1024];
150         octlet_t guid;
151         rom1394_directory dir;
152
153         for ( j = 0; j < raw1394_get_num_ports(); j++ )
154         {
155                 handle = raw1394_open(j);
156                 for ( i = 0; i < raw1394_get_nodecount(handle); ++i )
157                 {
158                         rom1394_get_directory( handle, i, &dir);
159                         if ( (rom1394_get_node_type(&dir) == ROM1394_NODE_TYPE_AVC) )
160                         {
161                                 guid = rom1394_get_guid(handle, i);
162                                 if (dir.label != NULL)
163                                 {
164                                         snprintf( line, 1023, "%02d %08x%08x \"%s\"\n", i, 
165                                                 (quadlet_t) (guid>>32), (quadlet_t) (guid & 0xffffffff), dir.label );
166                                 } else {
167                                         snprintf( line, 1023, "%02d %08x%08x \"Unlabeled Node %d\"\n", i, 
168                                                 (quadlet_t) (guid>>32), (quadlet_t) (guid & 0xffffffff), i );
169                                 }
170                                 dv_response_write( cmd_arg->response, line, strlen(line) );
171                                 rom1394_free_directory( &dir);
172                         }
173                 }
174                 raw1394_close( handle );
175         }
176         dv_response_write( cmd_arg->response, "\n", 1 );
177         return error;
178 }
179
180
181 /** List units already added to server.
182 */
183 response_codes dv1394d_list_units( command_argument cmd_arg )
184 {
185         response_codes error = RESPONSE_SUCCESS_N;
186         char line[1024];
187         int i;
188         
189         for (i = 0; i < MAX_UNITS; i++)
190         {
191                 if (dv1394d_get_unit(i) != NULL)
192                 {
193                         snprintf( line, 1023, "U%d %02d %08x%08x %d\n", i, dv_unit_get_nodeid(g_units[i]),
194                         (quadlet_t) (dv_unit_get_guid(g_units[i]) >> 32), 
195                         (quadlet_t) (dv_unit_get_guid(g_units[i]) & 0xffffffff),
196                         !dv_unit_is_offline( g_units[i] ) );
197                         dv_response_write( cmd_arg->response, line, strlen(line) );
198                 }
199         }
200         dv_response_write( cmd_arg->response, "\n", 1 );
201
202         return error;
203 }
204
205 static int
206 filter_files( const struct dirent *de )
207 {
208         if ( de->d_name[ 0 ] != '.' )
209                 return 1;
210         else
211                 return 0;
212 }
213
214 /** List clips in a directory.
215 */
216 response_codes dv1394d_list_clips( command_argument cmd_arg )
217 {
218         response_codes error = RESPONSE_BAD_FILE;
219         const char *dir_name = (const char*) cmd_arg->argument;
220         DIR *dir;
221         char fullname[1024];
222         struct dirent **de = NULL;
223         int i, n;
224         
225         snprintf( fullname, 1023, "%s%s", cmd_arg->root_dir, dir_name );
226         dir = opendir( fullname );
227         if (dir != NULL)
228         {
229                 struct stat info;
230                 error = RESPONSE_SUCCESS_N;
231                 n = scandir( fullname, &de, filter_files, alphasort );
232                 for (i = 0; i < n; i++ )
233                 {
234                         snprintf( fullname, 1023, "%s%s/%s", cmd_arg->root_dir, dir_name, de[i]->d_name );
235                         if ( stat( fullname, &info ) == 0 && S_ISDIR( info.st_mode ) )
236                                 dv_response_printf( cmd_arg->response, 1024, "\"%s/\"\n", de[i]->d_name );
237                 }
238                 for (i = 0; i < n; i++ )
239                 {
240                         snprintf( fullname, 1023, "%s%s/%s", cmd_arg->root_dir, dir_name, de[i]->d_name );
241                         if ( lstat( fullname, &info ) == 0 && 
242                                  ( S_ISREG( info.st_mode ) || ( strstr( fullname, ".clip" ) && info.st_mode | S_IXUSR ) ) )
243                                 dv_response_printf( cmd_arg->response, 1024, "\"%s\" %llu\n", de[i]->d_name, (unsigned long long) info.st_size );
244                         free( de[ i ] );
245                 }
246                 free( de );
247                 closedir( dir );
248                 dv_response_write( cmd_arg->response, "\n", 1 );
249         }
250
251         return error;
252 }
253
254 /** Set a server configuration property.
255 */
256
257 response_codes dv1394d_set_global_property( command_argument cmd_arg )
258 {
259         char *key = (char*) cmd_arg->argument;
260         char *value = NULL;
261
262         value = strchr( key, '=' );
263         if (value == NULL)
264                 return RESPONSE_OUT_OF_RANGE;
265         *value = 0;
266         value++;
267         dv1394d_log( LOG_DEBUG, "SET %s = %s", key, value );
268
269         if ( strncasecmp( key, "root", 1024) == 0 )
270         {
271                 int len = strlen(value);
272                 int i;
273                 
274                 /* stop all units and unload clips */
275                 for (i = 0; i < MAX_UNITS; i++)
276                 {
277                         if (g_units[i] != NULL)
278                                 dv_unit_terminate( g_units[i] );
279                 }
280
281                 /* set the property */
282                 strncpy( cmd_arg->root_dir, value, 1023 );
283
284                 /* add a trailing slash if needed */
285                 if ( cmd_arg->root_dir[ len - 1 ] != '/')
286                 {
287                         cmd_arg->root_dir[ len ] = '/';
288                         cmd_arg->root_dir[ len + 1 ] = '\0';
289                 }
290         }
291         else
292                 return RESPONSE_OUT_OF_RANGE;
293         
294         return RESPONSE_SUCCESS;
295 }
296
297 /** Get a server configuration property.
298 */
299
300 response_codes dv1394d_get_global_property( command_argument cmd_arg )
301 {
302         char *key = (char*) cmd_arg->argument;
303
304         if ( strncasecmp( key, "root", 1024) == 0 )
305         {
306                 dv_response_write( cmd_arg->response, cmd_arg->root_dir, strlen(cmd_arg->root_dir) );
307                 return RESPONSE_SUCCESS_1;
308         }
309         else
310                 return RESPONSE_OUT_OF_RANGE;
311         
312         return RESPONSE_SUCCESS;
313 }
314
315 /** IEEE 1394 Bus Reset handler 
316
317     This is included here for now due to all the unit management involved.
318 */
319
320 static int reset_handler( raw1394handle_t h, unsigned int generation )
321 {
322         int i, j, count, retry = 3;
323         int port = (int) raw1394_get_userdata( h );
324         
325         raw1394_update_generation( h, generation );
326         dv1394d_log( LOG_NOTICE, "bus reset on port %d", port );
327
328         while ( retry-- > 0 ) 
329         {
330                 raw1394handle_t handle = raw1394_open( port );
331                 count = raw1394_get_nodecount( handle );
332                 
333                 if ( count > 0 )
334                 {
335                         dv1394d_log( LOG_DEBUG, "bus reset, checking units" );
336                         
337                         /* suspend all units on this port */
338                         for ( j = MAX_UNITS; j > 0; j-- )
339                         {
340                                 if ( g_units[ j-1 ] != NULL && dv_unit_get_port( g_units[ j-1 ] ) == port )
341                                         dv_unit_suspend( g_units[ j-1 ] );
342                         }
343                         dv1394d_log( LOG_DEBUG, "All units are now stopped" );
344                         
345                         /* restore units with known guid, take others offline */
346                         for ( j = 0; j < MAX_UNITS; j++ )
347                         {
348                                 if ( g_units[j] != NULL && 
349                                         ( dv_unit_get_port( g_units[ j ] ) == port || dv_unit_get_port( g_units[ j ] ) == -1 ) )
350                                 {
351                                         int found = 0;
352                                         for ( i = 0; i < count; i++ )
353                                         {
354                                                 octlet_t guid;
355                                                 dv1394d_log( LOG_DEBUG, "attempting to get guid for node %d", i );
356                                                 guid = rom1394_get_guid( handle, i );
357                                                 if ( guid == g_units[ j ]->guid )
358                                                 {
359                                                         dv1394d_log( LOG_NOTICE, "unit with GUID %08x%08x found", 
360                                                                 (quadlet_t) (g_units[j]->guid>>32), (quadlet_t) (g_units[j]->guid & 0xffffffff));
361                                                         if ( dv_unit_is_offline( g_units[ j ] ) )
362                                                                 dv_unit_online( g_units[ j ] );
363                                                         else
364                                                                 dv_unit_restore( g_units[ j ] );
365                                                         found = 1;
366                                                         break;
367                                                 }
368                                         }
369                                         if ( found == 0 )
370                                                 dv_unit_offline( g_units[ j ] );
371                                 }
372                         }
373                         dv1394d_log( LOG_DEBUG, "completed bus reset handler");
374                         raw1394_close( handle );
375                         return 0;
376                 }
377                 raw1394_close( handle );
378         }
379         dv1394d_log( LOG_CRIT, "raw1394 reported zero nodes on the bus!" );
380         return 0;
381 }
382
383
384 /** One pthread per IEEE 1394 port
385 */
386
387 static pthread_t raw1394service_thread[4];
388
389 /** One raw1394 handle for each pthread/port
390 */
391
392 static raw1394handle_t raw1394service_handle[4];
393
394 /** The service thread that polls raw1394 for new events.
395 */
396
397 static void* raw1394_service( void *arg )
398 {
399         raw1394handle_t handle = (raw1394handle_t) arg;
400         struct pollfd raw1394_poll;
401         raw1394_poll.fd = raw1394_get_fd( handle );
402         raw1394_poll.events = POLLIN;
403         raw1394_poll.revents = 0;
404         while ( 1 )
405         {
406                 if ( poll( &raw1394_poll, 1, 200) > 0 )
407                 {
408                         if ( (raw1394_poll.revents & POLLIN) 
409                                         || (raw1394_poll.revents & POLLPRI) )
410                                 raw1394_loop_iterate( handle );
411                 }
412                 pthread_testcancel();
413         }
414         
415 }
416
417
418 /** Start the raw1394 service threads for handling bus reset.
419
420     One thread is launched per port on the system.
421 */
422
423 void raw1394_start_service_threads( void )
424 {
425         int port;
426         for ( port = 0; port < raw1394_get_num_ports(); port++ )
427         {
428                 raw1394service_handle[port] = raw1394_open( port );
429                 raw1394_set_bus_reset_handler( raw1394service_handle[port], reset_handler );
430                 pthread_create( &(raw1394service_thread[port]), NULL, raw1394_service, raw1394service_handle[port] );
431         }
432         for ( ; port < 4; port++ )
433                 raw1394service_handle[port] = NULL;
434 }
435
436 /** Shutdown all the raw1394 service threads.
437 */
438
439 void raw1394_stop_service_threads( void )
440 {
441         int i;
442         for ( i = 0; i < 4; i++ )
443         {
444                 if ( raw1394service_handle[i] != NULL )
445                 {
446                         pthread_cancel( raw1394service_thread[i] );
447                         pthread_join( raw1394service_thread[i], NULL );
448                         raw1394_close( raw1394service_handle[i] );
449                 }
450         }
451 }
452
453