root/trunk/libffado/support/alsa/alsa_plugin.cpp

Revision 1336, 20.3 kB (checked in by ppalmers, 16 years ago)

Bring trunk up to date with branches/libffado-2.0:

"""
svn merge -r 1254:1299 svn+ssh://ffadosvn@ffado.org/ffado/branches/libffado-2.0
svn merge -r 1301:1320 svn+ssh://ffadosvn@ffado.org/ffado/branches/libffado-2.0
svn merge -r 1322:1323 svn+ssh://ffadosvn@ffado.org/ffado/branches/libffado-2.0
svn merge -r 1329:HEAD svn+ssh://ffadosvn@ffado.org/ffado/branches/libffado-2.0
"""

Add getSupportedSamplingFrequencies() to DICE, RME and Metric Halo AvDevices?

Line 
1 /*
2  *  ALSA FireWire Plugin
3  *
4  *  Copyright (c) 2008 Pieter Palmers <pieter.palmers@ffado.org>
5  *
6  *   Based upon the JACK <-> ALSA plugin
7  *    Copyright (c) 2003 by Maarten de Boer <mdeboer@iua.upf.es>
8  *                  2005 Takashi Iwai <tiwai@suse.de>
9  *
10  *   This library is free software; you can redistribute it and/or modify
11  *   it under the terms of the GNU Lesser General Public License as
12  *   published by the Free Software Foundation; either version 2.1 of
13  *   the License, or (at your option) any later version.
14  *
15  *   This program is distributed in the hope that it will be useful,
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *   GNU Lesser General Public License for more details.
19  *
20  *   You should have received a copy of the GNU Lesser General Public
21  *   License along with this library; if not, write to the Free Software
22  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
23  *
24  */
25
26 #include <src/debugmodule/debugmodule.h>
27 DECLARE_GLOBAL_DEBUG_MODULE;
28
29 #include "libutil/IpcRingBuffer.h"
30 #include "libutil/SystemTimeSource.h"
31 using namespace Util;
32
33 extern "C" {
34
35 #include "version.h"
36
37 #include <byteswap.h>
38 #include <sys/shm.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
41
42 #include <inttypes.h>
43
44 #include <pthread.h>
45
46 #include <alsa/asoundlib.h>
47 #include <alsa/pcm_external.h>
48
49 #define FFADO_PLUGIN_VERSION "0.0.2"
50
51 #define PRINT_FUNCTION_ENTRY (printMessage("entering %s\n",__FUNCTION__))
52 // #define PRINT_FUNCTION_ENTRY
53
54 typedef struct {
55     snd_pcm_ioplug_t io;
56
57     int fd;
58     int activated;
59
60     unsigned int hw_ptr;
61     unsigned int channels;
62     snd_pcm_channel_area_t *areas;
63
64     snd_pcm_stream_t stream;
65
66     // thread for polling
67     pthread_t thread;
68
69     // IPC stuff
70     Util::IpcRingBuffer* buffer;
71
72     // options
73     long int verbose;
74     snd_pcm_uframes_t period;
75     long int nb_buffers;
76
77 } snd_pcm_ffado_t;
78
79 static int snd_pcm_ffado_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params) {
80     PRINT_FUNCTION_ENTRY;
81     snd_pcm_ffado_t *ffado = (snd_pcm_ffado_t *)io->private_data;
82
83     ffado->channels=0;
84     if (ffado->stream == SND_PCM_STREAM_PLAYBACK) {
85         // HACK
86         ffado->channels=2;
87     } else {
88         // HACK
89         ffado->channels=2;
90     }
91
92     return 0;
93 }
94
95 // static snd_pcm_sframes_t snd_pcm_ffado_write(snd_pcm_ioplug_t *io,
96 //                    const snd_pcm_channel_area_t *areas,
97 //                    snd_pcm_uframes_t offset,
98 //                    snd_pcm_uframes_t size)
99 // {
100 //     PRINT_FUNCTION_ENTRY;
101 //     snd_pcm_ffado_t *ffado = (snd_pcm_ffado_t *)io->private_data;
102 //     IpcRingBuffer::eResult res;
103 //     unsigned int i;
104 //
105 //     do {
106 //         uint32_t *audiobuffers_raw;
107 //         res = ffado->buffer->requestBlockForWrite((void**) &audiobuffers_raw); // pointer voodoo
108 //         if(res == IpcRingBuffer::eR_OK) {
109 //             memset(audiobuffers_raw, 0, ffado->channels * ffado->period * 4);
110 //             for (i = 0; i < ffado->channels; i++) {
111 //                 uint32_t *alsa_data_ptr = (uint32_t *)((char *)areas[i].addr + (areas[i].step * offset / 8));
112 //                 uint32_t *ffado_data_ptr = audiobuffers_raw + i*ffado->period;
113 //                 memcpy(ffado_data_ptr, alsa_data_ptr, ffado->period * 4);
114 //             }
115 //             // release the block
116 //             res = ffado->buffer->releaseBlockForWrite();
117 //             if(res != IpcRingBuffer::eR_OK) {
118 //                 debugOutput(DEBUG_LEVEL_NORMAL, "PBK: error committing memory block\n");
119 //                 break;
120 //             }
121 //         } else if(res != IpcRingBuffer::eR_Again) {
122 //             debugOutput(DEBUG_LEVEL_NORMAL, "PBK: error getting memory block\n");
123 //         }
124 //     } while (res == IpcRingBuffer::eR_Again);
125 //
126 //     ffado->hw_ptr += ffado->period;
127 //     ffado->hw_ptr %= io->buffer_size;
128 //
129 //     if(size != ffado->period) {
130 //         debugWarning("size %d, period %d, offset %d\n", size, ffado->period, offset);
131 //     } else {
132 //         debugOutput(DEBUG_LEVEL_NORMAL, "size %d, period %d, offset %d\n", size, ffado->period, offset);
133 //     }
134 //
135 //     if(res == IpcRingBuffer::eR_OK) {
136 //         return ffado->period;
137 //     } else {
138 //         debugOutput(DEBUG_LEVEL_NORMAL, "error happened\n");
139 //         return -1;
140 //     }
141 // }
142 //
143 // static snd_pcm_sframes_t snd_pcm_ffado_read(snd_pcm_ioplug_t *io,
144 //                   const snd_pcm_channel_area_t *areas,
145 //                   snd_pcm_uframes_t offset,
146 //                   snd_pcm_uframes_t size)
147 // {
148 //     PRINT_FUNCTION_ENTRY;
149 //     snd_pcm_ffado_t *ffado = (snd_pcm_ffado_t *)io->private_data;
150 //     IpcRingBuffer::eResult res;
151 //     unsigned int i;
152 //
153 //     do {
154 //         uint32_t *audiobuffers_raw;
155 //         res = ffado->buffer->requestBlockForRead((void**) &audiobuffers_raw); // pointer voodoo
156 //         if(res == IpcRingBuffer::eR_OK) {
157 //             for (i = 0; i < ffado->channels; i++) {
158 //                 uint32_t *alsa_data_ptr = (uint32_t *)((char *)areas[i].addr + (areas[i].step * offset / 8));
159 //                 uint32_t *ffado_data_ptr = audiobuffers_raw + i*ffado->period;
160 //                 memcpy(alsa_data_ptr, ffado_data_ptr, ffado->period * 4);
161 //             }
162 //             // release the block
163 //             res = ffado->buffer->releaseBlockForRead();
164 //             if(res != IpcRingBuffer::eR_OK) {
165 //                 debugOutput(DEBUG_LEVEL_NORMAL, "CAP: error committing memory block\n");
166 //                 break;
167 //             }
168 //         } else if(res != IpcRingBuffer::eR_Again) {
169 //             debugOutput(DEBUG_LEVEL_NORMAL, "CAP: error getting memory block\n");
170 //         }
171 //     } while (res == IpcRingBuffer::eR_Again);
172 //
173 //     ffado->hw_ptr += ffado->period;
174 //     ffado->hw_ptr %= io->buffer_size;
175 //
176 //     if(res == IpcRingBuffer::eR_OK) {
177 //         return ffado->period;
178 //     } else {
179 //         debugOutput(DEBUG_LEVEL_NORMAL, "error happened\n");
180 //         return -1;
181 //     }
182 // }
183
184 static int
185 snd_pcm_ffado_pollfunction(snd_pcm_ffado_t *ffado)
186 {
187
188 //      PRINT_FUNCTION_ENTRY;
189     static char buf[1];
190     snd_pcm_ioplug_t *io = &ffado->io;
191     const snd_pcm_channel_area_t *areas;
192
193     assert(ffado);
194     assert(ffado->buffer);
195
196     IpcRingBuffer::eResult res;
197     if (ffado->stream == SND_PCM_STREAM_PLAYBACK) {
198         debugOutput(DEBUG_LEVEL_VERBOSE, "PBK: wait\n");
199         res = ffado->buffer->waitForWrite();
200         debugOutput(DEBUG_LEVEL_VERBOSE, "PBK: done, fill: %d\n", ffado->buffer->getBufferFill());
201
202         if(res == IpcRingBuffer::eR_OK) {
203             do {
204                 uint32_t *audiobuffers_raw;
205                 res = ffado->buffer->requestBlockForWrite((void**) &audiobuffers_raw); // pointer voodoo
206                 if(res == IpcRingBuffer::eR_OK) {
207                     // we have the memory block, do the actual transfer
208                     // silence the block
209                     memset(audiobuffers_raw, 0, ffado->channels * ffado->period * 4);
210                     if(io->state == SND_PCM_STATE_RUNNING) {
211                         // get the data address the data comes from
212                         areas = snd_pcm_ioplug_mmap_areas(io);
213
214                         // create the list of areas where the data goes to
215                         unsigned int channel = 0;
216                         for (channel = 0; channel < ffado->channels; channel++) {
217                             uint32_t *target = (audiobuffers_raw + channel*ffado->period);
218                             ffado->areas[channel].addr = target;
219                             ffado->areas[channel].first = 0;
220                             ffado->areas[channel].step = 4*8; // FIXME: hardcoded sample size
221                         }
222                         snd_pcm_uframes_t xfer = 0;
223                         while (xfer < ffado->period) {
224                             snd_pcm_uframes_t frames = ffado->period - xfer;
225                             snd_pcm_uframes_t offset = ffado->hw_ptr;
226                             snd_pcm_uframes_t cont = io->buffer_size - offset;
227
228                             if (cont < frames)
229                                 frames = cont;
230
231                             for (channel = 0; channel < ffado->channels; channel++) {
232                                 snd_pcm_area_copy(&ffado->areas[channel], xfer, &areas[channel], offset, frames, io->format);
233                             }
234
235                             ffado->hw_ptr += frames;
236                             ffado->hw_ptr %= io->buffer_size;
237                             xfer += frames;
238                         }
239                     }
240                     // release the block
241                     res = ffado->buffer->releaseBlockForWrite();
242                     if(res != IpcRingBuffer::eR_OK) {
243                         debugOutput(DEBUG_LEVEL_NORMAL, "PBK: error committing memory block\n");
244                         break;
245                     }
246                 } else if(res != IpcRingBuffer::eR_Again) {
247                     debugOutput(DEBUG_LEVEL_NORMAL, "PBK: error getting memory block\n");
248                 }
249                 if (res == IpcRingBuffer::eR_Again) {
250                     debugWarning("Again\n");
251                 }
252             } while (res == IpcRingBuffer::eR_Again);
253         } else {
254             debugError("Error while waiting\n");
255         }
256     } else {
257         res = ffado->buffer->waitForRead();
258         if(res == IpcRingBuffer::eR_OK) {
259             do {
260                 uint32_t *audiobuffers_raw;
261                 res = ffado->buffer->requestBlockForRead((void**) &audiobuffers_raw); // pointer voodoo
262                 if(res == IpcRingBuffer::eR_OK) {
263                     // we have the memory block, do the actual transfer
264                     if(io->state == SND_PCM_STATE_RUNNING) {
265                         // get the data address the data goes to
266                         areas = snd_pcm_ioplug_mmap_areas(io);
267
268                         // create the list of areas where the data comes from
269                         unsigned int channel = 0;
270                         for (channel = 0; channel < io->channels; channel++) {
271                             ffado->areas[channel].addr = audiobuffers_raw + channel*ffado->period;
272                             ffado->areas[channel].first = 0;
273                             ffado->areas[channel].step = 4*8; // FIXME: hardcoded sample size
274                         }
275                         snd_pcm_uframes_t xfer = 0;
276                         while (xfer < ffado->period) {
277                             snd_pcm_uframes_t frames = ffado->period - xfer;
278                             snd_pcm_uframes_t offset = ffado->hw_ptr;
279                             snd_pcm_uframes_t cont = io->buffer_size - offset;
280
281                             if (cont < frames)
282                                 frames = cont;
283
284                             for (channel = 0; channel < io->channels; channel++) {
285                                 snd_pcm_area_copy(&areas[channel], offset, &ffado->areas[channel], xfer, frames, io->format);
286                             }
287
288                             ffado->hw_ptr += frames;
289                             ffado->hw_ptr %= io->buffer_size;
290                             xfer += frames;
291                         }
292                     }
293                     // release the block
294                     res = ffado->buffer->releaseBlockForRead();
295                     if(res != IpcRingBuffer::eR_OK) {
296                         debugOutput(DEBUG_LEVEL_NORMAL, "CAP: error committing memory block\n");
297                         break;
298                     }
299                 } else if(res != IpcRingBuffer::eR_Again) {
300                     debugOutput(DEBUG_LEVEL_NORMAL, "CAP: error getting memory block\n");
301                 }
302             } while (res == IpcRingBuffer::eR_Again);
303         } else {
304             debugError("Error while waiting\n");
305         }
306     }
307
308     write(ffado->fd, buf, 1); /* for polling */
309
310     if(res == IpcRingBuffer::eR_OK) {
311         return 0;
312     } else {
313         debugOutput(DEBUG_LEVEL_NORMAL, "error happened\n");
314         return -1;
315     }
316 }
317
318 // static int
319 // snd_pcm_ffado_pollfunction(snd_pcm_ffado_t *ffado)
320 // {
321 //     // wait for a period
322 //     IpcRingBuffer::eResult res;
323 //     if(ffado->stream == SND_PCM_STREAM_PLAYBACK) {
324 //         res = ffado->buffer->waitForWrite();
325 //     } else {
326 //         res = ffado->buffer->waitForRead();
327 //     }
328 //
329 //     if(res == IpcRingBuffer::eR_OK) {
330 //         char buf[1];
331 //         write(ffado->fd, buf, 1); /* for polling */
332 //         return 0;
333 //     } else {
334 //         return -1;
335 //     }
336 // }
337
338 static void * ffado_workthread(void *arg)
339 {
340     PRINT_FUNCTION_ENTRY;
341     snd_pcm_ffado_t *ffado = (snd_pcm_ffado_t *)arg;
342
343     int oldstate;
344
345     pthread_setcancelstate (PTHREAD_CANCEL_DEFERRED, &oldstate);
346
347     while (snd_pcm_ffado_pollfunction(ffado) == 0) {
348         pthread_testcancel();
349     }
350     return 0;
351 }
352
353 static int snd_pcm_ffado_poll_revents(snd_pcm_ioplug_t *io,
354                      struct pollfd *pfds, unsigned int nfds,
355                      unsigned short *revents)
356 {
357     static char buf[1];
358     PRINT_FUNCTION_ENTRY;
359     assert(pfds && nfds == 1 && revents);
360     read(pfds[0].fd, buf, 1);
361     *revents = pfds[0].revents;
362     return 0;
363 }
364
365 static void snd_pcm_ffado_free(snd_pcm_ffado_t *ffado)
366 {
367     PRINT_FUNCTION_ENTRY;
368     if (ffado) {
369         if (ffado->fd >= 0) close(ffado->fd);
370         if (ffado->io.poll_fd >= 0) close(ffado->io.poll_fd);
371         free(ffado->areas);
372         free(ffado);
373     }
374 }
375
376 static int snd_pcm_ffado_close(snd_pcm_ioplug_t *io)
377 {
378     PRINT_FUNCTION_ENTRY;
379     snd_pcm_ffado_t *ffado = (snd_pcm_ffado_t *)io->private_data;
380
381     // cleanup the SHM structures here
382     delete ffado->buffer;
383     ffado->buffer = NULL;
384
385     snd_pcm_ffado_free(ffado);
386     return 0;
387 }
388
389 static snd_pcm_sframes_t snd_pcm_ffado_pointer(snd_pcm_ioplug_t *io)
390 {
391     PRINT_FUNCTION_ENTRY;
392     snd_pcm_ffado_t *ffado = (snd_pcm_ffado_t *)io->private_data;
393     return ffado->hw_ptr;
394 }
395
396 static int snd_pcm_ffado_start(snd_pcm_ioplug_t *io)
397 {
398     int result = 0;
399     snd_pcm_ffado_t *ffado = (snd_pcm_ffado_t *)io->private_data;
400
401     PRINT_FUNCTION_ENTRY;
402
403     result = pthread_create (&ffado->thread, 0, ffado_workthread, ffado);
404     if(result) return result;
405
406     // FIXME: start the SHM stuff
407     return 0;
408 }
409
410 static int snd_pcm_ffado_stop(snd_pcm_ioplug_t *io)
411 {
412     snd_pcm_ffado_t *ffado = (snd_pcm_ffado_t *)io->private_data;
413
414     PRINT_FUNCTION_ENTRY;
415
416     if(pthread_cancel(ffado->thread)) {
417         debugError("could not cancel thread!\n");
418     }
419
420     if(pthread_join(ffado->thread,NULL)) {
421         debugError("could not join thread!\n");
422     }
423
424     // FIXME: stop the SHM client
425     return 0;
426 }
427
428 static int snd_pcm_ffado_prepare(snd_pcm_ioplug_t *io)
429 {
430     PRINT_FUNCTION_ENTRY;
431     return 0;
432 }
433
434 static snd_pcm_ioplug_callback_t ffado_pcm_callback;
435
436 #define ARRAY_SIZE(ary)    (sizeof(ary)/sizeof(ary[0]))
437
438 static int ffado_set_hw_constraint(snd_pcm_ffado_t *ffado)
439 {
440     PRINT_FUNCTION_ENTRY;
441     unsigned int access_list[] = {
442         SND_PCM_ACCESS_MMAP_NONINTERLEAVED,
443 //         SND_PCM_ACCESS_RW_NONINTERLEAVED,
444     };
445
446     unsigned int rate_list[1];
447
448     unsigned int format = SND_PCM_FORMAT_S24;
449     int err;
450
451     // FIXME: make all of the parameters dynamic instead of static
452     rate_list[0] = 48000;
453
454     // setup the plugin capabilities
455     if ((err = snd_pcm_ioplug_set_param_list(&ffado->io, SND_PCM_IOPLUG_HW_ACCESS,
456                          ARRAY_SIZE(access_list), access_list)) < 0 ||
457         (err = snd_pcm_ioplug_set_param_list(&ffado->io, SND_PCM_IOPLUG_HW_RATE,
458                          ARRAY_SIZE(rate_list), rate_list)) < 0 ||
459         (err = snd_pcm_ioplug_set_param_list(&ffado->io, SND_PCM_IOPLUG_HW_FORMAT,
460                          1, &format)) < 0 ||
461         (err = snd_pcm_ioplug_set_param_minmax(&ffado->io, SND_PCM_IOPLUG_HW_CHANNELS,
462                            ffado->channels, ffado->channels)) < 0 ||
463         (err = snd_pcm_ioplug_set_param_minmax(&ffado->io, SND_PCM_IOPLUG_HW_PERIOD_BYTES,
464                            ffado->period, ffado->period)) < 0 ||
465         (err = snd_pcm_ioplug_set_param_minmax(&ffado->io, SND_PCM_IOPLUG_HW_PERIODS,
466                            ffado->nb_buffers, ffado->nb_buffers)) < 0)
467         return err;
468
469     return 0;
470 }
471
472 static int snd_pcm_ffado_open(snd_pcm_t **pcmp, const char *name,
473                  snd_pcm_stream_t stream, int mode)
474 {
475
476     PRINT_FUNCTION_ENTRY;
477     snd_pcm_ffado_t *ffado;
478     int err;
479     int fd[2];
480
481     assert(pcmp);
482
483     ffado = (snd_pcm_ffado_t *)calloc(1, sizeof(*ffado));
484     if (!ffado)
485         return -ENOMEM;
486
487     ffado->stream=stream;
488
489     // discover the devices to discover the capabilities
490     // get the SHM structure
491
492     socketpair(AF_LOCAL, SOCK_STREAM, 0, fd);
493
494     ffado->fd = fd[0];
495
496     // initialize callback struct
497     ffado_pcm_callback.close = snd_pcm_ffado_close;
498     ffado_pcm_callback.start = snd_pcm_ffado_start;
499     ffado_pcm_callback.stop = snd_pcm_ffado_stop;
500     ffado_pcm_callback.pointer = snd_pcm_ffado_pointer;
501     ffado_pcm_callback.hw_params = snd_pcm_ffado_hw_params;
502     ffado_pcm_callback.prepare = snd_pcm_ffado_prepare;
503     ffado_pcm_callback.poll_revents = snd_pcm_ffado_poll_revents;
504 //     if (stream == SND_PCM_STREAM_PLAYBACK) {
505 //         ffado_pcm_callback.transfer = snd_pcm_ffado_write;
506 //     } else {
507 //         ffado_pcm_callback.transfer = snd_pcm_ffado_read;
508 //     }
509
510     // prepare io struct
511     ffado->io.version = SND_PCM_IOPLUG_VERSION;
512     ffado->io.name = "FFADO PCM Plugin";
513     ffado->io.callback = &ffado_pcm_callback;
514     ffado->io.private_data = ffado;
515 //     ffado->io.mmap_rw = 0;
516     ffado->io.mmap_rw = 1;
517     ffado->io.poll_fd = fd[1];
518     ffado->io.poll_events = stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
519
520     err = snd_pcm_ioplug_create(&ffado->io, name, stream, mode);
521     if (err < 0) {
522         snd_pcm_ffado_free(ffado);
523         return err;
524     }
525
526     err = ffado_set_hw_constraint(ffado);
527     if (err < 0) {
528         snd_pcm_ioplug_delete(&ffado->io);
529         return err;
530     }
531
532     *pcmp = ffado->io.pcm;
533
534     // these are the params
535     ffado->channels = 2;
536     ffado->period = 1024;
537     ffado->verbose = 6;
538     ffado->nb_buffers = 5;
539
540     setDebugLevel(ffado->verbose);
541
542     ffado->areas = (snd_pcm_channel_area_t *)calloc(ffado->channels, sizeof(snd_pcm_channel_area_t));
543     if (!ffado->areas) {
544         snd_pcm_ffado_free(ffado);
545         return -ENOMEM;
546     }
547
548     // prepare the IPC buffer
549     unsigned int buffsize = ffado->channels * ffado->period * 4;
550     if(stream == SND_PCM_STREAM_PLAYBACK) {
551         ffado->buffer = new IpcRingBuffer("playbackbuffer",
552                               IpcRingBuffer::eBT_Slave,
553                               IpcRingBuffer::eD_Outward,
554                               IpcRingBuffer::eB_Blocking,
555                               ffado->nb_buffers, buffsize);
556         if(ffado->buffer == NULL) {
557             debugError("Could not create playbackbuffer\n");
558             return -1;
559         }
560         if(!ffado->buffer->init()) {
561             debugError("Could not init playbackbuffer\n");
562             delete ffado->buffer;
563             ffado->buffer = NULL;
564             return -1;
565         }
566         ffado->buffer->setVerboseLevel(ffado->verbose);
567     } else {
568         ffado->buffer = new IpcRingBuffer("capturebuffer",
569                               IpcRingBuffer::eBT_Slave,
570                               IpcRingBuffer::eD_Inward,
571                               IpcRingBuffer::eB_Blocking,
572                               ffado->nb_buffers, buffsize);
573         if(ffado->buffer == NULL) {
574             debugError("Could not create capturebuffer\n");
575             return -1;
576         }
577         if(!ffado->buffer->init()) {
578             debugError("Could not init capturebuffer\n");
579             delete ffado->buffer;
580             ffado->buffer = NULL;
581             return -1;
582         }
583         ffado->buffer->setVerboseLevel(ffado->verbose);
584     }
585
586     return 0;
587 }
588
589 SND_PCM_PLUGIN_DEFINE_FUNC(ffado)
590 {
591     printMessage("FireWire plugin for ALSA\n  version %s compiled %s %s\n  using %s\n",
592         FFADO_PLUGIN_VERSION, __DATE__, __TIME__, PACKAGE_STRING);
593
594     snd_config_iterator_t i, next;
595     int err;
596
597     snd_config_for_each(i, next, conf) {
598         snd_config_t *n = snd_config_iterator_entry(i);
599         const char *id;
600         if (snd_config_get_id(n, &id) < 0)
601             continue;
602         if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0)
603             continue;
604
605         SNDERR("Unknown field %s", id);
606         return -EINVAL;
607     }
608
609     err = snd_pcm_ffado_open(pcmp, name, stream, mode);
610
611     return err;
612
613 }
614
615 SND_PCM_PLUGIN_SYMBOL(ffado);
616
617 } // extern "C"
Note: See TracBrowser for help on using the browser.