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

Revision 1172, 18.2 kB (checked in by ppalmers, 16 years ago)

lay down the foundations for easy ALSA/Pulse support

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