root/trunk/libffado/src/ffado_streaming.cpp

Revision 554, 17.4 kB (checked in by ppalmers, 17 years ago)

Merge echoaudio branch into trunk.

This adds support for the Echo Audiofire devices to FFADO. Possibly also other devices working with the Apple Class Driver will work with this code. It is not fully complete yet, but the main rework is
done.

First of all the IAvDevice class/interface is renamed to FFADODevice, in order to separate the AV/C code from the FFADO API code. A device supported by FFADO implements a FFADODevice.

The BeBoB device has been split up into three groups:
- libavc/* : all code and commands that are specified by AV/C specs. Note that a lot of the code that used to be in BeBoB::AvDevice? now resides in AVC::Unit
- genericavc/* : a FFADODevice that uses AV/C descriptors & commands for discovery and config
- bebob/* : the bebob FFADODevice that inherits from GenericAVC::AvDevice? but that uses BridgeCo? commands for discovery

Everything has been moved as high as possible in the class hierarchy. If necessary, a subclass that uses device specific commands is introduced (e.g. BeBoB::Plug inherits from AVC::Plug and uses the
BridgeCo? extended plug info command to discover it's properties).

There are some other fixes along the way that have been done too.

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