root/trunk/libffado/tests/test-ffado.cpp

Revision 639, 19.9 kB (checked in by ppalmers, 14 years ago)

- Introduce a generic infrastructure for FFADODevices to present the clock sources they support and their state
- Implement this infrastructure for BeBoB devices
- Implement this infrastructure for ECHO Fireworks devices

Line 
1 /*
2  * Copyright (C) 2005-2007 by by Daniel Wagner
3  * Copyright (C) 2005-2007 by by Pieter Palmers
4  *
5  * This file is part of FFADO
6  * FFADO = Free Firewire (pro-)audio drivers for linux
7  *
8  * FFADO is based upon FreeBoB.
9  *
10  * FFADO is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  * FFADO 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.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with FFADO; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22  * MA 02111-1307 USA.
23  */
24
25 /*
26  * This version uses the CPP API
27  */
28
29 #include <config.h>
30
31 #include "libffado/ffado.h"
32
33 #include "debugmodule/debugmodule.h"
34 #include "fbtypes.h"
35 #include "devicemanager.h"
36 #include "ffadodevice.h"
37
38 #include <dbus-c++/dbus.h>
39 #include "controlserver.h"
40 #include "libcontrol/BasicElements.h"
41
42 #include <signal.h>
43
44 #include <argp.h>
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <string.h>
48
49 #include <vector>
50 #include <string>
51 #include <iostream>
52 #include <sstream>
53
54 #include <lo/lo.h>
55
56 using namespace std;
57
58 DECLARE_GLOBAL_DEBUG_MODULE;
59
60 // prototypes & stuff for listing the OSC space
61 void list_osc_paths(lo_server s, lo_address t, const char *path);
62 void list_osc_params(lo_server s, lo_address t, const char *path);
63 string osc_param_get_value(lo_server s, lo_address t, const char *path, const char *param);
64
65 vector<string> osc_paths;
66 vector<string> osc_params;
67 string osc_value;
68
69 int osc_path_response_handler(const char *path, const char *types, lo_arg **argv, int argc,
70     void *data, void *user_data);
71
72 int osc_param_response_handler(const char *path, const char *types, lo_arg **argv, int argc,
73     void *data, void *user_data);
74
75 int osc_data_response_handler(const char *path, const char *types, lo_arg **argv, int argc,
76     void *data, void *user_data);
77
78 void osc_error_handler(int num, const char *msg, const char *path);
79
80 // DBUS stuff
81 DBus::BusDispatcher dispatcher;
82
83 // signal handler
84 int run=1;
85 static void sighandler (int sig)
86 {
87     run = 0;
88     dispatcher.leave();
89 }
90
91 // global's
92 const char *argp_program_version = PACKAGE_STRING;
93 const char *argp_program_bug_address = PACKAGE_BUGREPORT;
94
95 // Program documentation.
96 static char doc[] = "FFADO -- a driver for Firewire Audio devices (test application)\n\n"
97                     "OPERATION: Discover\n"
98                     "           SetSamplerate samplerate\n"
99                     "           SetClockSource [id]\n"
100                     "           ListOscSpace\n"
101                     "           OscServer\n"
102                     "           DBus\n"
103                     ;
104
105 // A description of the arguments we accept.
106 static char args_doc[] = "OPERATION";
107
108 struct arguments
109 {
110     short silent;
111     short verbose;
112     int   port;
113     int   node_id;
114     int   node_id_set;
115     char* args[2];
116 };
117
118 // The options we understand.
119 static struct argp_option options[] = {
120     {"quiet",    'q',       0,    0,  "Don't produce any output" },
121     {"silent",   's',       0,    OPTION_ALIAS },
122
123     {"verbose",  'v', "level",    0,  "Produce verbose output" },
124
125
126     {"node",     'n',    "id",    0,  "Node to use" },
127     {"port",     'p',    "nr",    0,  "IEEE1394 Port to use" },
128     { 0 }
129 };
130
131 //-------------------------------------------------------------
132
133 // Parse a single option.
134 static error_t
135 parse_opt( int key, char* arg, struct argp_state* state )
136 {
137     // Get the input argument from `argp_parse', which we
138     // know is a pointer to our arguments structure.
139     struct arguments* arguments = ( struct arguments* ) state->input;
140     char* tail;
141
142     switch (key) {
143     case 'q': case 's':
144         arguments->silent = 1;
145         break;
146     case 'v':
147         if (arg) {
148             arguments->verbose = strtol( arg, &tail, 0 );
149             if ( errno ) {
150                 fprintf( stderr,  "Could not parse 'verbose' argument\n" );
151                 return ARGP_ERR_UNKNOWN;
152             }
153         }
154         break;
155     case 'p':
156         if (arg) {
157             arguments->port = strtol( arg, &tail, 0 );
158             if ( errno ) {
159                 fprintf( stderr,  "Could not parse 'port' argument\n" );
160                 return ARGP_ERR_UNKNOWN;
161             }
162         } else {
163             if ( errno ) {
164                 fprintf( stderr, "Could not parse 'port' argumen\n" );
165                 return ARGP_ERR_UNKNOWN;
166             }
167         }
168         break;
169     case 'n':
170         if (arg) {
171             arguments->node_id = strtol( arg, &tail, 0 );
172             if ( errno ) {
173                 fprintf( stderr,  "Could not parse 'node' argument\n" );
174                 return ARGP_ERR_UNKNOWN;
175             }
176             arguments->node_id_set=1;
177         } else {
178             if ( errno ) {
179                 fprintf( stderr, "Could not parse 'node' argumen\n" );
180                 return ARGP_ERR_UNKNOWN;
181             }
182         }
183         break;
184     case ARGP_KEY_ARG:
185         if (state->arg_num >= 3) {
186             // Too many arguments.
187             argp_usage( state );
188         }
189         arguments->args[state->arg_num] = arg;
190         break;
191     case ARGP_KEY_END:
192         if (state->arg_num < 1) {
193         // Not enough arguments.
194         argp_usage( state );
195         }
196         break;
197     default:
198         return ARGP_ERR_UNKNOWN;
199     }
200     return 0;
201 }
202
203 // Our argp parser.
204 static struct argp argp = { options, parse_opt, args_doc, doc };
205
206 int exitfunction( int retval ) {
207     debugOutput( DEBUG_LEVEL_NORMAL, "Debug output flushed...\n" );
208     flushDebugOutput();
209    
210     return retval;
211 }
212
213 int
214 main( int argc, char **argv )
215 {
216     struct arguments arguments;
217
218     // Default values.
219     arguments.silent      = 0;
220     arguments.verbose     = 0;
221     arguments.port        = 0;
222     arguments.node_id     = 0;
223     arguments.node_id_set = 0; // if we don't specify a node, discover all
224     arguments.args[0]     = "";
225     arguments.args[1]     = "";
226
227     setDebugLevel(arguments.verbose);
228
229     // Parse our arguments; every option seen by `parse_opt' will
230     // be reflected in `arguments'.
231     if ( argp_parse ( &argp, argc, argv, 0, 0, &arguments ) ) {
232         fprintf( stderr, "Could not parse command line\n" );
233         return exitfunction(-1);
234     }
235
236     printf("verbose level = %d\n", arguments.verbose);
237
238     printf( "Using ffado library version: %s\n\n", ffado_get_version() );
239
240     if ( strcmp( arguments.args[0], "Discover" ) == 0 ) {
241         DeviceManager *m_deviceManager = new DeviceManager();
242         if ( !m_deviceManager ) {
243             fprintf( stderr, "Could not allocate device manager\n" );
244             return exitfunction(-1);
245         }
246         if ( arguments.verbose ) {
247             m_deviceManager->setVerboseLevel(arguments.verbose);
248         }
249         if ( !m_deviceManager->initialize( arguments.port ) ) {
250             fprintf( stderr, "Could not initialize device manager\n" );
251             delete m_deviceManager;
252             return exitfunction(-1);
253         }
254         if ( arguments.verbose ) {
255             m_deviceManager->setVerboseLevel(arguments.verbose);
256         }
257         if ( !m_deviceManager->discover() ) {
258             fprintf( stderr, "Could not discover devices\n" );
259             delete m_deviceManager;
260             return exitfunction(-1);
261         }
262         delete m_deviceManager;
263         return exitfunction(0);
264     } else if ( strcmp( arguments.args[0], "SetSamplerate" ) == 0 ) {
265         char* tail;
266         int samplerate = strtol( arguments.args[1], &tail, 0 );
267         if ( errno ) {
268             fprintf( stderr,  "Could not parse samplerate argument\n" );
269             return exitfunction(-1);
270         }
271
272         DeviceManager *m_deviceManager = new DeviceManager();
273         if ( !m_deviceManager ) {
274             fprintf( stderr, "Could not allocate device manager\n" );
275             return exitfunction(-1);
276         }
277         if ( arguments.verbose ) {
278             m_deviceManager->setVerboseLevel(arguments.verbose);
279         }
280         if ( !m_deviceManager->initialize( arguments.port ) ) {
281             fprintf( stderr, "Could not initialize device manager\n" );
282             delete m_deviceManager;
283             return exitfunction(-1);
284         }
285         if ( arguments.verbose ) {
286             m_deviceManager->setVerboseLevel(arguments.verbose);
287         }
288         if ( !m_deviceManager->discover() ) {
289             fprintf( stderr, "Could not discover devices\n" );
290             delete m_deviceManager;
291             return exitfunction(-1);
292         }
293
294         if(arguments.node_id_set) {
295             FFADODevice* avDevice = m_deviceManager->getAvDevice( arguments.node_id );
296             if ( avDevice ) {
297                 avDevice->setVerboseLevel(arguments.verbose);
298                 if ( ! avDevice->setSamplingFrequency( samplerate ) ) {
299                     fprintf( stderr, "Could not set samplerate\n" );
300                 }
301             }
302         } else {
303             int i=0;
304
305             int devices_on_bus = m_deviceManager->getNbDevices();
306             printf("  port = %d, devices_on_bus = %d\n", arguments.port, devices_on_bus);
307
308             for(i=0;i<devices_on_bus;i++) {
309                 int node_id=m_deviceManager->getDeviceNodeId(i);
310                 printf("  set samplerate for device = %d, node = %d\n", i, node_id);
311                 FFADODevice* avDevice = m_deviceManager->getAvDevice( node_id );
312                 if ( avDevice ) {
313                     avDevice->setVerboseLevel(arguments.verbose);
314                     if ( !avDevice->setSamplingFrequency( samplerate ) ) {
315                         fprintf( stderr, "Could not set samplerate\n" );
316                     }
317                 }
318             }
319         }
320         delete m_deviceManager;
321         return exitfunction(0);
322     } else if ( strcmp( arguments.args[0], "SetClockSource" ) == 0 ) {
323         char* tail;
324         unsigned int targetid = (unsigned int)strtol( arguments.args[1], &tail, 0 );
325         if ( errno ) {
326             fprintf( stderr,  "Could not parse clock source argument\n" );
327             targetid=0xFFFF;
328         }
329         DeviceManager *m_deviceManager = new DeviceManager();
330         if ( !m_deviceManager ) {
331             fprintf( stderr, "Could not allocate device manager\n" );
332             return exitfunction(-1);
333         }
334         if ( arguments.verbose ) {
335             m_deviceManager->setVerboseLevel(arguments.verbose);
336         }
337         if ( !m_deviceManager->initialize( arguments.port ) ) {
338             fprintf( stderr, "Could not initialize device manager\n" );
339             delete m_deviceManager;
340             return exitfunction(-1);
341         }
342         if ( arguments.verbose ) {
343             m_deviceManager->setVerboseLevel(arguments.verbose);
344         }
345         if ( !m_deviceManager->discover() ) {
346             fprintf( stderr, "Could not discover devices\n" );
347             delete m_deviceManager;
348             return exitfunction(-1);
349         }
350
351         if(arguments.node_id_set) {
352             FFADODevice* avDevice = m_deviceManager->getAvDevice( arguments.node_id );
353             if ( avDevice ) {
354                 FFADODevice::ClockSource s;
355            
356                 avDevice->setVerboseLevel(arguments.verbose);
357                 FFADODevice::ClockSourceVector sources=avDevice->getSupportedClockSources();
358                 for ( FFADODevice::ClockSourceVector::const_iterator it
359                         = sources.begin();
360                     it != sources.end();
361                     ++it )
362                 {
363                     FFADODevice::ClockSource c=*it;
364                     printf( " Type: %s, Id: %d, Valid: %d, Active: %d, Description: %s\n",
365                         FFADODevice::ClockSourceTypeToString(c.type), c.id, c.valid, c.active, c.description.c_str());
366                    
367                     if (c.id==targetid) {
368                         s=*it;
369                     }
370                 }
371                
372                 if (s.type != FFADODevice::eCT_Invalid) {
373                     printf("  set clock source to %d\n", s.id);
374                     if ( ! avDevice->setActiveClockSource( s ) ) {
375                         fprintf( stderr, "Could not set clock source\n" );
376                     }
377                 } else {
378                     printf("  no clock source with id %d found\n", targetid);
379                 }
380             }
381         } else {
382             fprintf( stderr, "please specify a node\n" );
383         }
384         delete m_deviceManager;
385         return exitfunction(0);
386     } else if ( strcmp( arguments.args[0], "ListOscSpace" ) == 0 ) {
387         // list osc space by using OSC messages
388         // a server is assumed to be present
389
390         /* start a new server.
391         when sending a message from this context, the response
392         address will be set to this server's address.
393         */
394         lo_server s = lo_server_new(NULL, osc_error_handler);
395         lo_address t = lo_address_new(NULL, "17820");
396
397         list_osc_paths(s, t, "/");
398
399         lo_address_free(t);
400         lo_server_free(s);
401
402     } else if ( strcmp( arguments.args[0], "OscServer" ) == 0 ) {
403         DeviceManager *m_deviceManager = new DeviceManager();
404         if ( !m_deviceManager ) {
405             fprintf( stderr, "Could not allocate device manager\n" );
406             return exitfunction(-1);
407         }
408         if ( !m_deviceManager->initialize( arguments.port ) ) {
409             fprintf( stderr, "Could not initialize device manager\n" );
410             delete m_deviceManager;
411             return exitfunction(-1);
412         }
413         if ( arguments.verbose ) {
414             m_deviceManager->setVerboseLevel(arguments.verbose);
415         }
416         if ( !m_deviceManager->discover() ) {
417             fprintf( stderr, "Could not discover devices\n" );
418             delete m_deviceManager;
419             return exitfunction(-1);
420         }
421
422         printf("server started\n");
423         printf("press ctrl-c to stop it & continue\n");
424
425         signal (SIGINT, sighandler);
426
427         run=1;
428         while(run) {
429             sleep(1);
430             fflush(stdout);
431             fflush(stderr);
432         }
433         signal (SIGINT, SIG_DFL);
434
435         printf("server stopped\n");
436         delete m_deviceManager;
437         return exitfunction(0);
438     } else if ( strcmp( arguments.args[0], "DBus" ) == 0 ) {
439         DeviceManager *m_deviceManager = new DeviceManager();
440         if ( !m_deviceManager ) {
441             fprintf( stderr, "Could not allocate device manager\n" );
442             return exitfunction(-1);
443         }
444         if ( !m_deviceManager->initialize( arguments.port ) ) {
445             fprintf( stderr, "Could not initialize device manager\n" );
446             delete m_deviceManager;
447             return exitfunction(-1);
448         }
449         if ( arguments.verbose ) {
450             m_deviceManager->setVerboseLevel(arguments.verbose);
451         }
452         if ( !m_deviceManager->discover() ) {
453             fprintf( stderr, "Could not discover devices\n" );
454             delete m_deviceManager;
455             return exitfunction(-1);
456         }
457        
458         signal (SIGINT, sighandler);
459        
460         DBus::_init_threading();
461    
462         // test DBUS stuff
463         DBus::default_dispatcher = &dispatcher;
464    
465         DBus::Connection conn = DBus::Connection::SessionBus();
466         conn.request_name("org.ffado.Control");
467        
468         DBusControl::Container *container
469             = new DBusControl::Container(conn, "/org/ffado/Control/DeviceManager", *m_deviceManager);
470        
471         printf("DBUS test service running\n");
472         printf("press ctrl-c to stop it & continue\n");
473        
474         dispatcher.enter();
475    
476         delete container;
477
478         signal (SIGINT, SIG_DFL);
479
480         printf("server stopped\n");
481         delete m_deviceManager;
482         return exitfunction(0);
483     } else {
484         printf( "unknown operation\n" );
485     }
486
487 }
488
489 void list_osc_paths(lo_server s, lo_address t, const char *path) {
490     vector<string> my_paths;
491
492     printf("listing path: %s\n", path);
493
494     osc_paths.clear();
495     lo_server_add_method(s, "/response", NULL, osc_path_response_handler, NULL);
496
497     if (lo_send(t, path, "s", "list") == -1) {
498         printf(" OSC error %d: %s\n", lo_address_errno(t), lo_address_errstr(t));
499     }
500
501     if (lo_server_recv_noblock(s, 1000) == 0) {
502         printf("timeout\n");
503         return;
504     }
505
506     lo_server_del_method(s, "/response", NULL);
507
508     list_osc_params(s, t, path);
509
510     my_paths=osc_paths;
511     for ( vector<string>::iterator it = my_paths.begin();
512             it != my_paths.end();
513             ++it )
514     {
515         string new_path=string(path) + *it;
516         new_path += string("/");
517         list_osc_paths(s, t, new_path.c_str());
518     }
519
520 }
521
522 void list_osc_params(lo_server s, lo_address t, const char *path) {
523     vector<string> my_paths;
524     printf("params for: %s\n", path);
525
526     osc_params.clear();
527     lo_server_add_method(s, "/response", NULL, osc_param_response_handler, NULL);
528
529     if (lo_send(t, path, "s", "params") == -1) {
530         printf(" OSC error %d: %s\n", lo_address_errno(t), lo_address_errstr(t));
531     }
532
533     if (lo_server_recv_noblock(s, 1000) == 0) {
534         printf("timeout\n");
535         return;
536     }
537
538     lo_server_del_method(s, "/response", NULL);
539
540     vector<string> my_params=osc_params;
541
542     for ( vector<string>::iterator it = my_params.begin();
543             it != my_params.end();
544             ++it )
545     {
546         string value=osc_param_get_value(s, t, path, (*it).c_str());
547         printf("  %20s = %s\n", (*it).c_str(), value.c_str());
548     }
549
550 }
551
552 string osc_param_get_value(lo_server s, lo_address t, const char *path, const char *param) {
553     lo_server_add_method(s, "/response", NULL, osc_data_response_handler, NULL);
554
555     if (lo_send(t, path, "ss", "get", param) == -1) {
556         printf(" OSC error %d: %s\n", lo_address_errno(t), lo_address_errstr(t));
557     }
558
559     if (lo_server_recv_noblock(s, 1000) == 0) {
560         return string("timeout");
561     }
562
563     lo_server_del_method(s, "/response", NULL);
564     return osc_value;
565 }
566
567 void osc_error_handler(int num, const char *msg, const char *path)
568 {
569     printf("liblo server error %d in path %s: %s\n", num, path, msg);
570 }
571
572 int osc_path_response_handler(const char *path, const char *types, lo_arg **argv, int argc,
573         void *data, void *user_data)
574 {
575     for (int i=0; i< argc;i++) {
576         switch (lo_type(types[i])) {
577             /** Standard C, NULL terminated string. */
578             case LO_STRING:
579                 osc_paths.push_back(string(&(argv[i]->s)));
580                 break;
581             default:
582                 printf("unexpected data type in response message\n");
583         }
584     }
585     return 1;
586 }
587
588 int osc_param_response_handler(const char *path, const char *types, lo_arg **argv, int argc,
589         void *data, void *user_data)
590 {
591     for (int i=0; i< argc;i++) {
592         switch (lo_type(types[i])) {
593             /** Standard C, NULL terminated string. */
594             case LO_STRING:
595                 osc_params.push_back(string(&(argv[i]->s)));
596                 break;
597             default:
598                 printf("unexpected data type in response message\n");
599         }
600     }
601     return 1;
602 }
603
604 int osc_data_response_handler(const char *path, const char *types, lo_arg **argv, int argc,
605         void *data, void *user_data)
606 {
607     std::ostringstream str;
608
609     if(argc==1) {
610         switch (lo_type(types[0])) {
611             /* basic OSC types */
612             /** 32 bit signed integer. */
613             case LO_INT32:
614                 str << "0x" << std::hex << argv[0]->i;
615                 osc_value=str.str();
616                 break;
617             case LO_INT64:
618                 str << "0x" << std::hex << argv[0]->h;
619                 osc_value=str.str();
620                 break;
621             /** 32 bit IEEE-754 float. */
622             case LO_FLOAT:
623                 str << argv[0]->f;
624                 osc_value=str.str();
625                 break;
626             /** Standard C, NULL terminated string. */
627             case LO_STRING:
628                 osc_value=string(&argv[0]->s);
629                 break;
630             default:
631                 osc_value="unsupported response datatype";
632         }
633     } else {
634         osc_value="invalid response";
635     }
636     return 1;
637 }
Note: See TracBrowser for help on using the browser.