root/trunk/libffado/src/ffado.cpp

Revision 739, 18.8 kB (checked in by ppalmers, 13 years ago)

- Adapt the ffado external API (upgrade to v3)

NEEDS NEW JACK BACKEND

- simplify FFADODevice constructor even more
- implement first framework support for supporting multiple adapters.

currently all firewire adapters are scanned for supported devices unless specified otherwise
however attaching devices to separate adapters is not supported. using multiple adapters at
that are connected together might work.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2  * Copyright (C) 2005-2007 by Daniel Wagner
3  * Copyright (C) 2005-2007 by Pieter Palmers
4  *
5  * This file is part of FFADO
6  * FFADO = Free Firewire (pro-)audio drivers for linux
7  *
8  * FFADO is based upon FreeBoB
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License version 2.1, as published by the Free Software Foundation;
13  *
14  * This library 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 GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22  * MA 02110-1301 USA
23  */
24
25 /*
26  * Implementation of the FFADO external C API
27  */
28
29 #include "config.h"
30
31 #include "../libffado/ffado.h"
32
33 #include "debugmodule/debugmodule.h"
34 #include "fbtypes.h"
35 #include "devicemanager.h"
36 #include "ffadodevice.h"
37 #include "libstreaming/StreamProcessorManager.h"
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <assert.h>
43 #include <string>
44
45 DECLARE_GLOBAL_DEBUG_MODULE;
46 IMPL_GLOBAL_DEBUG_MODULE( FFADO, DEBUG_LEVEL_VERBOSE );
47
48 #ifdef __cplusplus
49 extern "C" {
50 #endif
51
52 // this is very much nescessary, as otherwise the
53 // message buffer thread doesn't get killed when the
54 // library is dlclose()'d
55
56 static void exitfunc(void) __attribute__((destructor));
57
58 static void exitfunc(void)
59 {
60     delete DebugModuleManager::instance();
61
62 }
63 #ifdef __cplusplus
64 }
65 #endif
66
67 const char*
68 ffado_get_version() {
69     return PACKAGE_STRING;
70 }
71
72 int
73 ffado_get_api_version() {
74     return FFADO_API_VERSION;
75 }
76
77 #warning this should be cleaned up
78 #include "libavc/general/avc_generic.h"
79 void ffado_sleep_after_avc_command( int time )
80 {
81     AVC::AVCCommand::setSleepAfterAVCCommand( time );
82 }
83
84
85 using namespace Streaming;
86
87 struct _ffado_device
88 {
89     DeviceManager * m_deviceManager;
90     StreamProcessorManager *processorManager;
91
92     ffado_options_t options;
93     ffado_device_info_t device_info;
94 };
95
96 ffado_device_t *ffado_streaming_init (ffado_device_info_t device_info, ffado_options_t options) {
97     unsigned int i=0;
98     setDebugLevel(options.verbose);
99
100     struct _ffado_device *dev = new struct _ffado_device;
101
102     debugWarning("%s built %s %s\n", ffado_get_version(), __DATE__, __TIME__);
103
104     if(!dev) {
105         debugFatal( "Could not allocate streaming device\n" );
106         return 0;
107     }
108
109     memcpy((void *)&dev->options, (void *)&options, sizeof(dev->options));
110
111     dev->m_deviceManager = new DeviceManager();
112     if ( !dev->m_deviceManager ) {
113         debugFatal( "Could not allocate device manager\n" );
114         delete dev;
115         return 0;
116     }
117
118     dev->m_deviceManager->setVerboseLevel(dev->options.verbose);
119     if ( !dev->m_deviceManager->initialize() ) {
120         debugFatal( "Could not initialize device manager\n" );
121         delete dev->m_deviceManager;
122         delete dev;
123         return 0;
124     }
125
126     for (i = 0; i < device_info.nb_device_spec_strings; i++) {
127         char *s = device_info.device_spec_strings[i];
128         if ( !dev->m_deviceManager->addSpecString(s) ) {
129             debugFatal( "Could not add spec string %s to device manager\n", s );
130             delete dev->m_deviceManager;
131             delete dev;
132             return 0;
133         }
134     }
135
136
137     // create a processor manager to manage the actual stream
138     // processors
139     dev->processorManager = new StreamProcessorManager( dev->options.period_size,
140                                                         dev->options.sample_rate,
141                                                         dev->options.nb_buffers);
142     if(!dev->processorManager) {
143             debugFatal("Could not create StreamProcessorManager\n");
144             delete dev->m_deviceManager;
145             delete dev;
146             return 0;
147     }
148
149     dev->processorManager->setThreadParameters(dev->options.realtime, dev->options.packetizer_priority);
150
151     dev->processorManager->setVerboseLevel(dev->options.verbose);
152     if(!dev->processorManager->init()) {
153             debugFatal("Could not init StreamProcessorManager\n");
154             delete dev->processorManager;
155             delete dev->m_deviceManager;
156             delete dev;
157             return 0;
158     }
159
160     // set slave mode option
161     bool slaveMode=(dev->options.slave_mode != 0);
162     debugOutput(DEBUG_LEVEL_VERBOSE, "setting slave mode to %d\n", slaveMode);
163     if(!dev->m_deviceManager->setOption("slaveMode", slaveMode)) {
164             debugWarning("Failed to set slave mode option\n");
165     }
166     // set snoop mode option
167     bool snoopMode=(dev->options.snoop_mode != 0);
168     debugOutput(DEBUG_LEVEL_VERBOSE, "setting snoop mode to %d\n", snoopMode);
169     if(!dev->m_deviceManager->setOption("snoopMode", snoopMode)) {
170             debugWarning("Failed to set snoop mode option\n");
171     }
172
173     // discover the devices on the bus
174     if(!dev->m_deviceManager->discover()) {
175             debugFatal("Could not discover devices\n");
176             delete dev->processorManager;
177             delete dev->m_deviceManager;
178             delete dev;
179             return 0;
180     }
181
182     // are there devices on the bus?
183     if(dev->m_deviceManager->getAvDeviceCount()==0) {
184             debugFatal("There are no devices on the bus\n");
185             delete dev->processorManager;
186             delete dev->m_deviceManager;
187             delete dev;
188             return 0;
189     }
190
191     // iterate over the found devices
192     // add the stream processors of the devices to the managers
193     for(i=0;i<dev->m_deviceManager->getAvDeviceCount();i++) {
194         FFADODevice *device=dev->m_deviceManager->getAvDeviceByIndex(i);
195         assert(device);
196
197         debugOutput(DEBUG_LEVEL_VERBOSE, "Locking device (%p)\n", device);
198
199         if (!device->lock()) {
200             debugWarning("Could not lock device, skipping device (%p)!\n", device);
201             continue;
202         }
203
204         debugOutput(DEBUG_LEVEL_VERBOSE, "Setting samplerate to %d for (%p)\n",
205                     dev->options.sample_rate, device);
206
207         // Set the device's sampling rate to that requested
208         // FIXME: does this really belong here?  If so we need to handle errors.
209         if (!device->setSamplingFrequency(dev->options.sample_rate)) {
210             debugOutput(DEBUG_LEVEL_VERBOSE, " => Retry setting samplerate to %d for (%p)\n",
211                         dev->options.sample_rate, device);
212
213             // try again:
214             if (!device->setSamplingFrequency(dev->options.sample_rate)) {
215                 delete dev->processorManager;
216                 delete dev->m_deviceManager;
217                 delete dev;
218                 debugFatal("Could not set sampling frequency to %d\n",dev->options.sample_rate);
219                 return 0;
220             }
221         }
222
223         // prepare the device
224         device->prepare();
225         int j=0;
226         for(j=0; j<device->getStreamCount();j++) {
227             StreamProcessor *streamproc=device->getStreamProcessorByIndex(j);
228             debugOutput(DEBUG_LEVEL_VERBOSE, "Registering stream processor %d of device %d with processormanager\n",j,i);
229             if (!dev->processorManager->registerProcessor(streamproc)) {
230                 delete dev->processorManager;
231                 delete dev->m_deviceManager;
232                 delete dev;
233                 debugFatal("Could not register stream processor (%p) with the Processor manager\n", streamproc);
234                 return 0;
235             }
236         }
237     }
238
239     // set the sync source
240     if (!dev->processorManager->setSyncSource(dev->m_deviceManager->getSyncSource())) {
241         debugWarning("Could not set processorManager sync source (%p)\n",
242             dev->m_deviceManager->getSyncSource());
243     }
244
245     // we are ready!
246     debugOutputShort(DEBUG_LEVEL_VERBOSE, "\n\n");
247     return dev;
248
249 }
250
251 int ffado_streaming_prepare(ffado_device_t *dev) {
252     debugOutput(DEBUG_LEVEL_VERBOSE, "Preparing...\n");
253
254     if (!dev->processorManager->prepare()) {
255         debugFatal("Could not prepare streaming...\n");
256         return false;
257     }
258
259     return true;
260 }
261
262 void ffado_streaming_finish(ffado_device_t *dev) {
263     unsigned int i=0;
264
265     assert(dev);
266
267     // iterate over the found devices
268     for(i=0;i<dev->m_deviceManager->getAvDeviceCount();i++) {
269         FFADODevice *device=dev->m_deviceManager->getAvDeviceByIndex(i);
270         assert(device);
271
272         debugOutput(DEBUG_LEVEL_VERBOSE, "Unlocking device (%p)\n", device);
273
274         if (!device->unlock()) {
275             debugWarning("Could not unlock device (%p)!\n", device);
276         }
277     }
278
279     delete dev->processorManager;
280     delete dev->m_deviceManager;
281     delete dev;
282
283     return;
284 }
285
286 int ffado_streaming_start(ffado_device_t *dev) {
287     unsigned int i=0;
288     debugOutput(DEBUG_LEVEL_VERBOSE,"------------- Start -------------\n");
289
290     // create the connections for all devices
291     // iterate over the found devices
292     // add the stream processors of the devices to the managers
293     for(i=0;i<dev->m_deviceManager->getAvDeviceCount();i++) {
294         FFADODevice *device=dev->m_deviceManager->getAvDeviceByIndex(i);
295         assert(device);
296
297         int j=0;
298         for(j=0; j<device->getStreamCount();j++) {
299         debugOutput(DEBUG_LEVEL_VERBOSE,"Starting stream %d of device %d\n",j,i);
300             // start the stream
301             if (!device->startStreamByIndex(j)) {
302                 debugWarning("Could not start stream %d of device %d\n",j,i);
303                 continue;
304             }
305         }
306
307         if (!device->enableStreaming()) {
308             debugWarning("Could not enable streaming on device %d!\n",i);
309         }
310     }
311
312     if(dev->processorManager->start()) {
313         return 0;
314     } else {
315         ffado_streaming_stop(dev);
316         return -1;
317     }
318 }
319
320 int ffado_streaming_stop(ffado_device_t *dev) {
321     unsigned int i;
322     debugOutput(DEBUG_LEVEL_VERBOSE,"------------- Stop -------------\n");
323
324     dev->processorManager->stop();
325
326     // create the connections for all devices
327     // iterate over the found devices
328     // add the stream processors of the devices to the managers
329     for(i=0;i<dev->m_deviceManager->getAvDeviceCount();i++) {
330         FFADODevice *device=dev->m_deviceManager->getAvDeviceByIndex(i);
331         assert(device);
332
333         if (!device->disableStreaming()) {
334             debugWarning("Could not disable streaming on device %d!\n",i);
335         }
336
337         int j=0;
338         for(j=0; j<device->getStreamCount();j++) {
339             debugOutput(DEBUG_LEVEL_VERBOSE,"Stopping stream %d of device %d\n",j,i);
340             // stop the stream
341             // start the stream
342             if (!device->stopStreamByIndex(j)) {
343                 debugWarning("Could not stop stream %d of device %d\n",j,i);
344                 continue;
345             }
346         }
347     }
348
349     return 0;
350 }
351
352 int ffado_streaming_reset(ffado_device_t *dev) {
353     debugOutput(DEBUG_LEVEL_VERBOSE,"------------- Reset -------------\n");
354
355     // dev->processorManager->reset();
356
357     return 0;
358 }
359
360 int ffado_streaming_wait(ffado_device_t *dev) {
361     static int periods=0;
362     static int periods_print=0;
363     static int xruns=0;
364
365     periods++;
366     if(periods>periods_print) {
367         debugOutputShort(DEBUG_LEVEL_VERBOSE, "\nffado_streaming_wait\n");
368         debugOutputShort(DEBUG_LEVEL_VERBOSE, "============================================\n");
369         debugOutputShort(DEBUG_LEVEL_VERBOSE, "Xruns: %d\n",xruns);
370         debugOutputShort(DEBUG_LEVEL_VERBOSE, "============================================\n");
371         dev->processorManager->dumpInfo();
372         debugOutputShort(DEBUG_LEVEL_VERBOSE, "\n");
373         periods_print+=100;
374     }
375
376     if(dev->processorManager->waitForPeriod()) {
377         return dev->options.period_size;
378     } else {
379         debugWarning("XRUN detected\n");
380
381         // do xrun recovery
382         dev->processorManager->handleXrun();
383         xruns++;
384         return -1;
385     }
386 }
387
388 int ffado_streaming_transfer_capture_buffers(ffado_device_t *dev) {
389     return dev->processorManager->transfer(StreamProcessor::ePT_Receive);
390 }
391
392 int ffado_streaming_transfer_playback_buffers(ffado_device_t *dev) {
393     return dev->processorManager->transfer(StreamProcessor::ePT_Transmit);
394 }
395
396 int ffado_streaming_transfer_buffers(ffado_device_t *dev) {
397     return dev->processorManager->transfer();
398 }
399
400
401 int ffado_streaming_write(ffado_device_t *dev, int i, ffado_sample_t *buffer, int nsamples) {
402     Port *p=dev->processorManager->getPortByIndex(i, Port::E_Playback);
403     // use an assert here performancewise,
404     // it should already have failed before, if not correct
405     assert(p);
406
407     return p->writeEvents((void *)buffer, nsamples);
408 }
409
410 int ffado_streaming_read(ffado_device_t *dev, int i, ffado_sample_t *buffer, int nsamples) {
411     Port *p=dev->processorManager->getPortByIndex(i, Port::E_Capture);
412     // use an assert here performancewise,
413     // it should already have failed before, if not correct
414     assert(p);
415
416     return p->readEvents((void *)buffer, nsamples);
417 }
418
419 int ffado_streaming_get_nb_capture_streams(ffado_device_t *dev) {
420     return dev->processorManager->getPortCount(Port::E_Capture);
421 }
422
423 int ffado_streaming_get_nb_playback_streams(ffado_device_t *dev) {
424     return dev->processorManager->getPortCount(Port::E_Playback);
425 }
426
427 int ffado_streaming_get_capture_stream_name(ffado_device_t *dev, int i, char* buffer, size_t buffersize) {
428     Port *p=dev->processorManager->getPortByIndex(i, Port::E_Capture);
429     if(!p) {
430         debugWarning("Could not get capture port at index %d\n",i);
431         return -1;
432     }
433
434     std::string name=p->getName();
435     if (!strncpy(buffer, name.c_str(), buffersize)) {
436         debugWarning("Could not copy name\n");
437         return -1;
438     } else return 0;
439 }
440
441 int ffado_streaming_get_playback_stream_name(ffado_device_t *dev, int i, char* buffer, size_t buffersize) {
442     Port *p=dev->processorManager->getPortByIndex(i, Port::E_Playback);
443     if(!p) {
444         debugWarning("Could not get playback port at index %d\n",i);
445         return -1;
446     }
447
448     std::string name=p->getName();
449     if (!strncpy(buffer, name.c_str(), buffersize)) {
450         debugWarning("Could not copy name\n");
451         return -1;
452     } else return 0;
453 }
454
455 ffado_streaming_stream_type ffado_streaming_get_capture_stream_type(ffado_device_t *dev, int i) {
456     Port *p=dev->processorManager->getPortByIndex(i, Port::E_Capture);
457     if(!p) {
458         debugWarning("Could not get capture port at index %d\n",i);
459         return ffado_stream_type_invalid;
460     }
461     switch(p->getPortType()) {
462     case Port::E_Audio:
463         return ffado_stream_type_audio;
464     case Port::E_Midi:
465         return ffado_stream_type_midi;
466     case Port::E_Control:
467         return ffado_stream_type_control;
468     default:
469         return ffado_stream_type_unknown;
470     }
471 }
472
473 ffado_streaming_stream_type ffado_streaming_get_playback_stream_type(ffado_device_t *dev, int i) {
474     Port *p=dev->processorManager->getPortByIndex(i, Port::E_Playback);
475     if(!p) {
476         debugWarning("Could not get playback port at index %d\n",i);
477         return ffado_stream_type_invalid;
478     }
479     switch(p->getPortType()) {
480     case Port::E_Audio:
481         return ffado_stream_type_audio;
482     case Port::E_Midi:
483         return ffado_stream_type_midi;
484     case Port::E_Control:
485         return ffado_stream_type_control;
486     default:
487         return ffado_stream_type_unknown;
488     }
489 }
490
491 int ffado_streaming_set_stream_buffer_type(ffado_device_t *dev, int i,
492     ffado_streaming_buffer_type t, enum Port::E_Direction direction) {
493
494     Port *p=dev->processorManager->getPortByIndex(i, direction);
495     if(!p) {
496         debugWarning("Could not get %s port at index %d\n",
497             (direction==Port::E_Playback?"Playback":"Capture"),i);
498         return -1;
499     }
500
501     switch(t) {
502     case ffado_buffer_type_int24:
503         if (!p->setDataType(Port::E_Int24)) {
504             debugWarning("%s: Could not set data type to Int24\n",p->getName().c_str());
505             return -1;
506         }
507         if (!p->setBufferType(Port::E_PointerBuffer)) {
508             debugWarning("%s: Could not set buffer type to Pointerbuffer\n",p->getName().c_str());
509             return -1;
510         }
511         break;
512     case ffado_buffer_type_float:
513         if (!p->setDataType(Port::E_Float)) {
514             debugWarning("%s: Could not set data type to Float\n",p->getName().c_str());
515             return -1;
516         }
517         if (!p->setBufferType(Port::E_PointerBuffer)) {
518             debugWarning("%s: Could not set buffer type to Pointerbuffer\n",p->getName().c_str());
519             return -1;
520         }
521         break;
522     case ffado_buffer_type_midi:
523         if (!p->setDataType(Port::E_MidiEvent)) {
524             debugWarning("%s: Could not set data type to MidiEvent\n",p->getName().c_str());
525             return -1;
526         }
527         if (!p->setBufferType(Port::E_RingBuffer)) {
528             debugWarning("%s: Could not set buffer type to Ringbuffer\n",p->getName().c_str());
529             return -1;
530         }
531         break;
532     default:
533         debugWarning("%s: Unsupported buffer type\n",p->getName().c_str());
534         return -1;
535     }
536     return 0;
537
538 }
539
540 int ffado_streaming_set_playback_buffer_type(ffado_device_t *dev, int i, ffado_streaming_buffer_type t) {
541     return ffado_streaming_set_stream_buffer_type(dev, i, t, Port::E_Playback);
542 }
543
544 int ffado_streaming_set_capture_buffer_type(ffado_device_t *dev, int i, ffado_streaming_buffer_type t) {
545     return ffado_streaming_set_stream_buffer_type(dev, i, t, Port::E_Capture);
546 }
547
548 int ffado_streaming_stream_onoff(ffado_device_t *dev, int i,
549     int on, enum Port::E_Direction direction) {
550     Port *p=dev->processorManager->getPortByIndex(i, direction);
551     if(!p) {
552         debugWarning("Could not get %s port at index %d\n",
553             (direction==Port::E_Playback?"Playback":"Capture"),i);
554         return -1;
555     }
556     if(on) {
557         p->enable();
558     } else {
559         p->disable();
560     }
561     return 0;
562 }
563
564 int ffado_streaming_playback_stream_onoff(ffado_device_t *dev, int number, int on) {
565     return ffado_streaming_stream_onoff(dev, number, on, Port::E_Playback);
566 }
567
568 int ffado_streaming_capture_stream_onoff(ffado_device_t *dev, int number, int on) {
569     return ffado_streaming_stream_onoff(dev, number, on, Port::E_Capture);
570 }
571
572 // TODO: the way port buffers are set in the C api doesn't satisfy me
573 int ffado_streaming_set_capture_stream_buffer(ffado_device_t *dev, int i, char *buff) {
574         Port *p=dev->processorManager->getPortByIndex(i, Port::E_Capture);
575
576         // use an assert here performancewise,
577         // it should already have failed before, if not correct
578         assert(p);
579
580         p->useExternalBuffer(true);
581         p->setExternalBufferAddress((void *)buff);
582
583         return 0;
584
585 }
586
587 int ffado_streaming_set_playback_stream_buffer(ffado_device_t *dev, int i, char *buff) {
588         Port *p=dev->processorManager->getPortByIndex(i, Port::E_Playback);
589         // use an assert here performancewise,
590         // it should already have failed before, if not correct
591         assert(p);
592
593         p->useExternalBuffer(true);
594         p->setExternalBufferAddress((void *)buff);
595
596         return 0;
597 }
Note: See TracBrowser for help on using the browser.