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

Revision 816, 18.0 kB (checked in by ppalmers, 14 years ago)

remove support for per-port datatypes. It's too much hassle and it doesn't add enough value.
It also prevents thorough performance optimizations, especially for larger channel counts (e.g. SSE based).

Audio ports are now either all float or all int24. This can be specified by the ffado_streaming_set_audio_datatype
API function before the streaming is prepared. Hence we can still support the direct conversion to the
clients datatype when demuxing the packets.

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