root/trunk/libffado/src/ffado.cpp

Revision 791, 15.2 kB (checked in by ppalmers, 13 years ago)

try and get some better low-latency performance

  • 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 program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (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 General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24
25 /*
26  * Implementation of the FFADO external C API
27  */
28
29 #include "config.h"
30
31 #include "../libffado/ffado.h"
32 #include "libstreaming/generic/StreamProcessor.h"
33 #include "libstreaming/generic/Port.h"
34
35 #include "debugmodule/debugmodule.h"
36 #include "fbtypes.h"
37 #include "devicemanager.h"
38 #include "ffadodevice.h"
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <assert.h>
44 #include <string>
45
46 DECLARE_GLOBAL_DEBUG_MODULE;
47 IMPL_GLOBAL_DEBUG_MODULE( FFADO, DEBUG_LEVEL_VERBOSE );
48
49 #ifdef __cplusplus
50 extern "C" {
51 #endif
52
53 // this is very much nescessary, as otherwise the
54 // message buffer thread doesn't get killed when the
55 // library is dlclose()'d
56
57 static void exitfunc(void) __attribute__((destructor));
58
59 static void exitfunc(void)
60 {
61     delete DebugModuleManager::instance();
62
63 }
64 #ifdef __cplusplus
65 }
66 #endif
67
68 const char*
69 ffado_get_version() {
70     return PACKAGE_STRING;
71 }
72
73 int
74 ffado_get_api_version() {
75     return FFADO_API_VERSION;
76 }
77
78 #warning this should be cleaned up
79 #include "libavc/general/avc_generic.h"
80 void ffado_sleep_after_avc_command( int time )
81 {
82     AVC::AVCCommand::setSleepAfterAVCCommand( time );
83 }
84
85 struct _ffado_device
86 {
87     DeviceManager * m_deviceManager;
88
89     ffado_options_t options;
90     ffado_device_info_t device_info;
91 };
92
93 ffado_device_t *ffado_streaming_init (ffado_device_info_t device_info, ffado_options_t options) {
94     unsigned int i=0;
95     setDebugLevel(options.verbose);
96
97     struct _ffado_device *dev = new struct _ffado_device;
98
99     debugWarning("%s built %s %s\n", ffado_get_version(), __DATE__, __TIME__);
100
101     if(!dev) {
102         debugFatal( "Could not allocate streaming device\n" );
103         return 0;
104     }
105
106     memcpy((void *)&dev->options, (void *)&options, sizeof(dev->options));
107
108     dev->m_deviceManager = new DeviceManager();
109     if ( !dev->m_deviceManager ) {
110         debugFatal( "Could not allocate device manager\n" );
111         delete dev;
112         return 0;
113     }
114
115     dev->m_deviceManager->setVerboseLevel(dev->options.verbose);
116     dev->m_deviceManager->setThreadParameters(dev->options.realtime, dev->options.packetizer_priority);
117
118     for (i = 0; i < device_info.nb_device_spec_strings; i++) {
119         char *s = device_info.device_spec_strings[i];
120         if ( !dev->m_deviceManager->addSpecString(s) ) {
121             debugFatal( "Could not add spec string %s to device manager\n", s );
122             delete dev->m_deviceManager;
123             delete dev;
124             return 0;
125         }
126     }
127     // create a processor manager to manage the actual stream
128     // processors
129     if ( !dev->m_deviceManager->setStreamingParams(dev->options.period_size,
130                                                    dev->options.sample_rate,
131                                                    dev->options.nb_buffers))
132     {
133         debugFatal( "Could not set streaming parameters of device manager\n" );
134         delete dev->m_deviceManager;
135         delete dev;
136         return 0;
137     }
138
139     // set slave mode option
140     bool slaveMode=(dev->options.slave_mode != 0);
141     debugOutput(DEBUG_LEVEL_VERBOSE, "setting slave mode to %d\n", slaveMode);
142     if(!dev->m_deviceManager->setOption("slaveMode", slaveMode)) {
143             debugWarning("Failed to set slave mode option\n");
144     }
145     // set snoop mode option
146     bool snoopMode=(dev->options.snoop_mode != 0);
147     debugOutput(DEBUG_LEVEL_VERBOSE, "setting snoop mode to %d\n", snoopMode);
148     if(!dev->m_deviceManager->setOption("snoopMode", snoopMode)) {
149             debugWarning("Failed to set snoop mode option\n");
150     }
151
152     if ( !dev->m_deviceManager->initialize() ) {
153         debugFatal( "Could not initialize device manager\n" );
154         delete dev->m_deviceManager;
155         delete dev;
156         return 0;
157     }
158     // discover the devices on the bus
159     if(!dev->m_deviceManager->discover()) {
160         debugFatal("Could not discover devices\n");
161         delete dev->m_deviceManager;
162         delete dev;
163         return 0;
164     }
165     // are there devices on the bus?
166     if(dev->m_deviceManager->getAvDeviceCount() == 0) {
167         debugFatal("There are no devices on the bus\n");
168         delete dev->m_deviceManager;
169         delete dev;
170         return 0;
171     }
172     // prepare here or there are no ports for jack
173     if(!dev->m_deviceManager->initStreaming()) {
174         debugFatal("Could not init the streaming system\n");
175         return 0;
176     }
177     // we are ready!
178     return dev;
179 }
180
181 int ffado_streaming_prepare(ffado_device_t *dev) {
182     debugOutput(DEBUG_LEVEL_VERBOSE, "Preparing...\n");
183     // prepare here or there are no ports for jack
184     if(!dev->m_deviceManager->prepareStreaming()) {
185         debugFatal("Could not prepare the streaming system\n");
186         return 0;
187     }
188     return 0;
189 }
190
191 void ffado_streaming_finish(ffado_device_t *dev) {
192     assert(dev);
193     if(!dev->m_deviceManager->finishStreaming()) {
194         debugError("Could not finish the streaming\n");
195     }
196     delete dev->m_deviceManager;
197     delete dev;
198     return;
199 }
200
201 int ffado_streaming_start(ffado_device_t *dev) {
202     debugOutput(DEBUG_LEVEL_VERBOSE,"------------- Start -------------\n");
203     if(!dev->m_deviceManager->startStreaming()) {
204         debugFatal("Could not start the streaming system\n");
205         return -1;
206     }
207     return 0;
208 }
209
210 int ffado_streaming_stop(ffado_device_t *dev) {
211     debugOutput(DEBUG_LEVEL_VERBOSE,"------------- Stop -------------\n");
212     if(!dev->m_deviceManager->stopStreaming()) {
213         debugFatal("Could not stop the streaming system\n");
214         return -1;
215     }
216     return 0;
217 }
218
219 int ffado_streaming_reset(ffado_device_t *dev) {
220     debugOutput(DEBUG_LEVEL_VERBOSE,"------------- Reset -------------\n");
221     if(!dev->m_deviceManager->resetStreaming()) {
222         debugFatal("Could not reset the streaming system\n");
223         return -1;
224     }
225     return 0;
226 }
227
228 int ffado_streaming_wait(ffado_device_t *dev) {
229     static int periods=0;
230     static int periods_print=0;
231     static int xruns=0;
232
233     periods++;
234     if(periods>periods_print) {
235         debugOutputShort(DEBUG_LEVEL_VERBOSE, "\nffado_streaming_wait\n");
236         debugOutputShort(DEBUG_LEVEL_VERBOSE, "============================================\n");
237         debugOutputShort(DEBUG_LEVEL_VERBOSE, "Xruns: %d\n", xruns);
238         debugOutputShort(DEBUG_LEVEL_VERBOSE, "============================================\n");
239         dev->m_deviceManager->showStreamingInfo();
240         debugOutputShort(DEBUG_LEVEL_VERBOSE, "\n");
241         periods_print+=100;
242     }
243
244     if(dev->m_deviceManager->waitForPeriod()) {
245         return dev->options.period_size;
246     } else {
247         debugWarning("XRUN");
248         xruns++;
249         return -1;
250     }
251 }
252
253 int ffado_streaming_transfer_capture_buffers(ffado_device_t *dev) {
254     return dev->m_deviceManager->getStreamProcessorManager().transfer(Streaming::StreamProcessor::ePT_Receive);
255 }
256
257 int ffado_streaming_transfer_playback_buffers(ffado_device_t *dev) {
258     return dev->m_deviceManager->getStreamProcessorManager().transfer(Streaming::StreamProcessor::ePT_Transmit);
259 }
260
261 int ffado_streaming_transfer_buffers(ffado_device_t *dev) {
262     return dev->m_deviceManager->getStreamProcessorManager().transfer();
263 }
264
265
266 int ffado_streaming_write(ffado_device_t *dev, int i, ffado_sample_t *buffer, int nsamples) {
267     Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, Streaming::Port::E_Playback);
268     // use an assert here performancewise,
269     // it should already have failed before, if not correct
270     assert(p);
271
272     return p->writeEvents((void *)buffer, nsamples);
273 }
274
275 int ffado_streaming_read(ffado_device_t *dev, int i, ffado_sample_t *buffer, int nsamples) {
276     Streaming::Port *p=dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, Streaming::Port::E_Capture);
277     // use an assert here performancewise,
278     // it should already have failed before, if not correct
279     assert(p);
280
281     return p->readEvents((void *)buffer, nsamples);
282 }
283
284 int ffado_streaming_get_nb_capture_streams(ffado_device_t *dev) {
285     return dev->m_deviceManager->getStreamProcessorManager().getPortCount(Streaming::Port::E_Capture);
286 }
287
288 int ffado_streaming_get_nb_playback_streams(ffado_device_t *dev) {
289     return dev->m_deviceManager->getStreamProcessorManager().getPortCount(Streaming::Port::E_Playback);
290 }
291
292 int ffado_streaming_get_capture_stream_name(ffado_device_t *dev, int i, char* buffer, size_t buffersize) {
293     Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, Streaming::Port::E_Capture);
294     if(!p) {
295         debugWarning("Could not get capture port at index %d\n",i);
296         return -1;
297     }
298
299     std::string name=p->getName();
300     if (!strncpy(buffer, name.c_str(), buffersize)) {
301         debugWarning("Could not copy name\n");
302         return -1;
303     } else return 0;
304 }
305
306 int ffado_streaming_get_playback_stream_name(ffado_device_t *dev, int i, char* buffer, size_t buffersize) {
307     Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, Streaming::Port::E_Playback);
308     if(!p) {
309         debugWarning("Could not get playback port at index %d\n",i);
310         return -1;
311     }
312
313     std::string name=p->getName();
314     if (!strncpy(buffer, name.c_str(), buffersize)) {
315         debugWarning("Could not copy name\n");
316         return -1;
317     } else return 0;
318 }
319
320 ffado_streaming_stream_type ffado_streaming_get_capture_stream_type(ffado_device_t *dev, int i) {
321     Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, Streaming::Port::E_Capture);
322     if(!p) {
323         debugWarning("Could not get capture port at index %d\n",i);
324         return ffado_stream_type_invalid;
325     }
326     switch(p->getPortType()) {
327     case Streaming::Port::E_Audio:
328         return ffado_stream_type_audio;
329     case Streaming::Port::E_Midi:
330         return ffado_stream_type_midi;
331     case Streaming::Port::E_Control:
332         return ffado_stream_type_control;
333     default:
334         return ffado_stream_type_unknown;
335     }
336 }
337
338 ffado_streaming_stream_type ffado_streaming_get_playback_stream_type(ffado_device_t *dev, int i) {
339     Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, Streaming::Port::E_Playback);
340     if(!p) {
341         debugWarning("Could not get playback port at index %d\n",i);
342         return ffado_stream_type_invalid;
343     }
344     switch(p->getPortType()) {
345     case Streaming::Port::E_Audio:
346         return ffado_stream_type_audio;
347     case Streaming::Port::E_Midi:
348         return ffado_stream_type_midi;
349     case Streaming::Port::E_Control:
350         return ffado_stream_type_control;
351     default:
352         return ffado_stream_type_unknown;
353     }
354 }
355
356 int ffado_streaming_set_stream_buffer_type(ffado_device_t *dev, int i,
357     ffado_streaming_buffer_type t, enum Streaming::Port::E_Direction direction) {
358
359     Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, direction);
360     if(!p) {
361         debugWarning("Could not get %s port at index %d\n",
362             (direction==Streaming::Port::E_Playback?"Playback":"Capture"),i);
363         return -1;
364     }
365
366     switch(t) {
367     case ffado_buffer_type_int24:
368         if (!p->setDataType(Streaming::Port::E_Int24)) {
369             debugWarning("%s: Could not set data type to Int24\n",p->getName().c_str());
370             return -1;
371         }
372         if (!p->setBufferType(Streaming::Port::E_PointerBuffer)) {
373             debugWarning("%s: Could not set buffer type to Pointerbuffer\n",p->getName().c_str());
374             return -1;
375         }
376         break;
377     case ffado_buffer_type_float:
378         if (!p->setDataType(Streaming::Port::E_Float)) {
379             debugWarning("%s: Could not set data type to Float\n",p->getName().c_str());
380             return -1;
381         }
382         if (!p->setBufferType(Streaming::Port::E_PointerBuffer)) {
383             debugWarning("%s: Could not set buffer type to Pointerbuffer\n",p->getName().c_str());
384             return -1;
385         }
386         break;
387     case ffado_buffer_type_midi:
388         if (!p->setDataType(Streaming::Port::E_MidiEvent)) {
389             debugWarning("%s: Could not set data type to MidiEvent\n",p->getName().c_str());
390             return -1;
391         }
392         if (!p->setBufferType(Streaming::Port::E_RingBuffer)) {
393             debugWarning("%s: Could not set buffer type to Ringbuffer\n",p->getName().c_str());
394             return -1;
395         }
396         break;
397     default:
398         debugWarning("%s: Unsupported buffer type\n",p->getName().c_str());
399         return -1;
400     }
401     return 0;
402
403 }
404
405 int ffado_streaming_set_playback_buffer_type(ffado_device_t *dev, int i, ffado_streaming_buffer_type t) {
406     return ffado_streaming_set_stream_buffer_type(dev, i, t, Streaming::Port::E_Playback);
407 }
408
409 int ffado_streaming_set_capture_buffer_type(ffado_device_t *dev, int i, ffado_streaming_buffer_type t) {
410     return ffado_streaming_set_stream_buffer_type(dev, i, t, Streaming::Port::E_Capture);
411 }
412
413 int ffado_streaming_stream_onoff(ffado_device_t *dev, int i,
414     int on, enum Streaming::Port::E_Direction direction) {
415     Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, direction);
416     if(!p) {
417         debugWarning("Could not get %s port at index %d\n",
418             (direction==Streaming::Port::E_Playback?"Playback":"Capture"),i);
419         return -1;
420     }
421     if(on) {
422         p->enable();
423     } else {
424         p->disable();
425     }
426     return 0;
427 }
428
429 int ffado_streaming_playback_stream_onoff(ffado_device_t *dev, int number, int on) {
430     return ffado_streaming_stream_onoff(dev, number, on, Streaming::Port::E_Playback);
431 }
432
433 int ffado_streaming_capture_stream_onoff(ffado_device_t *dev, int number, int on) {
434     return ffado_streaming_stream_onoff(dev, number, on, Streaming::Port::E_Capture);
435 }
436
437 // TODO: the way port buffers are set in the C api doesn't satisfy me
438 int ffado_streaming_set_capture_stream_buffer(ffado_device_t *dev, int i, char *buff) {
439         Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, Streaming::Port::E_Capture);
440
441         // use an assert here performancewise,
442         // it should already have failed before, if not correct
443         assert(p);
444
445         p->useExternalBuffer(true);
446         p->setExternalBufferAddress((void *)buff);
447
448         return 0;
449
450 }
451
452 int ffado_streaming_set_playback_stream_buffer(ffado_device_t *dev, int i, char *buff) {
453         Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, Streaming::Port::E_Playback);
454         // use an assert here performancewise,
455         // it should already have failed before, if not correct
456         assert(p);
457
458         p->useExternalBuffer(true);
459         p->setExternalBufferAddress((void *)buff);
460
461         return 0;
462 }
Note: See TracBrowser for help on using the browser.