root/trunk/libffado/src/ffado_streaming.cpp

Revision 494, 17.5 kB (checked in by ppalmers, 14 years ago)

- switch over to a generic ffado_timestamp_t for the timestamped buffer (currently float)
- implemented some experimental stream phase sync method

- various small things

NOTE: not a very stable commit

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 "iavdevice.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         IAvDevice *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(parseSampleRate(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(parseSampleRate(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         IAvDevice *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         IAvDevice *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         IAvDevice *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.