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

Revision 2802, 16.1 kB (checked in by jwoithe, 3 years ago)

Cosmetic: "Firewire" becomes "FireWire?".

Officially both the "F" and "W" were capitalised in the FireWire? name, so
reflect this throughout FFADO's source tree. This mostly affects comments.

This patch originated from pander on the ffado-devel mailing list. To
maintain consistency, the committed version has been expanded to include
files not originally included in the original patch.

  • 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 <stdint.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include <signal.h>
36 #include <sched.h>
37
38 #include "libffado/ffado.h"
39
40 #include "debugmodule/debugmodule.h"
41
42 #include <math.h>
43 #include <argp.h>
44
45 int run;
46
47 DECLARE_GLOBAL_DEBUG_MODULE;
48
49 // Program documentation.
50 // Program documentation.
51 static char doc[] = "FFADO -- a driver for FireWire Audio devices (streaming test application)\n\n"
52                     ;
53
54 // A description of the arguments we accept.
55 static char args_doc[] = "";
56
57 struct arguments
58 {
59     long int verbose;
60     long int test_tone;
61     long int test_tone_freq;
62     long int period;
63     long int slave_mode;
64     long int snoop_mode;
65     long int nb_buffers;
66     long int sample_rate;
67     long int rtprio;
68     long int audio_buffer_type;
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     {"audio_buffer_type",  'b', "",  0,  "Datatype of audio buffers (0=float, 1=int24)" },
85     { 0 }
86 };
87
88 //-------------------------------------------------------------
89
90 // Parse a single option.
91 static error_t
92 parse_opt( int key, char* arg, struct argp_state* state )
93 {
94     // Get the input argument from `argp_parse', which we
95     // know is a pointer to our arguments structure.
96     struct arguments* arguments = ( struct arguments* ) state->input;
97     char* tail;
98
99     errno = 0;
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 }
239
240 int main(int argc, char *argv[])
241 {
242
243     struct arguments arguments;
244
245     // Default values.
246     arguments.test_tone         = 0;
247     arguments.test_tone_freq    = 1000;
248     arguments.verbose           = 6;
249     arguments.period            = 1024;
250     arguments.slave_mode        = 0;
251     arguments.snoop_mode        = 0;
252     arguments.nb_buffers        = 3;
253     arguments.sample_rate       = 44100;
254     arguments.rtprio            = 0;
255     arguments.audio_buffer_type = 0;
256    
257     // Parse our arguments; every option seen by `parse_opt' will
258     // be reflected in `arguments'.
259     if ( argp_parse ( &argp, argc, argv, 0, 0, &arguments ) ) {
260         debugError("Could not parse command line\n" );
261         return -1;
262     }
263
264     debugOutput(DEBUG_LEVEL_NORMAL, "verbose level = %d\n", (int)arguments.verbose);
265     setDebugLevel(arguments.verbose);
266
267     int nb_in_channels=0, nb_out_channels=0;
268     int i=0;
269     int start_flag = 0;
270
271     float frame_counter = 0.0;
272     float sine_advance = 0.0;
273     float amplitude = 0.97;
274    
275     int nb_periods=0;
276
277     int min_ch_count=0;
278
279     float **audiobuffers_in;
280     float **audiobuffers_out;
281     float *nullbuffer;
282    
283     run=1;
284
285     debugOutput(DEBUG_LEVEL_NORMAL, "FFADO streaming test application (3)\n");
286
287     signal (SIGINT, sighandler);
288     signal (SIGPIPE, sighandler);
289
290     ffado_device_info_t device_info;
291     memset(&device_info,0,sizeof(ffado_device_info_t));
292
293     ffado_options_t dev_options;
294     memset(&dev_options,0,sizeof(ffado_options_t));
295
296     dev_options.sample_rate = arguments.sample_rate;
297     dev_options.period_size = arguments.period;
298
299     dev_options.nb_buffers = arguments.nb_buffers;
300
301     dev_options.realtime = (arguments.rtprio != 0);
302     dev_options.packetizer_priority = arguments.rtprio;
303    
304     dev_options.verbose = arguments.verbose;
305        
306     dev_options.slave_mode = arguments.slave_mode;
307     dev_options.snoop_mode = arguments.snoop_mode;
308    
309     sine_advance = 2.0*M_PI*arguments.test_tone_freq/((float)dev_options.sample_rate);
310
311     ffado_device_t *dev=ffado_streaming_init(device_info, dev_options);
312
313     if (!dev) {
314         debugError("Could not init Ffado Streaming layer\n");
315         exit(-1);
316     }
317     if (arguments.audio_buffer_type == 0) {
318         ffado_streaming_set_audio_datatype(dev, ffado_audio_datatype_float);
319     } else {
320         ffado_streaming_set_audio_datatype(dev, ffado_audio_datatype_int24);
321     }
322
323     nb_in_channels = ffado_streaming_get_nb_capture_streams(dev);
324     nb_out_channels = ffado_streaming_get_nb_playback_streams(dev);
325
326     if (nb_in_channels < nb_out_channels) {
327         min_ch_count = nb_in_channels;
328     } else {
329         min_ch_count = nb_out_channels;
330     }
331
332     /* allocate intermediate buffers */
333     audiobuffers_in = (float **)calloc(nb_in_channels, sizeof(float *));
334     for (i=0; i < nb_in_channels; i++) {
335         audiobuffers_in[i] = (float *)calloc(arguments.period+1, sizeof(float));
336
337         switch (ffado_streaming_get_capture_stream_type(dev,i)) {
338             case ffado_stream_type_audio:
339                 /* assign the audiobuffer to the stream */
340                 ffado_streaming_set_capture_stream_buffer(dev, i, (char *)(audiobuffers_in[i]));
341                 ffado_streaming_capture_stream_onoff(dev, i, 1);
342                 break;
343                 // this is done with read/write routines because the nb of bytes can differ.
344             case ffado_stream_type_midi:
345                 // note that using a float * buffer for midievents is a HACK
346                 ffado_streaming_set_capture_stream_buffer(dev, i, (char *)(audiobuffers_in[i]));
347                 ffado_streaming_capture_stream_onoff(dev, i, 1);
348             default:
349                 break;
350         }
351     }
352
353     audiobuffers_out = (float **)calloc(nb_out_channels, sizeof(float *));
354     for (i=0; i < nb_out_channels; i++) {
355         audiobuffers_out[i] = (float *)calloc(arguments.period+1, sizeof(float));
356
357         switch (ffado_streaming_get_playback_stream_type(dev,i)) {
358             case ffado_stream_type_audio:
359                 /* assign the audiobuffer to the stream */
360                 ffado_streaming_set_playback_stream_buffer(dev, i, (char *)(audiobuffers_out[i]));
361                 ffado_streaming_playback_stream_onoff(dev, i, 1);
362                 break;
363                 // this is done with read/write routines because the nb of bytes can differ.
364             case ffado_stream_type_midi:
365                 ffado_streaming_set_playback_stream_buffer(dev, i, (char *)(audiobuffers_out[i]));
366                 ffado_streaming_playback_stream_onoff(dev, i, 1);
367             default:
368                 break;
369         }
370     }
371    
372     nullbuffer = (float *)calloc(arguments.period+1, sizeof(float));
373    
374    
375 //     /* open the files to write to*/
376 //     FILE* fid_in[nb_in_channels];
377 //     char name[256];
378 //
379 //     for (i=0;i<nb_in_channels;i++) {
380 //         snprintf(name,sizeof(name),"in_ch_%02d",i);
381 //         fid_in[i]=fopen(name,"w");
382 //
383 //         ffado_streaming_get_capture_stream_name(dev,i,name,sizeof(name));
384 //         fprintf(fid_in[i], "Channel name: %s\n",name);
385 //         switch (ffado_streaming_get_capture_stream_type(dev,i)) {
386 //         case ffado_stream_type_audio:
387 //             fprintf(fid_in[i], "Channel type: audio\n");
388 //             break;
389 //         case ffado_stream_type_midi:
390 //             fprintf(fid_in[i], "Channel type: midi\n");
391 //             break;
392 //         case ffado_stream_type_unknown:
393 //             fprintf(fid_in[i],"Channel type: unknown\n");
394 //             break;
395 //         default:
396 //         case ffado_stream_type_invalid:
397 //             fprintf(fid_in[i],"Channel type: invalid\n");
398 //             break;
399 //         }
400 //     }
401
402     // start the streaming layer
403     if (ffado_streaming_prepare(dev)) {
404         debugFatal("Could not prepare streaming system\n");
405         ffado_streaming_finish(dev);
406         return -1;
407     }
408     start_flag = ffado_streaming_start(dev);
409    
410     set_realtime_priority(arguments.rtprio);
411     debugOutput(DEBUG_LEVEL_NORMAL, "Entering receive loop (IN: %d, OUT: %d)\n", nb_in_channels, nb_out_channels);
412     while(run && start_flag==0) {
413         ffado_wait_response response;
414         response = ffado_streaming_wait(dev);
415         if (response == ffado_wait_xrun) {
416             debugOutput(DEBUG_LEVEL_NORMAL, "Xrun\n");
417             ffado_streaming_reset(dev);
418             continue;
419         } else if (response == ffado_wait_error) {
420             debugError("fatal xrun\n");
421             break;
422         }
423         ffado_streaming_transfer_capture_buffers(dev);
424
425         if (arguments.test_tone) {
426             // generate the test tone
427             for (i=0; i<arguments.period; i++) {
428                 float v = amplitude * sin(sine_advance * (frame_counter + (float)i));
429                 if (arguments.audio_buffer_type == 0) {
430                     nullbuffer[i] = v;
431                 } else {
432                     v = (v * 2147483392.0);
433                     int32_t tmp = ((int) v);
434                     tmp = tmp >> 8;
435                     memcpy(&nullbuffer[i], &tmp, sizeof(float));
436                 }
437             }
438            
439             // copy the test tone to the audio buffers
440             for (i=0; i < nb_out_channels; i++) {
441                 if (ffado_streaming_get_playback_stream_type(dev,i) == ffado_stream_type_audio) {
442                     memcpy((char *)(audiobuffers_out[i]), (char *)(nullbuffer), sizeof(float) * arguments.period);
443                 }
444             }
445         } else {
446             uint32_t *midibuffer;
447             int idx;
448             for (i=0; i < min_ch_count; i++) {
449                 switch (ffado_streaming_get_capture_stream_type(dev,i)) {
450                     case ffado_stream_type_audio:
451                         // if both channels are audio channels, copy the buffers
452                         if (ffado_streaming_get_playback_stream_type(dev,i) == ffado_stream_type_audio) {
453                             memcpy((char *)(audiobuffers_out[i]), (char *)(audiobuffers_in[i]), sizeof(float) * arguments.period);
454                         }
455                         break;
456                         // this is done with read/write routines because the nb of bytes can differ.
457                     case ffado_stream_type_midi:
458                         midibuffer=(uint32_t *)audiobuffers_in[i];
459                         for(idx=0; idx < arguments.period; idx++) {
460                             uint32_t midievent = *(midibuffer + idx);
461                             if(midievent & 0xFF000000) {
462                                 debugOutput(DEBUG_LEVEL_NORMAL, " Received midi event %08X at idx %d of period %d on port %d\n",
463                                             midievent, idx, nb_periods, i);
464                             }
465                         }
466                     default:
467                         break;
468                 }
469             }
470             for (i=0; i < nb_out_channels; i++) {
471                 if (ffado_streaming_get_playback_stream_type(dev,i) == ffado_stream_type_midi) {
472                     uint32_t *midievent = (uint32_t *)audiobuffers_out[i];
473                     *midievent = 0x010000FF;
474                     break;
475                 }
476             }
477
478         }
479
480         ffado_streaming_transfer_playback_buffers(dev);
481
482         nb_periods++;
483         frame_counter += arguments.period;
484
485     }
486
487     debugOutput(DEBUG_LEVEL_NORMAL, "Exiting receive loop\n");
488    
489     ffado_streaming_stop(dev);
490     ffado_streaming_finish(dev);
491
492 //     for (i=0;i<nb_in_channels;i++) {
493 //         fclose(fid_in[i]);
494 //     }
495    
496     for (i=0;i<nb_in_channels;i++) {
497         free(audiobuffers_in[i]);
498         free(audiobuffers_out[i]);
499     }
500     free(nullbuffer);
501     free(audiobuffers_in);
502     free(audiobuffers_out);
503
504   return EXIT_SUCCESS;
505 }
Note: See TracBrowser for help on using the browser.