root/trunk/libffado/tests/streaming/teststreaming3.cpp

Revision 794, 15.9 kB (checked in by ppalmers, 16 years ago)

add options to teststreaming3 (fix)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2  * Copyright (C) 2005-2007 by Pieter Palmers
3  *
4  * This file is part of FFADO
5  * FFADO = Free Firewire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB.
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24
25 /**
26  * Test application for the direct decode stream API
27  * for floating point use
28  */
29
30 #include "config.h"
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include <signal.h>
37 #include <sched.h>
38
39 #include "libffado/ffado.h"
40
41 #include "debugmodule/debugmodule.h"
42
43 #include <math.h>
44 #include <argp.h>
45
46 int run;
47
48 DECLARE_GLOBAL_DEBUG_MODULE;
49
50 // Program documentation.
51 // Program documentation.
52 static char doc[] = "FFADO -- a driver for Firewire Audio devices (streaming test application)\n\n"
53                     ;
54
55 // A description of the arguments we accept.
56 static char args_doc[] = "";
57
58 struct arguments
59 {
60     long int verbose;
61     long int test_tone;
62     long int test_tone_freq;
63     long int period;
64     long int slave_mode;
65     long int snoop_mode;
66     long int nb_buffers;
67     long int sample_rate;
68     long int rtprio;
69     char* args[2];
70    
71 };
72
73 // The options we understand.
74 static struct argp_option options[] = {
75     {"verbose",  'v', "level",    0,  "Verbose level" },
76     {"rtprio",  'P', "prio",  0,  "Realtime priority (0 = no RT scheduling)" },
77     {"test-tone",  't', "bool",  0,  "Output test sine" },
78     {"test-tone-freq",  'f', "hz",  0,  "Test sine frequency" },
79     {"samplerate",  'r', "hz",  0,  "Sample rate" },
80     {"period",  'p', "frames",  0,  "Period (buffer) size" },
81     {"nb_buffers",  'n', "nb",  0,  "Nb buffers (periods)" },
82     {"slave_mode",  's', "bool",  0,  "Run in slave mode" },
83     {"snoop_mode",  'S', "bool",  0,  "Run in snoop mode" },
84     { 0 }
85 };
86
87 //-------------------------------------------------------------
88
89 // Parse a single option.
90 static error_t
91 parse_opt( int key, char* arg, struct argp_state* state )
92 {
93     // Get the input argument from `argp_parse', which we
94     // know is a pointer to our arguments structure.
95     struct arguments* arguments = ( struct arguments* ) state->input;
96     char* tail;
97
98     switch (key) {
99     case 'v':
100         if (arg) {
101             arguments->verbose = strtol( arg, &tail, 0 );
102             if ( errno ) {
103                 fprintf( stderr,  "Could not parse 'verbose' argument\n" );
104                 return ARGP_ERR_UNKNOWN;
105             }
106         }
107         break;
108     case 'P':
109         if (arg) {
110             arguments->rtprio = strtol( arg, &tail, 0 );
111             if ( errno ) {
112                 fprintf( stderr,  "Could not parse 'rtprio' argument\n" );
113                 return ARGP_ERR_UNKNOWN;
114             }
115         }
116         break;
117     case 'p':
118         if (arg) {
119             arguments->period = strtol( arg, &tail, 0 );
120             if ( errno ) {
121                 fprintf( stderr,  "Could not parse 'period' argument\n" );
122                 return ARGP_ERR_UNKNOWN;
123             }
124         }
125         break;
126     case 'n':
127         if (arg) {
128             arguments->nb_buffers = strtol( arg, &tail, 0 );
129             if ( errno ) {
130                 fprintf( stderr,  "Could not parse 'nb_buffers' argument\n" );
131                 return ARGP_ERR_UNKNOWN;
132             }
133         }
134         break;
135     case 'r':
136         if (arg) {
137             arguments->sample_rate = strtol( arg, &tail, 0 );
138             if ( errno ) {
139                 fprintf( stderr,  "Could not parse 'samplerate' argument\n" );
140                 return ARGP_ERR_UNKNOWN;
141             }
142         }
143         break;
144     case 't':
145         if (arg) {
146             arguments->test_tone = strtol( arg, &tail, 0 );
147             if ( errno ) {
148                 fprintf( stderr,  "Could not parse 'test-tone' argument\n" );
149                 return ARGP_ERR_UNKNOWN;
150             }
151         }
152         break;
153     case 'f':
154         if (arg) {
155             arguments->test_tone_freq = strtol( arg, &tail, 0 );
156             if ( errno ) {
157                 fprintf( stderr,  "Could not parse 'test-tone-freq' argument\n" );
158                 return ARGP_ERR_UNKNOWN;
159             }
160         }
161         break;
162     case 's':
163         if (arg) {
164             arguments->slave_mode = strtol( arg, &tail, 0 );
165             if ( errno ) {
166                 fprintf( stderr,  "Could not parse 'slave_mode' argument\n" );
167                 return ARGP_ERR_UNKNOWN;
168             }
169         }
170         break;
171     case 'S':
172         if (arg) {
173             arguments->snoop_mode = strtol( arg, &tail, 0 );
174             if ( errno ) {
175                 fprintf( stderr,  "Could not parse 'snoop_mode' argument\n" );
176                 return ARGP_ERR_UNKNOWN;
177             }
178         }
179         break;
180     case ARGP_KEY_ARG:
181         break;
182     case ARGP_KEY_END:
183         break;
184     default:
185         return ARGP_ERR_UNKNOWN;
186     }
187     return 0;
188 }
189
190 // Our argp parser.
191 static struct argp argp = { options, parse_opt, args_doc, doc };
192
193 int set_realtime_priority(unsigned int prio)
194 {
195     debugOutput(DEBUG_LEVEL_NORMAL, "Setting thread prio to %u\n", prio);
196     if (prio > 0) {
197         struct sched_param schp;
198         /*
199         * set the process to realtime privs
200         */
201         memset(&schp, 0, sizeof(schp));
202         schp.sched_priority = prio;
203        
204         if (sched_setscheduler(0, SCHED_FIFO, &schp) != 0) {
205             perror("sched_setscheduler");
206             return -1;
207         }
208   } else {
209         struct sched_param schp;
210         /*
211         * set the process to realtime privs
212         */
213         memset(&schp, 0, sizeof(schp));
214         schp.sched_priority = 0;
215        
216         if (sched_setscheduler(0, SCHED_OTHER, &schp) != 0) {
217             perror("sched_setscheduler");
218             return -1;
219         }
220   }
221   return 0;
222 }
223
224 static void sighandler (int sig)
225 {
226     run = 0;
227     set_realtime_priority(0);
228 }
229
230 int main(int argc, char *argv[])
231 {
232
233     struct arguments arguments;
234
235     // Default values.
236     arguments.test_tone         = 0;
237     arguments.test_tone_freq    = 1000;
238     arguments.verbose           = 6;
239     arguments.period            = 1024;
240     arguments.slave_mode        = 0;
241     arguments.snoop_mode        = 0;
242     arguments.nb_buffers        = 3;
243     arguments.sample_rate       = 44100;
244     arguments.rtprio            = 0;
245    
246     // Parse our arguments; every option seen by `parse_opt' will
247     // be reflected in `arguments'.
248     if ( argp_parse ( &argp, argc, argv, 0, 0, &arguments ) ) {
249         debugError("Could not parse command line\n" );
250         return -1;
251     }
252
253     debugOutput(DEBUG_LEVEL_NORMAL, "verbose level = %d\n", arguments.verbose);
254     setDebugLevel(arguments.verbose);
255
256     int samplesread=0;
257 //     int sampleswritten=0;
258     int nb_in_channels=0, nb_out_channels=0;
259     int retval=0;
260     int i=0;
261     int start_flag = 0;
262
263     float frame_counter = 0.0;
264     float sine_advance = 0.0;
265     float amplitude = 0.97;
266    
267     int nb_periods=0;
268
269     int min_ch_count=0;
270
271     float **audiobuffers_in;
272     float **audiobuffers_out;
273     float *nullbuffer;
274    
275     run=1;
276
277     debugOutput(DEBUG_LEVEL_NORMAL, "FFADO streaming test application (3)\n");
278
279     signal (SIGINT, sighandler);
280     signal (SIGPIPE, sighandler);
281
282     ffado_device_info_t device_info;
283     memset(&device_info,0,sizeof(ffado_device_info_t));
284
285     ffado_options_t dev_options;
286     memset(&dev_options,0,sizeof(ffado_options_t));
287
288     dev_options.sample_rate = arguments.sample_rate;
289     dev_options.period_size = arguments.period;
290
291     dev_options.nb_buffers = arguments.nb_buffers;
292
293     dev_options.realtime = (arguments.rtprio != 0);
294     dev_options.packetizer_priority = arguments.rtprio + 1;
295    
296     dev_options.verbose = arguments.verbose;
297        
298     dev_options.slave_mode = arguments.slave_mode;
299     dev_options.snoop_mode = arguments.snoop_mode;
300    
301     sine_advance = 2.0*M_PI*arguments.test_tone_freq/((float)dev_options.sample_rate);
302
303     ffado_device_t *dev=ffado_streaming_init(device_info, dev_options);
304
305     if (!dev) {
306         debugError("Could not init Ffado Streaming layer\n");
307         exit(-1);
308     }
309
310     nb_in_channels = ffado_streaming_get_nb_capture_streams(dev);
311     nb_out_channels = ffado_streaming_get_nb_playback_streams(dev);
312
313     if (nb_in_channels < nb_out_channels) {
314         min_ch_count = nb_in_channels;
315     } else {
316         min_ch_count = nb_out_channels;
317     }
318    
319     /* allocate intermediate buffers */
320     audiobuffers_in = (float **)calloc(nb_in_channels, sizeof(float *));
321     for (i=0; i < nb_in_channels; i++) {
322         audiobuffers_in[i] = (float *)calloc(arguments.period+1, sizeof(float));
323            
324         switch (ffado_streaming_get_capture_stream_type(dev,i)) {
325             case ffado_stream_type_audio:
326                 /* assign the audiobuffer to the stream */
327                 ffado_streaming_set_capture_stream_buffer(dev, i, (char *)(audiobuffers_in[i]));
328                 ffado_streaming_set_capture_buffer_type(dev, i, ffado_buffer_type_float);
329                 ffado_streaming_capture_stream_onoff(dev, i, 1);
330                 break;
331                 // this is done with read/write routines because the nb of bytes can differ.
332             case ffado_stream_type_midi:
333             default:
334                 break;
335         }
336     }
337    
338     audiobuffers_out = (float **)calloc(nb_out_channels, sizeof(float));
339     for (i=0; i < nb_out_channels; i++) {
340         audiobuffers_out[i] = (float *)calloc(arguments.period+1, sizeof(float));
341            
342         switch (ffado_streaming_get_playback_stream_type(dev,i)) {
343             case ffado_stream_type_audio:
344                 /* assign the audiobuffer to the stream */
345                 ffado_streaming_set_playback_stream_buffer(dev, i, (char *)(audiobuffers_out[i]));
346                 ffado_streaming_set_playback_buffer_type(dev, i, ffado_buffer_type_float);
347                 ffado_streaming_playback_stream_onoff(dev, i, 1);
348                 break;
349                 // this is done with read/write routines because the nb of bytes can differ.
350             case ffado_stream_type_midi:
351             default:
352                 break;
353         }
354     }
355    
356     nullbuffer = (float *)calloc(arguments.period+1, sizeof(float));
357    
358    
359 //     /* open the files to write to*/
360 //     FILE* fid_in[nb_in_channels];
361 //     char name[256];
362 //
363 //     for (i=0;i<nb_in_channels;i++) {
364 //         snprintf(name,sizeof(name),"in_ch_%02d",i);
365 //         fid_in[i]=fopen(name,"w");
366 //
367 //         ffado_streaming_get_capture_stream_name(dev,i,name,sizeof(name));
368 //         fprintf(fid_in[i], "Channel name: %s\n",name);
369 //         switch (ffado_streaming_get_capture_stream_type(dev,i)) {
370 //         case ffado_stream_type_audio:
371 //             fprintf(fid_in[i], "Channel type: audio\n");
372 //             break;
373 //         case ffado_stream_type_midi:
374 //             fprintf(fid_in[i], "Channel type: midi\n");
375 //             break;
376 //         case ffado_stream_type_unknown:
377 //             fprintf(fid_in[i],"Channel type: unknown\n");
378 //             break;
379 //         default:
380 //         case ffado_stream_type_invalid:
381 //             fprintf(fid_in[i],"Channel type: invalid\n");
382 //             break;
383 //         }
384 //     }
385
386     // start the streaming layer
387     ffado_streaming_prepare(dev);
388     start_flag = ffado_streaming_start(dev);
389    
390     set_realtime_priority(arguments.rtprio);
391     debugOutput(DEBUG_LEVEL_NORMAL, "Entering receive loop (IN: %d, OUT: %d)\n", nb_in_channels, nb_out_channels);
392     while(run && start_flag==0) {
393         retval = ffado_streaming_wait(dev);
394         if (retval < 0) {
395             debugOutput(DEBUG_LEVEL_NORMAL, "Xrun\n");
396             ffado_streaming_reset(dev);
397             continue;
398         }
399        
400         ffado_streaming_transfer_capture_buffers(dev);
401        
402         if (arguments.test_tone) {
403             // generate the test tone
404             for (i=0; i<arguments.period; i++) {
405                 nullbuffer[i] = amplitude * sin(sine_advance * (frame_counter + (float)i));
406             }
407            
408             // copy the test tone to the audio buffers
409             for (i=0; i < nb_out_channels; i++) {
410                 if (ffado_streaming_get_playback_stream_type(dev,i) == ffado_stream_type_audio) {
411                     memcpy((char *)(audiobuffers_out[i]), (char *)(nullbuffer), sizeof(float) * arguments.period);
412                 }
413             }
414         } else {
415             for (i=0; i < min_ch_count; i++) {
416                 switch (ffado_streaming_get_capture_stream_type(dev,i)) {
417                     case ffado_stream_type_audio:
418                         // if both channels are audio channels, copy the buffers
419                         if (ffado_streaming_get_playback_stream_type(dev,i) == ffado_stream_type_audio) {
420                             memcpy((char *)(audiobuffers_out[i]), (char *)(audiobuffers_in[i]), sizeof(float) * arguments.period);
421                         }
422                         break;
423                         // this is done with read/write routines because the nb of bytes can differ.
424                     case ffado_stream_type_midi:
425                     default:
426                         break;
427                 }
428             }
429         }
430        
431         ffado_streaming_transfer_playback_buffers(dev);
432        
433         nb_periods++;
434         frame_counter += arguments.period;
435
436 //         if((nb_periods % 32)==0) {
437 // //             debugOutput(DEBUG_LEVEL_NORMAL, "\r%05d periods",nb_periods);
438 //         }
439
440 //         for(i=0;i<nb_in_channels;i++) {
441 //             
442 //             
443 //             switch (ffado_streaming_get_capture_stream_type(dev,i)) {
444 //             case ffado_stream_type_audio:
445 //                 // no need to get the buffers manually, we have set the API internal buffers to the audiobuffer[i]'s
446 // //                 //samplesread=freebob_streaming_read(dev, i, audiobuffer[i], arguments.period);
447 //                 samplesread=arguments.period;
448 //                 break;
449 //             case ffado_stream_type_midi:
450 //                 //samplesread=ffado_streaming_read(dev, i, audiobuffers_out[i], arguments.period);
451 //                 break;
452 //                         default: break;
453 //             }
454 //     
455 // //               fprintf(fid_in[i], "---- Period read  (%d samples) ----\n",samplesread);
456 // //               hexDumpToFile(fid_in[i],(unsigned char*)audiobuffers_in[i],samplesread*sizeof(float)+1);
457 //         }
458
459 //         for(i=0;i<nb_out_channels;i++) {
460 //             float *buff;
461 //             int sampleswritten=0;
462 //             if (i<nb_in_channels) {
463 //                 buff=audiobuffers_out[i];
464 //             } else {
465 //                 buff=nullbuffer;
466 //             }
467 //             
468 //             switch (ffado_streaming_get_playback_stream_type(dev,i)) {
469 //             case ffado_stream_type_audio:
470 // //                  sampleswritten=freebob_streaming_write(dev, i, buff, arguments.period);
471 //                 sampleswritten=arguments.period;
472 //                 break;
473 //             case ffado_stream_type_midi:
474 // //                 sampleswritten=freebob_streaming_write(dev, i, buff, arguments.period);
475 //                 break;
476 //                         default: break;
477 //             }
478 // //               fprintf(fid_out[i], "---- Period write (%d samples) ----\n",sampleswritten);
479 // //               hexDumpToFile(fid_out[i],(unsigned char*)buff,sampleswritten*sizeof(ffado_sample_t));
480 //         }
481     }
482
483     debugOutput(DEBUG_LEVEL_NORMAL, "Exiting receive loop\n");
484    
485     ffado_streaming_stop(dev);
486     ffado_streaming_finish(dev);
487
488 //     for (i=0;i<nb_in_channels;i++) {
489 //         fclose(fid_in[i]);
490 //     }
491    
492     for (i=0;i<nb_in_channels;i++) {
493         free(audiobuffers_in[i]);
494         free(audiobuffers_out[i]);
495     }
496     free(nullbuffer);
497     free(audiobuffers_in);
498     free(audiobuffers_out);
499
500   return EXIT_SUCCESS;
501 }
Note: See TracBrowser for help on using the browser.