root/branches/echoaudio/tests/test-ffado.cpp

Revision 500, 15.4 kB (checked in by ppalmers, 17 years ago)

- renamed the IAvDevice to FFADODevice since it's not a pure 'AvDevice?' anymore and it also isn't an interface anymore.

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 <signal.h>
39
40 #include <argp.h>
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <string.h>
44
45 #include <vector>
46 #include <string>
47 #include <iostream>
48 #include <sstream>
49
50 #include <lo/lo.h>
51
52 using namespace std;
53
54 DECLARE_GLOBAL_DEBUG_MODULE;
55
56 // prototypes & stuff for listing the OSC space
57 void list_osc_paths(lo_server s, lo_address t, const char *path);
58 void list_osc_params(lo_server s, lo_address t, const char *path);
59 string osc_param_get_value(lo_server s, lo_address t, const char *path, const char *param);
60
61 vector<string> osc_paths;
62 vector<string> osc_params;
63 string osc_value;
64
65 int osc_path_response_handler(const char *path, const char *types, lo_arg **argv, int argc,
66     void *data, void *user_data);
67
68 int osc_param_response_handler(const char *path, const char *types, lo_arg **argv, int argc,
69     void *data, void *user_data);
70
71 int osc_data_response_handler(const char *path, const char *types, lo_arg **argv, int argc,
72     void *data, void *user_data);
73
74 void osc_error_handler(int num, const char *msg, const char *path);
75
76 // signal handler
77 int run=1;
78 static void sighandler (int sig)
79 {
80     run = 0;
81 }
82
83 // global's
84 const char *argp_program_version = PACKAGE_STRING;
85 const char *argp_program_bug_address = PACKAGE_BUGREPORT;
86
87 // Program documentation.
88 static char doc[] = "FFADO -- a driver for Firewire Audio devices (test application)\n\n"
89                     "OPERATION: Discover\n"
90                     "           SetSamplerate\n"
91                     "           ListOscSpace\n"
92                     "           OscServer\n";
93
94 // A description of the arguments we accept.
95 static char args_doc[] = "OPERATION";
96
97 struct arguments
98 {
99     short silent;
100     short verbose;
101     int   port;
102     int   node_id;
103     int   node_id_set;
104     char* args[2];
105 };
106
107 // The options we understand.
108 static struct argp_option options[] = {
109     {"quiet",    'q',       0,    0,  "Don't produce any output" },
110     {"silent",   's',       0,    OPTION_ALIAS },
111
112     {"verbose",  'v', "level",    0,  "Produce verbose output" },
113
114
115     {"node",     'n',    "id",    0,  "Node to use" },
116     {"port",     'p',    "nr",    0,  "IEEE1394 Port to use" },
117     { 0 }
118 };
119
120 //-------------------------------------------------------------
121
122 // Parse a single option.
123 static error_t
124 parse_opt( int key, char* arg, struct argp_state* state )
125 {
126     // Get the input argument from `argp_parse', which we
127     // know is a pointer to our arguments structure.
128     struct arguments* arguments = ( struct arguments* ) state->input;
129     char* tail;
130
131     switch (key) {
132     case 'q': case 's':
133         arguments->silent = 1;
134         break;
135     case 'v':
136         if (arg) {
137             arguments->verbose = strtol( arg, &tail, 0 );
138             if ( errno ) {
139                 fprintf( stderr,  "Could not parse 'verbose' argument\n" );
140                 return ARGP_ERR_UNKNOWN;
141             }
142         }
143         break;
144     case 'p':
145         if (arg) {
146             arguments->port = strtol( arg, &tail, 0 );
147             if ( errno ) {
148                 fprintf( stderr,  "Could not parse 'port' argument\n" );
149                 return ARGP_ERR_UNKNOWN;
150             }
151         } else {
152             if ( errno ) {
153                 fprintf( stderr, "Could not parse 'port' argumen\n" );
154                 return ARGP_ERR_UNKNOWN;
155             }
156         }
157         break;
158     case 'n':
159         if (arg) {
160             arguments->node_id = strtol( arg, &tail, 0 );
161             if ( errno ) {
162                 fprintf( stderr,  "Could not parse 'node' argument\n" );
163                 return ARGP_ERR_UNKNOWN;
164             }
165             arguments->node_id_set=1;
166         } else {
167             if ( errno ) {
168                 fprintf( stderr, "Could not parse 'node' argumen\n" );
169                 return ARGP_ERR_UNKNOWN;
170             }
171         }
172         break;
173     case ARGP_KEY_ARG:
174         if (state->arg_num >= 2) {
175             // Too many arguments.
176             argp_usage( state );
177         }
178         arguments->args[state->arg_num] = arg;
179         break;
180     case ARGP_KEY_END:
181         if (state->arg_num < 1) {
182         // Not enough arguments.
183         argp_usage( state );
184         }
185         break;
186     default:
187         return ARGP_ERR_UNKNOWN;
188     }
189     return 0;
190 }
191
192 // Our argp parser.
193 static struct argp argp = { options, parse_opt, args_doc, doc };
194
195 int exitfunction( int retval ) {
196     debugOutput( DEBUG_LEVEL_NORMAL, "Debug output flushed...\n" );
197     flushDebugOutput();
198    
199     return retval;
200 }
201
202 int
203 main( int argc, char **argv )
204 {
205     struct arguments arguments;
206
207     // Default values.
208     arguments.silent      = 0;
209     arguments.verbose     = 0;
210     arguments.port        = 0;
211     arguments.node_id     = 0;
212     arguments.node_id_set = 0; // if we don't specify a node, discover all
213     arguments.args[0]     = "";
214     arguments.args[1]     = "";
215
216     setDebugLevel(arguments.verbose);
217
218     // Parse our arguments; every option seen by `parse_opt' will
219     // be reflected in `arguments'.
220     if ( argp_parse ( &argp, argc, argv, 0, 0, &arguments ) ) {
221         fprintf( stderr, "Could not parse command line\n" );
222         return exitfunction(-1);
223     }
224
225     printf("verbose level = %d\n", arguments.verbose);
226
227     printf( "Using ffado library version: %s\n\n", ffado_get_version() );
228
229     if ( strcmp( arguments.args[0], "Discover" ) == 0 ) {
230         DeviceManager *m_deviceManager = new DeviceManager();
231         if ( !m_deviceManager ) {
232             fprintf( stderr, "Could not allocate device manager\n" );
233             return exitfunction(-1);
234         }
235         if ( arguments.verbose ) {
236             m_deviceManager->setVerboseLevel(arguments.verbose);
237         }
238         if ( !m_deviceManager->initialize( arguments.port ) ) {
239             fprintf( stderr, "Could not initialize device manager\n" );
240             delete m_deviceManager;
241             return exitfunction(-1);
242         }
243         if ( arguments.verbose ) {
244             m_deviceManager->setVerboseLevel(arguments.verbose);
245         }
246         if ( !m_deviceManager->discover() ) {
247             fprintf( stderr, "Could not discover devices\n" );
248             delete m_deviceManager;
249             return exitfunction(-1);
250         }
251         delete m_deviceManager;
252         return exitfunction(0);
253     } else if ( strcmp( arguments.args[0], "SetSamplerate" ) == 0 ) {
254         char* tail;
255         int samplerate = strtol( arguments.args[1], &tail, 0 );
256         if ( errno ) {
257             fprintf( stderr,  "Could not parse samplerate argument\n" );
258             return exitfunction(-1);
259         }
260
261         DeviceManager *m_deviceManager = new DeviceManager();
262         if ( !m_deviceManager ) {
263             fprintf( stderr, "Could not allocate device manager\n" );
264             return exitfunction(-1);
265         }
266         if ( arguments.verbose ) {
267             m_deviceManager->setVerboseLevel(arguments.verbose);
268         }
269         if ( !m_deviceManager->initialize( arguments.port ) ) {
270             fprintf( stderr, "Could not initialize device manager\n" );
271             delete m_deviceManager;
272             return exitfunction(-1);
273         }
274         if ( arguments.verbose ) {
275             m_deviceManager->setVerboseLevel(arguments.verbose);
276         }
277         if ( !m_deviceManager->discover() ) {
278             fprintf( stderr, "Could not discover devices\n" );
279             delete m_deviceManager;
280             return exitfunction(-1);
281         }
282
283         if(arguments.node_id_set) {
284             FFADODevice* avDevice = m_deviceManager->getAvDevice( arguments.node_id );
285             if ( avDevice ) {
286                 if ( avDevice->setSamplingFrequency( parseSampleRate( samplerate ) ) ) {
287                     m_deviceManager->discover();
288                 } else {
289                     fprintf( stderr, "Could not set samplerate\n" );
290                 }
291             }
292         } else {
293             int i=0;
294
295             int devices_on_bus = m_deviceManager->getNbDevices();
296             printf("  port = %d, devices_on_bus = %d\n", arguments.port, devices_on_bus);
297
298             for(i=0;i<devices_on_bus;i++) {
299                 int node_id=m_deviceManager->getDeviceNodeId(i);
300                 printf("  set samplerate for device = %d, node = %d\n", i, node_id);
301                 FFADODevice* avDevice = m_deviceManager->getAvDevice( node_id );
302                 if ( avDevice ) {
303                     if ( !avDevice->setSamplingFrequency( parseSampleRate( samplerate ) ) ) {
304                         fprintf( stderr, "Could not set samplerate\n" );
305                     }
306                 }
307             }
308         }
309         delete m_deviceManager;
310         return exitfunction(0);
311     } else if ( strcmp( arguments.args[0], "ListOscSpace" ) == 0 ) {
312         // list osc space by using OSC messages
313         // a server is assumed to be present
314
315         /* start a new server.
316         when sending a message from this context, the response
317         address will be set to this server's address.
318         */
319         lo_server s = lo_server_new(NULL, osc_error_handler);
320         lo_address t = lo_address_new(NULL, "17820");
321
322         list_osc_paths(s, t, "/");
323
324         lo_address_free(t);
325         lo_server_free(s);
326
327     } else if ( strcmp( arguments.args[0], "OscServer" ) == 0 ) {
328         DeviceManager *m_deviceManager = new DeviceManager();
329         if ( !m_deviceManager ) {
330             fprintf( stderr, "Could not allocate device manager\n" );
331             return exitfunction(-1);
332         }
333         if ( !m_deviceManager->initialize( arguments.port ) ) {
334             fprintf( stderr, "Could not initialize device manager\n" );
335             delete m_deviceManager;
336             return exitfunction(-1);
337         }
338         if ( arguments.verbose ) {
339             m_deviceManager->setVerboseLevel(arguments.verbose);
340         }
341         if ( !m_deviceManager->discover() ) {
342             fprintf( stderr, "Could not discover devices\n" );
343             delete m_deviceManager;
344             return exitfunction(-1);
345         }
346
347         printf("server started\n");
348         printf("press ctrl-c to stop it & continue\n");
349
350         signal (SIGINT, sighandler);
351
352         run=1;
353         while(run) {
354             sleep(1);
355             fflush(stdout);
356             fflush(stderr);
357         }
358         signal (SIGINT, SIG_DFL);
359
360         printf("server stopped\n");
361         delete m_deviceManager;
362         return exitfunction(0);
363
364     } else {
365         printf( "unknown operation\n" );
366     }
367
368 }
369
370 void list_osc_paths(lo_server s, lo_address t, const char *path) {
371     vector<string> my_paths;
372
373     printf("listing path: %s\n", path);
374
375     osc_paths.clear();
376     lo_server_add_method(s, "/response", NULL, osc_path_response_handler, NULL);
377
378     if (lo_send(t, path, "s", "list") == -1) {
379         printf(" OSC error %d: %s\n", lo_address_errno(t), lo_address_errstr(t));
380     }
381
382     if (lo_server_recv_noblock(s, 1000) == 0) {
383         printf("timeout\n");
384         return;
385     }
386
387     lo_server_del_method(s, "/response", NULL);
388
389     list_osc_params(s, t, path);
390
391     my_paths=osc_paths;
392     for ( vector<string>::iterator it = my_paths.begin();
393             it != my_paths.end();
394             ++it )
395     {
396         string new_path=string(path) + *it;
397         new_path += string("/");
398         list_osc_paths(s, t, new_path.c_str());
399     }
400
401 }
402
403 void list_osc_params(lo_server s, lo_address t, const char *path) {
404     vector<string> my_paths;
405     printf("params for: %s\n", path);
406
407     osc_params.clear();
408     lo_server_add_method(s, "/response", NULL, osc_param_response_handler, NULL);
409
410     if (lo_send(t, path, "s", "params") == -1) {
411         printf(" OSC error %d: %s\n", lo_address_errno(t), lo_address_errstr(t));
412     }
413
414     if (lo_server_recv_noblock(s, 1000) == 0) {
415         printf("timeout\n");
416         return;
417     }
418
419     lo_server_del_method(s, "/response", NULL);
420
421     vector<string> my_params=osc_params;
422
423     for ( vector<string>::iterator it = my_params.begin();
424             it != my_params.end();
425             ++it )
426     {
427         string value=osc_param_get_value(s, t, path, (*it).c_str());
428         printf("  %20s = %s\n", (*it).c_str(), value.c_str());
429     }
430
431 }
432
433 string osc_param_get_value(lo_server s, lo_address t, const char *path, const char *param) {
434     lo_server_add_method(s, "/response", NULL, osc_data_response_handler, NULL);
435
436     if (lo_send(t, path, "ss", "get", param) == -1) {
437         printf(" OSC error %d: %s\n", lo_address_errno(t), lo_address_errstr(t));
438     }
439
440     if (lo_server_recv_noblock(s, 1000) == 0) {
441         return string("timeout");
442     }
443
444     lo_server_del_method(s, "/response", NULL);
445     return osc_value;
446 }
447
448 void osc_error_handler(int num, const char *msg, const char *path)
449 {
450     printf("liblo server error %d in path %s: %s\n", num, path, msg);
451 }
452
453 int osc_path_response_handler(const char *path, const char *types, lo_arg **argv, int argc,
454         void *data, void *user_data)
455 {
456     for (int i=0; i< argc;i++) {
457         switch (lo_type(types[i])) {
458             /** Standard C, NULL terminated string. */
459             case LO_STRING:
460                 osc_paths.push_back(string(&(argv[i]->s)));
461                 break;
462             default:
463                 printf("unexpected data type in response message\n");
464         }
465     }
466     return 1;
467 }
468
469 int osc_param_response_handler(const char *path, const char *types, lo_arg **argv, int argc,
470         void *data, void *user_data)
471 {
472     for (int i=0; i< argc;i++) {
473         switch (lo_type(types[i])) {
474             /** Standard C, NULL terminated string. */
475             case LO_STRING:
476                 osc_params.push_back(string(&(argv[i]->s)));
477                 break;
478             default:
479                 printf("unexpected data type in response message\n");
480         }
481     }
482     return 1;
483 }
484
485 int osc_data_response_handler(const char *path, const char *types, lo_arg **argv, int argc,
486         void *data, void *user_data)
487 {
488     std::ostringstream str;
489
490     if(argc==1) {
491         switch (lo_type(types[0])) {
492             /* basic OSC types */
493             /** 32 bit signed integer. */
494             case LO_INT32:
495                 str << "0x" << std::hex << argv[0]->i;
496                 osc_value=str.str();
497                 break;
498             case LO_INT64:
499                 str << "0x" << std::hex << argv[0]->h;
500                 osc_value=str.str();
501                 break;
502             /** 32 bit IEEE-754 float. */
503             case LO_FLOAT:
504                 str << argv[0]->f;
505                 osc_value=str.str();
506                 break;
507             /** Standard C, NULL terminated string. */
508             case LO_STRING:
509                 osc_value=string(&argv[0]->s);
510                 break;
511             default:
512                 osc_value="unsupported response datatype";
513         }
514     } else {
515         osc_value="invalid response";
516     }
517     return 1;
518 }
Note: See TracBrowser for help on using the browser.