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

Revision 815, 18.6 kB (checked in by ppalmers, 13 years ago)

- AMDTP transmit port caching for better performance
- less debug output in critical path

  • 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     long int audio_buffer_type;
70     char* args[2];
71    
72 };
73
74 // The options we understand.
75 static struct argp_option options[] = {
76     {"verbose",  'v', "level",    0,  "Verbose level" },
77     {"rtprio",  'P', "prio",  0,  "Realtime priority (0 = no RT scheduling)" },
78     {"test-tone",  't', "bool",  0,  "Output test sine" },
79     {"test-tone-freq",  'f', "hz",  0,  "Test sine frequency" },
80     {"samplerate",  'r', "hz",  0,  "Sample rate" },
81     {"period",  'p', "frames",  0,  "Period (buffer) size" },
82     {"nb_buffers",  'n', "nb",  0,  "Nb buffers (periods)" },
83     {"slave_mode",  's', "bool",  0,  "Run in slave mode" },
84     {"snoop_mode",  'S', "bool",  0,  "Run in snoop mode" },
85     {"audio_buffer_type",  'b', "",  0,  "Datatype of audio buffers (0=float, 1=int24)" },
86     { 0 }
87 };
88
89 //-------------------------------------------------------------
90
91 // Parse a single option.
92 static error_t
93 parse_opt( int key, char* arg, struct argp_state* state )
94 {
95     // Get the input argument from `argp_parse', which we
96     // know is a pointer to our arguments structure.
97     struct arguments* arguments = ( struct arguments* ) state->input;
98     char* tail;
99
100     switch (key) {
101     case 'v':
102         if (arg) {
103             arguments->verbose = strtol( arg, &tail, 0 );
104             if ( errno ) {
105                 fprintf( stderr,  "Could not parse 'verbose' argument\n" );
106                 return ARGP_ERR_UNKNOWN;
107             }
108         }
109         break;
110     case 'P':
111         if (arg) {
112             arguments->rtprio = strtol( arg, &tail, 0 );
113             if ( errno ) {
114                 fprintf( stderr,  "Could not parse 'rtprio' argument\n" );
115                 return ARGP_ERR_UNKNOWN;
116             }
117         }
118         break;
119     case 'p':
120         if (arg) {
121             arguments->period = strtol( arg, &tail, 0 );
122             if ( errno ) {
123                 fprintf( stderr,  "Could not parse 'period' argument\n" );
124                 return ARGP_ERR_UNKNOWN;
125             }
126         }
127         break;
128     case 'n':
129         if (arg) {
130             arguments->nb_buffers = strtol( arg, &tail, 0 );
131             if ( errno ) {
132                 fprintf( stderr,  "Could not parse 'nb_buffers' argument\n" );
133                 return ARGP_ERR_UNKNOWN;
134             }
135         }
136         break;
137     case 'r':
138         if (arg) {
139             arguments->sample_rate = strtol( arg, &tail, 0 );
140             if ( errno ) {
141                 fprintf( stderr,  "Could not parse 'samplerate' argument\n" );
142                 return ARGP_ERR_UNKNOWN;
143             }
144         }
145         break;
146     case 't':
147         if (arg) {
148             arguments->test_tone = strtol( arg, &tail, 0 );
149             if ( errno ) {
150                 fprintf( stderr,  "Could not parse 'test-tone' argument\n" );
151                 return ARGP_ERR_UNKNOWN;
152             }
153         }
154         break;
155     case 'f':
156         if (arg) {
157             arguments->test_tone_freq = strtol( arg, &tail, 0 );
158             if ( errno ) {
159                 fprintf( stderr,  "Could not parse 'test-tone-freq' argument\n" );
160                 return ARGP_ERR_UNKNOWN;
161             }
162         }
163         break;
164     case 'b':
165         if (arg) {
166             arguments->audio_buffer_type = strtol( arg, &tail, 0 );
167             if ( errno ) {
168                 fprintf( stderr,  "Could not parse 'audio-buffer-type' argument\n" );
169                 return ARGP_ERR_UNKNOWN;
170             }
171         }
172         break;
173     case 's':
174         if (arg) {
175             arguments->slave_mode = strtol( arg, &tail, 0 );
176             if ( errno ) {
177                 fprintf( stderr,  "Could not parse 'slave_mode' argument\n" );
178                 return ARGP_ERR_UNKNOWN;
179             }
180         }
181         break;
182     case 'S':
183         if (arg) {
184             arguments->snoop_mode = strtol( arg, &tail, 0 );
185             if ( errno ) {
186                 fprintf( stderr,  "Could not parse 'snoop_mode' argument\n" );
187                 return ARGP_ERR_UNKNOWN;
188             }
189         }
190         break;
191     case ARGP_KEY_ARG:
192         break;
193     case ARGP_KEY_END:
194         break;
195     default:
196         return ARGP_ERR_UNKNOWN;
197     }
198     return 0;
199 }
200
201 // Our argp parser.
202 static struct argp argp = { options, parse_opt, args_doc, doc };
203
204 int set_realtime_priority(unsigned int prio)
205 {
206     debugOutput(DEBUG_LEVEL_NORMAL, "Setting thread prio to %u\n", prio);
207     if (prio > 0) {
208         struct sched_param schp;
209         /*
210         * set the process to realtime privs
211         */
212         memset(&schp, 0, sizeof(schp));
213         schp.sched_priority = prio;
214        
215         if (sched_setscheduler(0, SCHED_FIFO, &schp) != 0) {
216             perror("sched_setscheduler");
217             return -1;
218         }
219   } else {
220         struct sched_param schp;
221         /*
222         * set the process to realtime privs
223         */
224         memset(&schp, 0, sizeof(schp));
225         schp.sched_priority = 0;
226        
227         if (sched_setscheduler(0, SCHED_OTHER, &schp) != 0) {
228             perror("sched_setscheduler");
229             return -1;
230         }
231   }
232   return 0;
233 }
234
235 static void sighandler (int sig)
236 {
237     run = 0;
238     set_realtime_priority(0);
239 }
240
241 int main(int argc, char *argv[])
242 {
243
244     struct arguments arguments;
245
246     // Default values.
247     arguments.test_tone         = 0;
248     arguments.test_tone_freq    = 1000;
249     arguments.verbose           = 6;
250     arguments.period            = 1024;
251     arguments.slave_mode        = 0;
252     arguments.snoop_mode        = 0;
253     arguments.nb_buffers        = 3;
254     arguments.sample_rate       = 44100;
255     arguments.rtprio            = 0;
256     arguments.audio_buffer_type = 0;
257    
258     // Parse our arguments; every option seen by `parse_opt' will
259     // be reflected in `arguments'.
260     if ( argp_parse ( &argp, argc, argv, 0, 0, &arguments ) ) {
261         debugError("Could not parse command line\n" );
262         return -1;
263     }
264
265     debugOutput(DEBUG_LEVEL_NORMAL, "verbose level = %d\n", arguments.verbose);
266     setDebugLevel(arguments.verbose);
267
268     int nb_in_channels=0, nb_out_channels=0;
269     int retval=0;
270     int i=0;
271     int start_flag = 0;
272
273     float frame_counter = 0.0;
274     float sine_advance = 0.0;
275     float amplitude = 0.97;
276    
277     int nb_periods=0;
278
279     int min_ch_count=0;
280
281     float **audiobuffers_in;
282     float **audiobuffers_out;
283     float *nullbuffer;
284    
285     run=1;
286
287     debugOutput(DEBUG_LEVEL_NORMAL, "FFADO streaming test application (3)\n");
288
289     signal (SIGINT, sighandler);
290     signal (SIGPIPE, sighandler);
291
292     ffado_device_info_t device_info;
293     memset(&device_info,0,sizeof(ffado_device_info_t));
294
295     ffado_options_t dev_options;
296     memset(&dev_options,0,sizeof(ffado_options_t));
297
298     dev_options.sample_rate = arguments.sample_rate;
299     dev_options.period_size = arguments.period;
300
301     dev_options.nb_buffers = arguments.nb_buffers;
302
303     dev_options.realtime = (arguments.rtprio != 0);
304     dev_options.packetizer_priority = arguments.rtprio;
305    
306     dev_options.verbose = arguments.verbose;
307        
308     dev_options.slave_mode = arguments.slave_mode;
309     dev_options.snoop_mode = arguments.snoop_mode;
310    
311     sine_advance = 2.0*M_PI*arguments.test_tone_freq/((float)dev_options.sample_rate);
312
313     ffado_device_t *dev=ffado_streaming_init(device_info, dev_options);
314
315     if (!dev) {
316         debugError("Could not init Ffado Streaming layer\n");
317         exit(-1);
318     }
319
320     nb_in_channels = ffado_streaming_get_nb_capture_streams(dev);
321     nb_out_channels = ffado_streaming_get_nb_playback_streams(dev);
322
323     if (nb_in_channels < nb_out_channels) {
324         min_ch_count = nb_in_channels;
325     } else {
326         min_ch_count = nb_out_channels;
327     }
328    
329     /* allocate intermediate buffers */
330     audiobuffers_in = (float **)calloc(nb_in_channels, sizeof(float *));
331     for (i=0; i < nb_in_channels; i++) {
332         audiobuffers_in[i] = (float *)calloc(arguments.period+1, sizeof(float));
333
334         switch (ffado_streaming_get_capture_stream_type(dev,i)) {
335             case ffado_stream_type_audio:
336                 /* assign the audiobuffer to the stream */
337                 ffado_streaming_set_capture_stream_buffer(dev, i, (char *)(audiobuffers_in[i]));
338                 if (arguments.audio_buffer_type == 0) {
339                     ffado_streaming_set_capture_buffer_type(dev, i, ffado_buffer_type_float);
340                 } else {
341                     ffado_streaming_set_capture_buffer_type(dev, i, ffado_buffer_type_int24);
342                 }
343                 ffado_streaming_capture_stream_onoff(dev, i, 1);
344                 break;
345                 // this is done with read/write routines because the nb of bytes can differ.
346             case ffado_stream_type_midi:
347                 // note that using a float * buffer for midievents is a HACK
348                 ffado_streaming_set_capture_stream_buffer(dev, i, (char *)(audiobuffers_in[i]));
349                 ffado_streaming_set_capture_buffer_type(dev, i, ffado_buffer_type_midi);
350                 ffado_streaming_capture_stream_onoff(dev, i, 1);
351             default:
352                 break;
353         }
354     }
355
356     audiobuffers_out = (float **)calloc(nb_out_channels, sizeof(float));
357     for (i=0; i < nb_out_channels; i++) {
358         audiobuffers_out[i] = (float *)calloc(arguments.period+1, sizeof(float));
359
360         switch (ffado_streaming_get_playback_stream_type(dev,i)) {
361             case ffado_stream_type_audio:
362                 /* assign the audiobuffer to the stream */
363                 ffado_streaming_set_playback_stream_buffer(dev, i, (char *)(audiobuffers_out[i]));
364                 if (arguments.audio_buffer_type == 0) {
365                     ffado_streaming_set_playback_buffer_type(dev, i, ffado_buffer_type_float);
366                 } else {
367                     ffado_streaming_set_playback_buffer_type(dev, i, ffado_buffer_type_int24);
368                 }
369                 ffado_streaming_playback_stream_onoff(dev, i, 1);
370                 break;
371                 // this is done with read/write routines because the nb of bytes can differ.
372             case ffado_stream_type_midi:
373                 ffado_streaming_set_playback_buffer_type(dev, i, ffado_buffer_type_midi);
374                 ffado_streaming_set_playback_stream_buffer(dev, i, (char *)(audiobuffers_out[i]));
375                 ffado_streaming_playback_stream_onoff(dev, i, 1);
376             default:
377                 break;
378         }
379     }
380    
381     nullbuffer = (float *)calloc(arguments.period+1, sizeof(float));
382    
383    
384 //     /* open the files to write to*/
385 //     FILE* fid_in[nb_in_channels];
386 //     char name[256];
387 //
388 //     for (i=0;i<nb_in_channels;i++) {
389 //         snprintf(name,sizeof(name),"in_ch_%02d",i);
390 //         fid_in[i]=fopen(name,"w");
391 //
392 //         ffado_streaming_get_capture_stream_name(dev,i,name,sizeof(name));
393 //         fprintf(fid_in[i], "Channel name: %s\n",name);
394 //         switch (ffado_streaming_get_capture_stream_type(dev,i)) {
395 //         case ffado_stream_type_audio:
396 //             fprintf(fid_in[i], "Channel type: audio\n");
397 //             break;
398 //         case ffado_stream_type_midi:
399 //             fprintf(fid_in[i], "Channel type: midi\n");
400 //             break;
401 //         case ffado_stream_type_unknown:
402 //             fprintf(fid_in[i],"Channel type: unknown\n");
403 //             break;
404 //         default:
405 //         case ffado_stream_type_invalid:
406 //             fprintf(fid_in[i],"Channel type: invalid\n");
407 //             break;
408 //         }
409 //     }
410
411     // start the streaming layer
412     if (ffado_streaming_prepare(dev)) {
413         debugFatal("Could not prepare streaming system\n");
414         ffado_streaming_finish(dev);
415         return -1;
416     }
417     start_flag = ffado_streaming_start(dev);
418    
419     set_realtime_priority(arguments.rtprio);
420     debugOutput(DEBUG_LEVEL_NORMAL, "Entering receive loop (IN: %d, OUT: %d)\n", nb_in_channels, nb_out_channels);
421     while(run && start_flag==0) {
422         retval = ffado_streaming_wait(dev);
423         if (retval < 0) {
424             debugOutput(DEBUG_LEVEL_NORMAL, "Xrun\n");
425             ffado_streaming_reset(dev);
426             continue;
427         }
428        
429         ffado_streaming_transfer_capture_buffers(dev);
430        
431         if (arguments.test_tone) {
432             // generate the test tone
433             for (i=0; i<arguments.period; i++) {
434                 float v = amplitude * sin(sine_advance * (frame_counter + (float)i));
435                 if (arguments.audio_buffer_type == 0) {
436                     nullbuffer[i] = v;
437                 } else {
438                     v = (v * 2147483392.0);
439                     int32_t tmp = ((int) v);
440                     tmp = tmp >> 8;
441                     memcpy(&nullbuffer[i], &tmp, sizeof(float));
442                 }
443             }
444            
445             // copy the test tone to the audio buffers
446             for (i=0; i < nb_out_channels; i++) {
447                 if (ffado_streaming_get_playback_stream_type(dev,i) == ffado_stream_type_audio) {
448                     memcpy((char *)(audiobuffers_out[i]), (char *)(nullbuffer), sizeof(float) * arguments.period);
449                 }
450             }
451         } else {
452             uint32_t *midibuffer;
453             int idx;
454             for (i=0; i < min_ch_count; i++) {
455                 switch (ffado_streaming_get_capture_stream_type(dev,i)) {
456                     case ffado_stream_type_audio:
457                         // if both channels are audio channels, copy the buffers
458                         if (ffado_streaming_get_playback_stream_type(dev,i) == ffado_stream_type_audio) {
459                             memcpy((char *)(audiobuffers_out[i]), (char *)(audiobuffers_in[i]), sizeof(float) * arguments.period);
460                         }
461                         break;
462                         // this is done with read/write routines because the nb of bytes can differ.
463                     case ffado_stream_type_midi:
464                         midibuffer=(uint32_t *)audiobuffers_in[i];
465                         for(idx=0; idx < arguments.period; idx++) {
466                             uint32_t midievent = *(midibuffer + idx);
467                             if(midievent & 0xFF000000) {
468                                 debugOutput(DEBUG_LEVEL_NORMAL, " Received midi event %08X at idx %d of period %d on port %d\n",
469                                             midievent, idx, nb_periods, i);
470                             }
471                         }
472                     default:
473                         break;
474                 }
475             }
476             for (i=0; i < nb_out_channels; i++) {
477                 if (ffado_streaming_get_playback_stream_type(dev,i) == ffado_stream_type_midi) {
478                     uint32_t *midievent = (uint32_t *)audiobuffers_out[i];
479                     *midievent = 0x010000FF;
480                     break;
481                 }
482             }
483
484         }
485
486         ffado_streaming_transfer_playback_buffers(dev);
487
488         nb_periods++;
489         frame_counter += arguments.period;
490
491 //         if((nb_periods % 32)==0) {
492 // //             debugOutput(DEBUG_LEVEL_NORMAL, "\r%05d periods",nb_periods);
493 //         }
494
495 //         for(i=0;i<nb_in_channels;i++) {
496 //             
497 //             
498 //             switch (ffado_streaming_get_capture_stream_type(dev,i)) {
499 //             case ffado_stream_type_audio:
500 //                 // no need to get the buffers manually, we have set the API internal buffers to the audiobuffer[i]'s
501 // //                 //samplesread=freebob_streaming_read(dev, i, audiobuffer[i], arguments.period);
502 //                 samplesread=arguments.period;
503 //                 break;
504 //             case ffado_stream_type_midi:
505 //                 //samplesread=ffado_streaming_read(dev, i, audiobuffers_out[i], arguments.period);
506 //                 break;
507 //                         default: break;
508 //             }
509 //     
510 // //               fprintf(fid_in[i], "---- Period read  (%d samples) ----\n",samplesread);
511 // //               hexDumpToFile(fid_in[i],(unsigned char*)audiobuffers_in[i],samplesread*sizeof(float)+1);
512 //         }
513
514 //         for(i=0;i<nb_out_channels;i++) {
515 //             float *buff;
516 //             int sampleswritten=0;
517 //             if (i<nb_in_channels) {
518 //                 buff=audiobuffers_out[i];
519 //             } else {
520 //                 buff=nullbuffer;
521 //             }
522 //             
523 //             switch (ffado_streaming_get_playback_stream_type(dev,i)) {
524 //             case ffado_stream_type_audio:
525 // //                  sampleswritten=freebob_streaming_write(dev, i, buff, arguments.period);
526 //                 sampleswritten=arguments.period;
527 //                 break;
528 //             case ffado_stream_type_midi:
529 // //                 sampleswritten=freebob_streaming_write(dev, i, buff, arguments.period);
530 //                 break;
531 //                         default: break;
532 //             }
533 // //               fprintf(fid_out[i], "---- Period write (%d samples) ----\n",sampleswritten);
534 // //               hexDumpToFile(fid_out[i],(unsigned char*)buff,sampleswritten*sizeof(ffado_sample_t));
535 //         }
536     }
537
538     debugOutput(DEBUG_LEVEL_NORMAL, "Exiting receive loop\n");
539    
540     ffado_streaming_stop(dev);
541     ffado_streaming_finish(dev);
542
543 //     for (i=0;i<nb_in_channels;i++) {
544 //         fclose(fid_in[i]);
545 //     }
546    
547     for (i=0;i<nb_in_channels;i++) {
548         free(audiobuffers_in[i]);
549         free(audiobuffers_out[i]);
550     }
551     free(nullbuffer);
552     free(audiobuffers_in);
553     free(audiobuffers_out);
554
555   return EXIT_SUCCESS;
556 }
Note: See TracBrowser for help on using the browser.