root/branches/api-cleanup/tests/streaming/teststreaming3.cpp

Revision 809, 16.9 kB (checked in by ppalmers, 16 years ago)

First round of cleanup:
- make Ports auto-register to a PortManager?
- remove the different 'signal' types, everything is now period-signaled.
- removed obsolete streaming test programs

  • 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;
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                 // note that using a float * buffer for midievents is a HACK
334                 ffado_streaming_set_capture_stream_buffer(dev, i, (char *)(audiobuffers_in[i]));
335                 ffado_streaming_set_capture_buffer_type(dev, i, ffado_buffer_type_midi);
336                 ffado_streaming_capture_stream_onoff(dev, i, 1);
337             default:
338                 break;
339         }
340     }
341
342     audiobuffers_out = (float **)calloc(nb_out_channels, sizeof(float));
343     for (i=0; i < nb_out_channels; i++) {
344         audiobuffers_out[i] = (float *)calloc(arguments.period+1, sizeof(float));
345
346         switch (ffado_streaming_get_playback_stream_type(dev,i)) {
347             case ffado_stream_type_audio:
348                 /* assign the audiobuffer to the stream */
349                 ffado_streaming_set_playback_stream_buffer(dev, i, (char *)(audiobuffers_out[i]));
350                 ffado_streaming_set_playback_buffer_type(dev, i, ffado_buffer_type_float);
351                 ffado_streaming_playback_stream_onoff(dev, i, 1);
352                 break;
353                 // this is done with read/write routines because the nb of bytes can differ.
354             case ffado_stream_type_midi:
355                 ffado_streaming_set_playback_buffer_type(dev, i, ffado_buffer_type_midi);
356                 ffado_streaming_playback_stream_onoff(dev, i, 0);
357             default:
358                 break;
359         }
360     }
361    
362     nullbuffer = (float *)calloc(arguments.period+1, sizeof(float));
363    
364    
365 //     /* open the files to write to*/
366 //     FILE* fid_in[nb_in_channels];
367 //     char name[256];
368 //
369 //     for (i=0;i<nb_in_channels;i++) {
370 //         snprintf(name,sizeof(name),"in_ch_%02d",i);
371 //         fid_in[i]=fopen(name,"w");
372 //
373 //         ffado_streaming_get_capture_stream_name(dev,i,name,sizeof(name));
374 //         fprintf(fid_in[i], "Channel name: %s\n",name);
375 //         switch (ffado_streaming_get_capture_stream_type(dev,i)) {
376 //         case ffado_stream_type_audio:
377 //             fprintf(fid_in[i], "Channel type: audio\n");
378 //             break;
379 //         case ffado_stream_type_midi:
380 //             fprintf(fid_in[i], "Channel type: midi\n");
381 //             break;
382 //         case ffado_stream_type_unknown:
383 //             fprintf(fid_in[i],"Channel type: unknown\n");
384 //             break;
385 //         default:
386 //         case ffado_stream_type_invalid:
387 //             fprintf(fid_in[i],"Channel type: invalid\n");
388 //             break;
389 //         }
390 //     }
391
392     // start the streaming layer
393     ffado_streaming_prepare(dev);
394     start_flag = ffado_streaming_start(dev);
395    
396     set_realtime_priority(arguments.rtprio);
397     debugOutput(DEBUG_LEVEL_NORMAL, "Entering receive loop (IN: %d, OUT: %d)\n", nb_in_channels, nb_out_channels);
398     while(run && start_flag==0) {
399         retval = ffado_streaming_wait(dev);
400         if (retval < 0) {
401             debugOutput(DEBUG_LEVEL_NORMAL, "Xrun\n");
402             ffado_streaming_reset(dev);
403             continue;
404         }
405        
406         ffado_streaming_transfer_capture_buffers(dev);
407        
408         if (arguments.test_tone) {
409             // generate the test tone
410             for (i=0; i<arguments.period; i++) {
411                 nullbuffer[i] = amplitude * sin(sine_advance * (frame_counter + (float)i));
412             }
413            
414             // copy the test tone to the audio buffers
415             for (i=0; i < nb_out_channels; i++) {
416                 if (ffado_streaming_get_playback_stream_type(dev,i) == ffado_stream_type_audio) {
417                     memcpy((char *)(audiobuffers_out[i]), (char *)(nullbuffer), sizeof(float) * arguments.period);
418                 }
419             }
420         } else {
421             uint32_t *midibuffer;
422             int idx;
423             for (i=0; i < min_ch_count; i++) {
424                 switch (ffado_streaming_get_capture_stream_type(dev,i)) {
425                     case ffado_stream_type_audio:
426                         // if both channels are audio channels, copy the buffers
427                         if (ffado_streaming_get_playback_stream_type(dev,i) == ffado_stream_type_audio) {
428                             memcpy((char *)(audiobuffers_out[i]), (char *)(audiobuffers_in[i]), sizeof(float) * arguments.period);
429                         }
430                         break;
431                         // this is done with read/write routines because the nb of bytes can differ.
432                     case ffado_stream_type_midi:
433                         midibuffer=(uint32_t *)audiobuffers_in[i];
434                         for(idx=0; idx < arguments.period; idx++) {
435                             uint32_t midievent = *(midibuffer + idx);
436                             if(midievent & 0xFF000000) {
437                                 debugOutput(DEBUG_LEVEL_NORMAL, " Received midi event %08X on idx %d of period %d\n",
438                                             midievent, idx, nb_periods);
439                             }
440                         }
441                     default:
442                         break;
443                 }
444             }
445         }
446        
447         ffado_streaming_transfer_playback_buffers(dev);
448        
449         nb_periods++;
450         frame_counter += arguments.period;
451
452 //         if((nb_periods % 32)==0) {
453 // //             debugOutput(DEBUG_LEVEL_NORMAL, "\r%05d periods",nb_periods);
454 //         }
455
456 //         for(i=0;i<nb_in_channels;i++) {
457 //             
458 //             
459 //             switch (ffado_streaming_get_capture_stream_type(dev,i)) {
460 //             case ffado_stream_type_audio:
461 //                 // no need to get the buffers manually, we have set the API internal buffers to the audiobuffer[i]'s
462 // //                 //samplesread=freebob_streaming_read(dev, i, audiobuffer[i], arguments.period);
463 //                 samplesread=arguments.period;
464 //                 break;
465 //             case ffado_stream_type_midi:
466 //                 //samplesread=ffado_streaming_read(dev, i, audiobuffers_out[i], arguments.period);
467 //                 break;
468 //                         default: break;
469 //             }
470 //     
471 // //               fprintf(fid_in[i], "---- Period read  (%d samples) ----\n",samplesread);
472 // //               hexDumpToFile(fid_in[i],(unsigned char*)audiobuffers_in[i],samplesread*sizeof(float)+1);
473 //         }
474
475 //         for(i=0;i<nb_out_channels;i++) {
476 //             float *buff;
477 //             int sampleswritten=0;
478 //             if (i<nb_in_channels) {
479 //                 buff=audiobuffers_out[i];
480 //             } else {
481 //                 buff=nullbuffer;
482 //             }
483 //             
484 //             switch (ffado_streaming_get_playback_stream_type(dev,i)) {
485 //             case ffado_stream_type_audio:
486 // //                  sampleswritten=freebob_streaming_write(dev, i, buff, arguments.period);
487 //                 sampleswritten=arguments.period;
488 //                 break;
489 //             case ffado_stream_type_midi:
490 // //                 sampleswritten=freebob_streaming_write(dev, i, buff, arguments.period);
491 //                 break;
492 //                         default: break;
493 //             }
494 // //               fprintf(fid_out[i], "---- Period write (%d samples) ----\n",sampleswritten);
495 // //               hexDumpToFile(fid_out[i],(unsigned char*)buff,sampleswritten*sizeof(ffado_sample_t));
496 //         }
497     }
498
499     debugOutput(DEBUG_LEVEL_NORMAL, "Exiting receive loop\n");
500    
501     ffado_streaming_stop(dev);
502     ffado_streaming_finish(dev);
503
504 //     for (i=0;i<nb_in_channels;i++) {
505 //         fclose(fid_in[i]);
506 //     }
507    
508     for (i=0;i<nb_in_channels;i++) {
509         free(audiobuffers_in[i]);
510         free(audiobuffers_out[i]);
511     }
512     free(nullbuffer);
513     free(audiobuffers_in);
514     free(audiobuffers_out);
515
516   return EXIT_SUCCESS;
517 }
Note: See TracBrowser for help on using the browser.