root/branches/ppalmers-streaming/src/ffado_streaming.cpp

Revision 719, 17.7 kB (checked in by ppalmers, 15 years ago)

backup 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 "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_NORMAL);
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,
89                                                         dev->options.sample_rate,
90                                                         dev->options.nb_buffers);
91     if(!dev->processorManager) {
92             debugFatal("Could not create StreamProcessorManager\n");
93             delete dev->m_deviceManager;
94             delete dev;
95             return 0;
96     }
97
98     dev->processorManager->setThreadParameters(dev->options.realtime, dev->options.packetizer_priority);
99
100     dev->processorManager->setVerboseLevel(DEBUG_LEVEL_VERBOSE);
101     if(!dev->processorManager->init()) {
102             debugFatal("Could not init StreamProcessorManager\n");
103             delete dev->processorManager;
104             delete dev->m_deviceManager;
105             delete dev;
106             return 0;
107     }
108
109     // set slave mode option
110     bool slaveMode=(dev->options.slave_mode != 0);
111     debugOutput(DEBUG_LEVEL_VERBOSE, "setting slave mode to %d\n", slaveMode);
112     if(!dev->m_deviceManager->setOption("slaveMode", slaveMode)) {
113             debugWarning("Failed to set slave mode option\n");
114     }
115     // set snoop mode option
116     bool snoopMode=(dev->options.snoop_mode != 0);
117     debugOutput(DEBUG_LEVEL_VERBOSE, "setting snoop mode to %d\n", snoopMode);
118     if(!dev->m_deviceManager->setOption("snoopMode", snoopMode)) {
119             debugWarning("Failed to set snoop mode option\n");
120     }
121
122     // discover the devices on the bus
123     if(!dev->m_deviceManager->discover()) {
124             debugFatal("Could not discover devices\n");
125             delete dev->processorManager;
126             delete dev->m_deviceManager;
127             delete dev;
128             return 0;
129     }
130
131     // are there devices on the bus?
132     if(dev->m_deviceManager->getAvDeviceCount()==0) {
133             debugFatal("There are no devices on the bus\n");
134             delete dev->processorManager;
135             delete dev->m_deviceManager;
136             delete dev;
137             return 0;
138     }
139
140     // iterate over the found devices
141     // add the stream processors of the devices to the managers
142     for(i=0;i<dev->m_deviceManager->getAvDeviceCount();i++) {
143         FFADODevice *device=dev->m_deviceManager->getAvDeviceByIndex(i);
144         assert(device);
145
146         debugOutput(DEBUG_LEVEL_VERBOSE, "Locking device (%p)\n", device);
147
148         if (!device->lock()) {
149             debugWarning("Could not lock device, skipping device (%p)!\n", device);
150             continue;
151         }
152
153         debugOutput(DEBUG_LEVEL_VERBOSE, "Setting samplerate to %d for (%p)\n",
154                     dev->options.sample_rate, device);
155
156         // Set the device's sampling rate to that requested
157         // FIXME: does this really belong here?  If so we need to handle errors.
158         if (!device->setSamplingFrequency(dev->options.sample_rate)) {
159             debugOutput(DEBUG_LEVEL_VERBOSE, " => Retry setting samplerate to %d for (%p)\n",
160                         dev->options.sample_rate, device);
161
162             // try again:
163             if (!device->setSamplingFrequency(dev->options.sample_rate)) {
164                 delete dev->processorManager;
165                 delete dev->m_deviceManager;
166                 delete dev;
167                 debugFatal("Could not set sampling frequency to %d\n",dev->options.sample_rate);
168                 return 0;
169             }
170         }
171
172         // prepare the device
173         device->prepare();
174         int j=0;
175         for(j=0; j<device->getStreamCount();j++) {
176             StreamProcessor *streamproc=device->getStreamProcessorByIndex(j);
177             debugOutput(DEBUG_LEVEL_VERBOSE, "Registering stream processor %d of device %d with processormanager\n",j,i);
178             if (!dev->processorManager->registerProcessor(streamproc)) {
179                 delete dev->processorManager;
180                 delete dev->m_deviceManager;
181                 delete dev;
182                 debugFatal("Could not register stream processor (%p) with the Processor manager\n", streamproc);
183                 return 0;
184             }
185         }
186     }
187
188     // set the sync source
189     if (!dev->processorManager->setSyncSource(dev->m_deviceManager->getSyncSource())) {
190         debugWarning("Could not set processorManager sync source (%p)\n",
191             dev->m_deviceManager->getSyncSource());
192     }
193
194     // we are ready!
195     debugOutputShort(DEBUG_LEVEL_VERBOSE, "\n\n");
196     return dev;
197
198 }
199
200 int ffado_streaming_prepare(ffado_device_t *dev) {
201     debugOutput(DEBUG_LEVEL_VERBOSE, "Preparing...\n");
202
203     if (!dev->processorManager->prepare()) {
204         debugFatal("Could not prepare streaming...\n");
205         return false;
206     }
207
208     return true;
209 }
210
211 void ffado_streaming_finish(ffado_device_t *dev) {
212     unsigned int i=0;
213
214     assert(dev);
215
216     // iterate over the found devices
217     for(i=0;i<dev->m_deviceManager->getAvDeviceCount();i++) {
218         FFADODevice *device=dev->m_deviceManager->getAvDeviceByIndex(i);
219         assert(device);
220
221         debugOutput(DEBUG_LEVEL_VERBOSE, "Unlocking device (%p)\n", device);
222
223         if (!device->unlock()) {
224             debugWarning("Could not unlock device (%p)!\n", device);
225         }
226     }
227
228     delete dev->processorManager;
229     delete dev->m_deviceManager;
230     delete dev;
231
232     return;
233 }
234
235 int ffado_streaming_start(ffado_device_t *dev) {
236     unsigned int i=0;
237     debugOutput(DEBUG_LEVEL_VERBOSE,"------------- Start -------------\n");
238
239     // create the connections for all devices
240     // iterate over the found devices
241     // add the stream processors of the devices to the managers
242     for(i=0;i<dev->m_deviceManager->getAvDeviceCount();i++) {
243         FFADODevice *device=dev->m_deviceManager->getAvDeviceByIndex(i);
244         assert(device);
245
246         int j=0;
247         for(j=0; j<device->getStreamCount();j++) {
248         debugOutput(DEBUG_LEVEL_VERBOSE,"Starting stream %d of device %d\n",j,i);
249             // start the stream
250             if (!device->startStreamByIndex(j)) {
251                 debugWarning("Could not start stream %d of device %d\n",j,i);
252                 continue;
253             }
254         }
255
256         if (!device->enableStreaming()) {
257             debugWarning("Could not enable streaming on device %d!\n",i);
258         }
259     }
260
261     if(dev->processorManager->start()) {
262         return 0;
263     } else {
264         ffado_streaming_stop(dev);
265         return -1;
266     }
267 }
268
269 int ffado_streaming_stop(ffado_device_t *dev) {
270     unsigned int i;
271     debugOutput(DEBUG_LEVEL_VERBOSE,"------------- Stop -------------\n");
272
273     dev->processorManager->stop();
274
275     // create the connections for all devices
276     // iterate over the found devices
277     // add the stream processors of the devices to the managers
278     for(i=0;i<dev->m_deviceManager->getAvDeviceCount();i++) {
279         FFADODevice *device=dev->m_deviceManager->getAvDeviceByIndex(i);
280         assert(device);
281
282         if (!device->disableStreaming()) {
283             debugWarning("Could not disable streaming on device %d!\n",i);
284         }
285
286         int j=0;
287         for(j=0; j<device->getStreamCount();j++) {
288             debugOutput(DEBUG_LEVEL_VERBOSE,"Stopping stream %d of device %d\n",j,i);
289             // stop the stream
290             // start the stream
291             if (!device->stopStreamByIndex(j)) {
292                 debugWarning("Could not stop stream %d of device %d\n",j,i);
293                 continue;
294             }
295         }
296     }
297
298     return 0;
299 }
300
301 int ffado_streaming_reset(ffado_device_t *dev) {
302     debugOutput(DEBUG_LEVEL_VERBOSE,"------------- Reset -------------\n");
303
304     // dev->processorManager->reset();
305
306     return 0;
307 }
308
309 int ffado_streaming_wait(ffado_device_t *dev) {
310     static int periods=0;
311     static int periods_print=0;
312     static int xruns=0;
313
314     periods++;
315     if(periods>periods_print) {
316         debugOutputShort(DEBUG_LEVEL_VERBOSE, "\nffado_streaming_wait\n");
317         debugOutputShort(DEBUG_LEVEL_VERBOSE, "============================================\n");
318         debugOutputShort(DEBUG_LEVEL_VERBOSE, "Xruns: %d\n",xruns);
319         debugOutputShort(DEBUG_LEVEL_VERBOSE, "============================================\n");
320         dev->processorManager->dumpInfo();
321         debugOutputShort(DEBUG_LEVEL_VERBOSE, "\n");
322         periods_print+=100;
323     }
324
325     if(dev->processorManager->waitForPeriod()) {
326         return dev->options.period_size;
327     } else {
328         debugWarning("XRUN detected\n");
329
330         // do xrun recovery
331         dev->processorManager->handleXrun();
332         xruns++;
333         return -1;
334     }
335 }
336
337 int ffado_streaming_transfer_capture_buffers(ffado_device_t *dev) {
338     return dev->processorManager->transfer(StreamProcessor::ePT_Receive);
339 }
340
341 int ffado_streaming_transfer_playback_buffers(ffado_device_t *dev) {
342     return dev->processorManager->transfer(StreamProcessor::ePT_Transmit);
343 }
344
345 int ffado_streaming_transfer_buffers(ffado_device_t *dev) {
346     return dev->processorManager->transfer();
347 }
348
349
350 int ffado_streaming_write(ffado_device_t *dev, int i, ffado_sample_t *buffer, int nsamples) {
351     Port *p=dev->processorManager->getPortByIndex(i, Port::E_Playback);
352     // use an assert here performancewise,
353     // it should already have failed before, if not correct
354     assert(p);
355
356     return p->writeEvents((void *)buffer, nsamples);
357 }
358
359 int ffado_streaming_read(ffado_device_t *dev, int i, ffado_sample_t *buffer, int nsamples) {
360     Port *p=dev->processorManager->getPortByIndex(i, Port::E_Capture);
361     // use an assert here performancewise,
362     // it should already have failed before, if not correct
363     assert(p);
364
365     return p->readEvents((void *)buffer, nsamples);
366 }
367
368 int ffado_streaming_get_nb_capture_streams(ffado_device_t *dev) {
369     return dev->processorManager->getPortCount(Port::E_Capture);
370 }
371
372 int ffado_streaming_get_nb_playback_streams(ffado_device_t *dev) {
373     return dev->processorManager->getPortCount(Port::E_Playback);
374 }
375
376 int ffado_streaming_get_capture_stream_name(ffado_device_t *dev, int i, char* buffer, size_t buffersize) {
377     Port *p=dev->processorManager->getPortByIndex(i, Port::E_Capture);
378     if(!p) {
379         debugWarning("Could not get capture port at index %d\n",i);
380         return -1;
381     }
382
383     std::string name=p->getName();
384     if (!strncpy(buffer, name.c_str(), buffersize)) {
385         debugWarning("Could not copy name\n");
386         return -1;
387     } else return 0;
388 }
389
390 int ffado_streaming_get_playback_stream_name(ffado_device_t *dev, int i, char* buffer, size_t buffersize) {
391     Port *p=dev->processorManager->getPortByIndex(i, Port::E_Playback);
392     if(!p) {
393         debugWarning("Could not get playback port at index %d\n",i);
394         return -1;
395     }
396
397     std::string name=p->getName();
398     if (!strncpy(buffer, name.c_str(), buffersize)) {
399         debugWarning("Could not copy name\n");
400         return -1;
401     } else return 0;
402 }
403
404 ffado_streaming_stream_type ffado_streaming_get_capture_stream_type(ffado_device_t *dev, int i) {
405     Port *p=dev->processorManager->getPortByIndex(i, Port::E_Capture);
406     if(!p) {
407         debugWarning("Could not get capture port at index %d\n",i);
408         return ffado_stream_type_invalid;
409     }
410     switch(p->getPortType()) {
411     case Port::E_Audio:
412         return ffado_stream_type_audio;
413     case Port::E_Midi:
414         return ffado_stream_type_midi;
415     case Port::E_Control:
416         return ffado_stream_type_control;
417     default:
418         return ffado_stream_type_unknown;
419     }
420 }
421
422 ffado_streaming_stream_type ffado_streaming_get_playback_stream_type(ffado_device_t *dev, int i) {
423     Port *p=dev->processorManager->getPortByIndex(i, Port::E_Playback);
424     if(!p) {
425         debugWarning("Could not get playback port at index %d\n",i);
426         return ffado_stream_type_invalid;
427     }
428     switch(p->getPortType()) {
429     case Port::E_Audio:
430         return ffado_stream_type_audio;
431     case Port::E_Midi:
432         return ffado_stream_type_midi;
433     case Port::E_Control:
434         return ffado_stream_type_control;
435     default:
436         return ffado_stream_type_unknown;
437     }
438 }
439
440 int ffado_streaming_set_stream_buffer_type(ffado_device_t *dev, int i,
441     ffado_streaming_buffer_type t, enum Port::E_Direction direction) {
442
443     Port *p=dev->processorManager->getPortByIndex(i, direction);
444     if(!p) {
445         debugWarning("Could not get %s port at index %d\n",
446             (direction==Port::E_Playback?"Playback":"Capture"),i);
447         return -1;
448     }
449
450     switch(t) {
451     case ffado_buffer_type_int24:
452         if (!p->setDataType(Port::E_Int24)) {
453             debugWarning("%s: Could not set data type to Int24\n",p->getName().c_str());
454             return -1;
455         }
456         if (!p->setBufferType(Port::E_PointerBuffer)) {
457             debugWarning("%s: Could not set buffer type to Pointerbuffer\n",p->getName().c_str());
458             return -1;
459         }
460         break;
461     case ffado_buffer_type_float:
462         if (!p->setDataType(Port::E_Float)) {
463             debugWarning("%s: Could not set data type to Float\n",p->getName().c_str());
464             return -1;
465         }
466         if (!p->setBufferType(Port::E_PointerBuffer)) {
467             debugWarning("%s: Could not set buffer type to Pointerbuffer\n",p->getName().c_str());
468             return -1;
469         }
470         break;
471     case ffado_buffer_type_midi:
472         if (!p->setDataType(Port::E_MidiEvent)) {
473             debugWarning("%s: Could not set data type to MidiEvent\n",p->getName().c_str());
474             return -1;
475         }
476         if (!p->setBufferType(Port::E_RingBuffer)) {
477             debugWarning("%s: Could not set buffer type to Ringbuffer\n",p->getName().c_str());
478             return -1;
479         }
480         break;
481     default:
482         debugWarning("%s: Unsupported buffer type\n",p->getName().c_str());
483         return -1;
484     }
485     return 0;
486
487 }
488
489 int ffado_streaming_set_playback_buffer_type(ffado_device_t *dev, int i, ffado_streaming_buffer_type t) {
490     return ffado_streaming_set_stream_buffer_type(dev, i, t, Port::E_Playback);
491 }
492
493 int ffado_streaming_set_capture_buffer_type(ffado_device_t *dev, int i, ffado_streaming_buffer_type t) {
494     return ffado_streaming_set_stream_buffer_type(dev, i, t, Port::E_Capture);
495 }
496
497 int ffado_streaming_stream_onoff(ffado_device_t *dev, int i,
498     int on, enum Port::E_Direction direction) {
499     Port *p=dev->processorManager->getPortByIndex(i, direction);
500     if(!p) {
501         debugWarning("Could not get %s port at index %d\n",
502             (direction==Port::E_Playback?"Playback":"Capture"),i);
503         return -1;
504     }
505     if(on) {
506         p->enable();
507     } else {
508         p->disable();
509     }
510     return 0;
511 }
512
513 int ffado_streaming_playback_stream_onoff(ffado_device_t *dev, int number, int on) {
514     return ffado_streaming_stream_onoff(dev, number, on, Port::E_Playback);
515 }
516
517 int ffado_streaming_capture_stream_onoff(ffado_device_t *dev, int number, int on) {
518     return ffado_streaming_stream_onoff(dev, number, on, Port::E_Capture);
519 }
520
521 // TODO: the way port buffers are set in the C api doesn't satisfy me
522 int ffado_streaming_set_capture_stream_buffer(ffado_device_t *dev, int i, char *buff) {
523         Port *p=dev->processorManager->getPortByIndex(i, Port::E_Capture);
524
525         // use an assert here performancewise,
526         // it should already have failed before, if not correct
527         assert(p);
528
529         p->useExternalBuffer(true);
530         p->setExternalBufferAddress((void *)buff);
531
532         return 0;
533
534 }
535
536 int ffado_streaming_set_playback_stream_buffer(ffado_device_t *dev, int i, char *buff) {
537         Port *p=dev->processorManager->getPortByIndex(i, Port::E_Playback);
538         // use an assert here performancewise,
539         // it should already have failed before, if not correct
540         assert(p);
541
542         p->useExternalBuffer(true);
543         p->setExternalBufferAddress((void *)buff);
544
545         return 0;
546 }
547
Note: See TracBrowser for help on using the browser.