root/trunk/libffado/src/ffado.cpp

Revision 2078, 14.4 kB (checked in by jwoithe, 9 years ago)

A first pass at infrastructure required to support jack's runtime setbufsize functionality. It has been tested with exactly one interface (RME Fireface-800) and it seems to work, but there's stacks which can go wrong so wider testing is encouraged. Note that to make use of this a revised firewire jack driver will be required. I'm going to talk to the jack guys about how to proceed with this (it's slightly tricky because the libffado API is changed by this patch to add a new function - ffado_streaming_set_period_size()).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2  * Copyright (C) 2005-2008 by Daniel Wagner
3  * Copyright (C) 2005-2008 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 2 of the License, or
13  * (at your option) version 3 of the License.
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 "version.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 struct _ffado_device
79 {
80     DeviceManager * m_deviceManager;
81
82     ffado_options_t options;
83     ffado_device_info_t device_info;
84 };
85
86 ffado_device_t *ffado_streaming_init (ffado_device_info_t device_info, ffado_options_t options) {
87     unsigned int i=0;
88     setDebugLevel(options.verbose);
89
90     struct _ffado_device *dev = new struct _ffado_device;
91
92     printMessage("%s built %s %s\n", ffado_get_version(), __DATE__, __TIME__);
93
94 #if DEBUG_USE_MESSAGE_BUFFER
95     // ok
96 #else
97     printMessage("FFADO built without realtime-safe message buffer support. This can cause xruns and is not recommended.\n");
98 #endif
99
100     if(!dev) {
101         debugFatal( "Could not allocate streaming device\n" );
102         return 0;
103     }
104
105     memcpy((void *)&dev->options, (void *)&options, sizeof(dev->options));
106
107     dev->m_deviceManager = new DeviceManager();
108     if ( !dev->m_deviceManager ) {
109         debugFatal( "Could not allocate device manager\n" );
110         delete dev;
111         return 0;
112     }
113
114     dev->m_deviceManager->setVerboseLevel(dev->options.verbose);
115
116     if(dev->options.realtime) {
117         debugOutput(DEBUG_LEVEL_VERBOSE,
118                     "Starting with realtime scheduling, base priority %d\n",
119                     dev->options.packetizer_priority);
120     } else {
121         debugWarning("Realtime scheduling is not enabled. This will cause significant reliability issues.\n");
122     }
123     dev->m_deviceManager->setThreadParameters(dev->options.realtime, dev->options.packetizer_priority);
124
125     for (i = 0; i < device_info.nb_device_spec_strings; i++) {
126         char *s = device_info.device_spec_strings[i];
127         if ( !dev->m_deviceManager->addSpecString(s) ) {
128             debugFatal( "Could not add spec string %s to device manager\n", s );
129             delete dev->m_deviceManager;
130             delete dev;
131             return 0;
132         }
133     }
134     // create a processor manager to manage the actual stream
135     // processors
136     if ( !dev->m_deviceManager->setStreamingParams(dev->options.period_size,
137                                                    dev->options.sample_rate,
138                                                    dev->options.nb_buffers))
139     {
140         debugFatal( "Could not set streaming parameters of device manager\n" );
141         delete dev->m_deviceManager;
142         delete dev;
143         return 0;
144     }
145
146     // set slave mode option
147     bool slaveMode=(dev->options.slave_mode != 0);
148     debugOutput(DEBUG_LEVEL_VERBOSE, "setting slave mode to %d\n", slaveMode);
149     if(!dev->m_deviceManager->setOption("slaveMode", slaveMode)) {
150             debugWarning("Failed to set slave mode option\n");
151     }
152     // set snoop mode option
153     bool snoopMode=(dev->options.snoop_mode != 0);
154     debugOutput(DEBUG_LEVEL_VERBOSE, "setting snoop mode to %d\n", snoopMode);
155     if(!dev->m_deviceManager->setOption("snoopMode", snoopMode)) {
156             debugWarning("Failed to set snoop mode option\n");
157     }
158
159     if ( !dev->m_deviceManager->initialize() ) {
160         debugFatal( "Could not initialize device manager\n" );
161         delete dev->m_deviceManager;
162         delete dev;
163         return 0;
164     }
165     // discover the devices on the bus
166     if(!dev->m_deviceManager->discover()) {
167         debugFatal("Could not discover devices\n");
168         delete dev->m_deviceManager;
169         delete dev;
170         return 0;
171     }
172     // are there devices on the bus?
173     if(dev->m_deviceManager->getAvDeviceCount() == 0) {
174         debugFatal("There are no devices on the bus\n");
175         delete dev->m_deviceManager;
176         delete dev;
177         return 0;
178     }
179     // prepare here or there are no ports for jack
180     if(!dev->m_deviceManager->initStreaming()) {
181         debugFatal("Could not init the streaming system\n");
182         return 0;
183     }
184     // we are ready!
185     return dev;
186 }
187
188 int ffado_streaming_set_period_size(ffado_device_t *dev, unsigned int period) {
189     if (!dev->m_deviceManager->setPeriodSize(period))
190     {
191         debugFatal( "Could not set period size of device manager\n" );
192         return -1;
193     }
194     return 0;
195 }
196
197 int ffado_streaming_prepare(ffado_device_t *dev) {
198     debugOutput(DEBUG_LEVEL_VERBOSE, "Preparing...\n");
199     // prepare here or there are no ports for jack
200     if(!dev->m_deviceManager->prepareStreaming()) {
201         debugFatal("Could not prepare the streaming system\n");
202         return -1;
203     }
204     return 0;
205 }
206
207 void ffado_streaming_finish(ffado_device_t *dev) {
208     assert(dev);
209     if(!dev->m_deviceManager->finishStreaming()) {
210         debugError("Could not finish the streaming\n");
211     }
212     delete dev->m_deviceManager;
213     delete dev;
214     return;
215 }
216
217 int ffado_streaming_start(ffado_device_t *dev) {
218     debugOutput(DEBUG_LEVEL_VERBOSE,"------------- Start -------------\n");
219     if(!dev->m_deviceManager->startStreaming()) {
220         debugFatal("Could not start the streaming system\n");
221         return -1;
222     }
223     return 0;
224 }
225
226 int ffado_streaming_stop(ffado_device_t *dev) {
227     debugOutput(DEBUG_LEVEL_VERBOSE,"------------- Stop -------------\n");
228     if(!dev->m_deviceManager->stopStreaming()) {
229         debugFatal("Could not stop the streaming system\n");
230         return -1;
231     }
232     return 0;
233 }
234
235 int ffado_streaming_reset(ffado_device_t *dev) {
236     debugOutput(DEBUG_LEVEL_VERBOSE,"------------- Reset -------------\n");
237     if(!dev->m_deviceManager->resetStreaming()) {
238         debugFatal("Could not reset the streaming system\n");
239         return -1;
240     }
241     return 0;
242 }
243
244 ffado_wait_response
245 ffado_streaming_wait(ffado_device_t *dev) {
246     static int periods=0;
247     static int periods_print=0;
248     static int xruns=0;
249
250     periods++;
251     if(periods>periods_print) {
252         debugOutputShort(DEBUG_LEVEL_NORMAL, "\nffado_streaming_wait\n");
253         debugOutputShort(DEBUG_LEVEL_NORMAL, "============================================\n");
254         debugOutputShort(DEBUG_LEVEL_NORMAL, "Xruns: %d\n", xruns);
255         debugOutputShort(DEBUG_LEVEL_NORMAL, "============================================\n");
256         dev->m_deviceManager->showStreamingInfo();
257         debugOutputShort(DEBUG_LEVEL_NORMAL, "\n");
258         periods_print+=100;
259     }
260
261     enum DeviceManager::eWaitResult result;
262     result = dev->m_deviceManager->waitForPeriod();
263     if(result == DeviceManager::eWR_OK) {
264         return ffado_wait_ok;
265     } else if (result == DeviceManager::eWR_Xrun) {
266         debugOutput(DEBUG_LEVEL_NORMAL, "Handled XRUN\n");
267         xruns++;
268         return ffado_wait_xrun;
269     } else if (result == DeviceManager::eWR_Shutdown) {
270         debugWarning("Streaming system requests shutdown.\n");
271         return ffado_wait_shutdown;
272     } else {
273         debugError("Error condition while waiting (Unhandled XRUN)\n");
274         xruns++;
275         return ffado_wait_error;
276     }
277 }
278
279 int ffado_streaming_transfer_capture_buffers(ffado_device_t *dev) {
280     return dev->m_deviceManager->getStreamProcessorManager().transfer(Streaming::StreamProcessor::ePT_Receive);
281 }
282
283 int ffado_streaming_transfer_playback_buffers(ffado_device_t *dev) {
284     return dev->m_deviceManager->getStreamProcessorManager().transfer(Streaming::StreamProcessor::ePT_Transmit);
285 }
286
287 int ffado_streaming_transfer_buffers(ffado_device_t *dev) {
288     return dev->m_deviceManager->getStreamProcessorManager().transfer();
289 }
290
291 int ffado_streaming_get_nb_capture_streams(ffado_device_t *dev) {
292     return dev->m_deviceManager->getStreamProcessorManager().getPortCount(Streaming::Port::E_Capture);
293 }
294
295 int ffado_streaming_get_nb_playback_streams(ffado_device_t *dev) {
296     return dev->m_deviceManager->getStreamProcessorManager().getPortCount(Streaming::Port::E_Playback);
297 }
298
299 int ffado_streaming_get_capture_stream_name(ffado_device_t *dev, int i, char* buffer, size_t buffersize) {
300     Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, Streaming::Port::E_Capture);
301     if(!p) {
302         debugWarning("Could not get capture port at index %d\n",i);
303         return -1;
304     }
305
306     std::string name=p->getName();
307     if (!strncpy(buffer, name.c_str(), buffersize)) {
308         debugWarning("Could not copy name\n");
309         return -1;
310     } else return 0;
311 }
312
313 int ffado_streaming_get_playback_stream_name(ffado_device_t *dev, int i, char* buffer, size_t buffersize) {
314     Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, Streaming::Port::E_Playback);
315     if(!p) {
316         debugWarning("Could not get playback port at index %d\n",i);
317         return -1;
318     }
319
320     std::string name=p->getName();
321     if (!strncpy(buffer, name.c_str(), buffersize)) {
322         debugWarning("Could not copy name\n");
323         return -1;
324     } else return 0;
325 }
326
327 ffado_streaming_stream_type ffado_streaming_get_capture_stream_type(ffado_device_t *dev, int i) {
328     Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, Streaming::Port::E_Capture);
329     if(!p) {
330         debugWarning("Could not get capture port at index %d\n",i);
331         return ffado_stream_type_invalid;
332     }
333     switch(p->getPortType()) {
334     case Streaming::Port::E_Audio:
335         return ffado_stream_type_audio;
336     case Streaming::Port::E_Midi:
337         return ffado_stream_type_midi;
338     case Streaming::Port::E_Control:
339         return ffado_stream_type_control;
340     default:
341         return ffado_stream_type_unknown;
342     }
343 }
344
345 ffado_streaming_stream_type ffado_streaming_get_playback_stream_type(ffado_device_t *dev, int i) {
346     Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, Streaming::Port::E_Playback);
347     if(!p) {
348         debugWarning("Could not get playback port at index %d\n",i);
349         return ffado_stream_type_invalid;
350     }
351     switch(p->getPortType()) {
352     case Streaming::Port::E_Audio:
353         return ffado_stream_type_audio;
354     case Streaming::Port::E_Midi:
355         return ffado_stream_type_midi;
356     case Streaming::Port::E_Control:
357         return ffado_stream_type_control;
358     default:
359         return ffado_stream_type_unknown;
360     }
361 }
362
363 int ffado_streaming_set_audio_datatype(ffado_device_t *dev,
364     ffado_streaming_audio_datatype t) {
365     switch(t) {
366         case ffado_audio_datatype_int24:
367             if(!dev->m_deviceManager->getStreamProcessorManager().setAudioDataType(
368                Streaming::StreamProcessorManager::eADT_Int24)) {
369                 debugError("Could not set datatype\n");
370                 return -1;
371             }
372             break;
373         case ffado_audio_datatype_float:
374             if(!dev->m_deviceManager->getStreamProcessorManager().setAudioDataType(
375                Streaming::StreamProcessorManager::eADT_Float)) {
376                 debugError("Could not set datatype\n");
377                 return -1;
378             }
379             break;
380         default:
381             debugError("Invalid audio datatype\n");
382             return -1;
383     }
384     return 0;
385 }
386
387 ffado_streaming_audio_datatype ffado_streaming_get_audio_datatype(ffado_device_t *dev) {
388     switch(dev->m_deviceManager->getStreamProcessorManager().getAudioDataType()) {
389         case Streaming::StreamProcessorManager::eADT_Int24:
390             return ffado_audio_datatype_int24;
391         case Streaming::StreamProcessorManager::eADT_Float:
392             return ffado_audio_datatype_float;
393         default:
394             debugError("Invalid audio datatype\n");
395             return ffado_audio_datatype_error;
396     }
397 }
398
399 int ffado_streaming_stream_onoff(ffado_device_t *dev, int i,
400     int on, enum Streaming::Port::E_Direction direction) {
401     Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, direction);
402     if(!p) {
403         debugWarning("Could not get %s port at index %d\n",
404             (direction==Streaming::Port::E_Playback?"Playback":"Capture"),i);
405         return -1;
406     }
407     if(on) {
408         p->enable();
409     } else {
410         p->disable();
411     }
412     return 0;
413 }
414
415 int ffado_streaming_playback_stream_onoff(ffado_device_t *dev, int number, int on) {
416     return ffado_streaming_stream_onoff(dev, number, on, Streaming::Port::E_Playback);
417 }
418
419 int ffado_streaming_capture_stream_onoff(ffado_device_t *dev, int number, int on) {
420     return ffado_streaming_stream_onoff(dev, number, on, Streaming::Port::E_Capture);
421 }
422
423 int ffado_streaming_set_capture_stream_buffer(ffado_device_t *dev, int i, char *buff) {
424     Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, Streaming::Port::E_Capture);
425     // use an assert here performancewise,
426     // it should already have failed before, if not correct
427     assert(p);
428     p->setBufferAddress((void *)buff);
429     return 0;
430 }
431
432 int ffado_streaming_set_playback_stream_buffer(ffado_device_t *dev, int i, char *buff) {
433     Streaming::Port *p = dev->m_deviceManager->getStreamProcessorManager().getPortByIndex(i, Streaming::Port::E_Playback);
434     // use an assert here performancewise,
435     // it should already have failed before, if not correct
436     assert(p);
437     p->setBufferAddress((void *)buff);
438     return 0;
439 }
Note: See TracBrowser for help on using the browser.