root/branches/libfreebob-2.0/src/libstreaming/freebob_streaming.cpp

Revision 302, 13.9 kB (checked in by jwoithe, 16 years ago)

jack driver: call detach() from finish() if detach() hasn't yet been called. This works around the fact that jack doesn't call detach() on close at this stage. Once this is fixed in jack the workaround can be removed.
C streaming API: set sample rate before device initialisation. This permits jackd to set the sample rate to that requested on the command line when starting jackd.
Motu device: start adding details to setSamplingFrequency() beyond that required for basic functionality.

Line 
1 /* $Id$ */
2
3 /*
4  *   FreeBob Streaming API
5  *   FreeBob = Firewire (pro-)audio for linux
6  *
7  *   http://freebob.sf.net
8  *
9  *   Copyright (C) 2005,2006 Pieter Palmers <pieterpalmers@users.sourceforge.net>
10  *
11  *   This program is free software {} you can redistribute it and/or modify
12  *   it under the terms of the GNU General Public License as published by
13  *   the Free Software Foundation {} either version 2 of the License, or
14  *   (at your option) any later version.
15  *
16  *   This program is distributed in the hope that it will be useful,
17  *   but WITHOUT ANY WARRANTY {} without even the implied warranty of
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *   GNU General Public License for more details.
20  *
21  *   You should have received a copy of the GNU General Public License
22  *   along with this program {} if not, write to the Free Software
23  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  *
25  *
26  *
27  */
28
29 /* freebob_streaming.c
30  *
31  * Implementation of the FreeBob Streaming API
32  *
33  */
34
35 #include "libfreebob/freebob_streaming.h"
36 #include "../devicemanager.h"
37 #include "../iavdevice.h"
38
39 #include "IsoHandler.h"
40 #include "IsoStream.h"
41 #include "StreamProcessor.h"
42 #include "StreamProcessorManager.h"
43 #include "AmdtpStreamProcessor.h"
44 #include "IsoHandlerManager.h"
45 #include "../libutil/PosixThread.h"
46 #include "AmdtpPort.h"
47
48 #include <assert.h>
49
50 #include <string.h>
51 #include <string>
52
53 /**
54  * Device structure
55  */
56
57 DECLARE_GLOBAL_DEBUG_MODULE;
58
59 using namespace FreebobStreaming;
60
61 struct _freebob_device
62 {       
63         DeviceManager * m_deviceManager;
64         StreamProcessorManager *processorManager;
65
66         freebob_options_t options;
67         freebob_device_info_t device_info;
68 };
69
70 freebob_device_t *freebob_streaming_init (freebob_device_info_t *device_info, freebob_options_t options) {
71         unsigned int i=0;
72
73         struct _freebob_device *dev = new struct _freebob_device;
74
75     debugFatal("%s built %s %s\n", freebob_get_version(), __DATE__, __TIME__);
76
77         if(!dev) {
78                 debugFatal( "Could not allocate streaming device\n" );
79                 return 0;
80         }
81
82         memcpy((void *)&dev->options, (void *)&options, sizeof(dev->options));
83         memcpy((void *)&dev->device_info, (void *)device_info, sizeof(dev->device_info));
84
85         dev->m_deviceManager = new DeviceManager();
86         if ( !dev->m_deviceManager ) {
87                 debugFatal( "Could not allocate device manager\n" );
88                         delete dev;
89                 return 0;
90         }
91         if ( !dev->m_deviceManager->initialize( dev->options.port ) ) {
92                 debugFatal( "Could not initialize device manager\n" );
93                 delete dev->m_deviceManager;
94                         delete dev;
95                 return 0;
96         }
97
98         // create a processor manager to manage the actual stream
99         // processors   
100         dev->processorManager = new StreamProcessorManager(dev->options.period_size,dev->options.nb_buffers);
101         if(!dev->processorManager) {
102                 debugFatal("Could not create StreamProcessorManager\n");
103                 delete dev->m_deviceManager;
104                 delete dev;
105                 return 0;
106         }
107        
108     dev->processorManager->setThreadParameters(dev->options.realtime, dev->options.packetizer_priority);
109        
110         dev->processorManager->setVerboseLevel(DEBUG_LEVEL_VERBOSE);
111         if(!dev->processorManager->init()) {
112                 debugFatal("Could not init StreamProcessorManager\n");
113                 delete dev->processorManager;
114                 delete dev->m_deviceManager;
115                 delete dev;
116                 return 0;
117         }
118
119         // discover the devices on the bus
120         if(!dev->m_deviceManager->discover(DEBUG_LEVEL_VERBOSE)) {
121                 debugOutput(DEBUG_LEVEL_VERBOSE, "Could not discover devices\n");
122                 return 0;
123         }
124
125         // iterate over the found devices
126         // add the stream processors of the devices to the managers
127         for(i=0;i<dev->m_deviceManager->getAvDeviceCount();i++) {
128                 IAvDevice *device=dev->m_deviceManager->getAvDeviceByIndex(i);
129                 assert(device);
130
131                 // Set the device's sampling rate to that requested
132                 // FIXME: does this really belong here?  If so we need to handle errors.
133                 device->setSamplingFrequency(parseSampleRate(dev->options.sample_rate));
134
135                 // prepare the device
136                 device->prepare();
137
138                 int j=0;
139                 for(j=0; j<device->getStreamCount();j++) {
140                         StreamProcessor *streamproc=device->getStreamProcessorByIndex(j);
141                         debugOutput(DEBUG_LEVEL_VERBOSE, "Registering stream processor %d of device %d with processormanager\n",j,i);
142                         if (!dev->processorManager->registerProcessor(streamproc)) {
143                                 debugWarning("Could not register stream processor (%p) with the Processor manager\n",streamproc);
144                         }
145                 }
146         }
147
148         // we are ready!
149        
150         debugOutputShort(DEBUG_LEVEL_VERBOSE, "\n\n");
151         return dev;
152
153 }
154
155 int freebob_streaming_prepare(freebob_device_t *dev) {
156         debugOutput(DEBUG_LEVEL_VERBOSE, "Preparing...\n");
157        
158         dev->processorManager->prepare();
159
160         return true;
161 }
162
163 void freebob_streaming_finish(freebob_device_t *dev) {
164
165         assert(dev);
166
167         delete dev->processorManager;
168         delete dev->m_deviceManager;
169         delete dev;
170
171         return;
172 }
173
174 int freebob_streaming_start(freebob_device_t *dev) {
175         unsigned int i=0;
176         debugOutput(DEBUG_LEVEL_VERBOSE,"------------- Start -------------\n");
177
178        
179         // create the connections for all devices
180         // iterate over the found devices
181         // add the stream processors of the devices to the managers
182         for(i=0;i<dev->m_deviceManager->getAvDeviceCount();i++) {
183                 IAvDevice *device=dev->m_deviceManager->getAvDeviceByIndex(i);
184                 assert(device);
185
186                 int j=0;
187                 for(j=0; j<device->getStreamCount();j++) {
188                 debugOutput(DEBUG_LEVEL_VERBOSE,"Starting stream %d of device %d\n",j,i);
189                         // start the stream
190                         device->startStreamByIndex(j);
191                 }
192         }
193
194         dev->processorManager->start();
195
196         return 0;
197 }
198
199 int freebob_streaming_stop(freebob_device_t *dev) {
200         unsigned int i;
201         debugOutput(DEBUG_LEVEL_VERBOSE,"------------- Stop -------------\n");
202
203         dev->processorManager->stop();
204
205         // create the connections for all devices
206         // iterate over the found devices
207         // add the stream processors of the devices to the managers
208         for(i=0;i<dev->m_deviceManager->getAvDeviceCount();i++) {
209                 IAvDevice *device=dev->m_deviceManager->getAvDeviceByIndex(i);
210                 assert(device);
211                
212
213                 int j=0;
214                 for(j=0; j<device->getStreamCount();j++) {
215                 debugOutput(DEBUG_LEVEL_VERBOSE,"Stopping stream %d of device %d\n",j,i);
216                         // stop the stream
217                         device->stopStreamByIndex(j);
218                 }
219         }
220
221         return 0;
222 }
223
224 int freebob_streaming_reset(freebob_device_t *dev) {
225         debugOutput(DEBUG_LEVEL_VERBOSE,"------------- Reset -------------\n");
226
227 //      dev->processorManager->reset();
228
229         return 0;
230 }
231
232 int freebob_streaming_wait(freebob_device_t *dev) {
233         static int periods=0;
234         static int periods_print=0;
235         static int xruns=0;
236                
237                 periods++;
238                 if(periods>periods_print) {
239                         debugOutput(DEBUG_LEVEL_VERBOSE, "\n");
240                         debugOutput(DEBUG_LEVEL_VERBOSE, "============================================\n");
241                         debugOutput(DEBUG_LEVEL_VERBOSE, "Xruns: %d\n",xruns);
242                         debugOutput(DEBUG_LEVEL_VERBOSE, "============================================\n");
243                         dev->processorManager->dumpInfo();
244 //                      debugOutput(DEBUG_LEVEL_VERBOSE, "--------------------------------------------\n");
245 /*                      quadlet_t *addr=(quadlet_t*)(dev->processorManager->getPortByIndex(0, Port::E_Capture)->getBufferAddress());
246                         if (addr) hexDumpQuadlets(addr,10);*/
247                         debugOutput(DEBUG_LEVEL_VERBOSE, "\n");
248                         periods_print+=100;
249                 }
250         if(dev->processorManager->waitForPeriod()) {
251                 return dev->options.period_size;
252         } else {
253                 debugWarning("XRUN detected\n");
254                 // do xrun recovery
255                
256                 dev->processorManager->handleXrun();
257                 xruns++;
258                 return -1;
259         }
260 }
261
262 int freebob_streaming_transfer_capture_buffers(freebob_device_t *dev) {
263         return dev->processorManager->transfer(StreamProcessor::E_Receive);
264 }
265
266 int freebob_streaming_transfer_playback_buffers(freebob_device_t *dev) {
267         return dev->processorManager->transfer(StreamProcessor::E_Transmit);
268 }
269
270 int freebob_streaming_transfer_buffers(freebob_device_t *dev) {
271         return dev->processorManager->transfer();
272 }
273
274
275 int freebob_streaming_write(freebob_device_t *dev, int i, freebob_sample_t *buffer, int nsamples) {
276 // debugFatal("Not implemented\n");
277         Port *p=dev->processorManager->getPortByIndex(i, Port::E_Playback);
278         // use an assert here performancewise,
279         // it should already have failed before, if not correct
280         assert(p);
281        
282         return p->writeEvents((void *)buffer, nsamples);
283 }
284
285 int freebob_streaming_read(freebob_device_t *dev, int i, freebob_sample_t *buffer, int nsamples) {
286         Port *p=dev->processorManager->getPortByIndex(i, Port::E_Capture);
287         // use an assert here performancewise,
288         // it should already have failed before, if not correct
289         assert(p);
290        
291         return p->readEvents((void *)buffer, nsamples);
292 }
293
294 pthread_t freebob_streaming_get_packetizer_thread(freebob_device_t *dev) {
295 //      debugFatal("Not implemented\n");
296         return 0;
297 }
298
299
300 int freebob_streaming_get_nb_capture_streams(freebob_device_t *dev) {
301         return dev->processorManager->getPortCount(Port::E_Capture);
302 }
303
304 int freebob_streaming_get_nb_playback_streams(freebob_device_t *dev) {
305         return dev->processorManager->getPortCount(Port::E_Playback);
306 }
307
308 int freebob_streaming_get_capture_stream_name(freebob_device_t *dev, int i, char* buffer, size_t buffersize) {
309         Port *p=dev->processorManager->getPortByIndex(i, Port::E_Capture);
310         if(!p) {
311                 debugWarning("Could not get capture port at index %d\n",i);
312                 return -1;
313         }
314
315         std::string name=p->getName();
316         if (!strncpy(buffer, name.c_str(), buffersize)) {
317                 debugWarning("Could not copy name\n");
318                 return -1;
319         } else return 0;
320 }
321
322 int freebob_streaming_get_playback_stream_name(freebob_device_t *dev, int i, char* buffer, size_t buffersize) {
323        
324         Port *p=dev->processorManager->getPortByIndex(i, Port::E_Playback);
325         if(!p) {
326                 debugWarning("Could not get playback port at index %d\n",i);
327                 return -1;
328         }
329
330         std::string name=p->getName();
331         if (!strncpy(buffer, name.c_str(), buffersize)) {
332                 debugWarning("Could not copy name\n");
333                 return -1;
334         } else return 0;
335 }
336
337 freebob_streaming_stream_type freebob_streaming_get_capture_stream_type(freebob_device_t *dev, int i) {
338         Port *p=dev->processorManager->getPortByIndex(i, Port::E_Capture);
339         if(!p) {
340                 debugWarning("Could not get capture port at index %d\n",i);
341                 return freebob_stream_type_invalid;
342         }
343         switch(p->getPortType()) {
344         case Port::E_Audio:
345                 return freebob_stream_type_audio;
346         case Port::E_Midi:
347                 return freebob_stream_type_midi;
348         case Port::E_Control:
349                 return freebob_stream_type_control;
350         default:
351                 return freebob_stream_type_unknown;
352         }
353 }
354
355 freebob_streaming_stream_type freebob_streaming_get_playback_stream_type(freebob_device_t *dev, int i) {
356         Port *p=dev->processorManager->getPortByIndex(i, Port::E_Playback);
357         if(!p) {
358                 debugWarning("Could not get playback port at index %d\n",i);
359                 return freebob_stream_type_invalid;
360         }
361         switch(p->getPortType()) {
362         case Port::E_Audio:
363                 return freebob_stream_type_audio;
364         case Port::E_Midi:
365                 return freebob_stream_type_midi;
366         case Port::E_Control:
367                 return freebob_stream_type_control;
368         default:
369                 return freebob_stream_type_unknown;
370         }
371 }
372
373 int freebob_streaming_set_stream_buffer_type(freebob_device_t *dev, int i,
374         freebob_streaming_buffer_type t, enum Port::E_Direction direction) {
375
376         Port *p=dev->processorManager->getPortByIndex(i, direction);
377         if(!p) {
378                 debugWarning("Could not get %s port at index %d\n",
379                       (direction==Port::E_Playback?"Playback":"Capture"),i);
380                 return -1;
381         }
382        
383         switch(t) {
384         case freebob_buffer_type_int24:
385            if (!p->setDataType(Port::E_Int24)) {
386                debugWarning("%s: Could not set data type to Int24\n",p->getName().c_str());
387                return -1;
388            }
389            if (!p->setBufferType(Port::E_PointerBuffer)) {
390                debugWarning("%s: Could not set buffer type to Pointerbuffer\n",p->getName().c_str());
391                return -1;
392            }
393            break;
394         case freebob_buffer_type_float:
395            if (!p->setDataType(Port::E_Float)) {
396                debugWarning("%s: Could not set data type to Float\n",p->getName().c_str());
397                return -1;
398            }
399            if (!p->setBufferType(Port::E_PointerBuffer)) {
400                debugWarning("%s: Could not set buffer type to Pointerbuffer\n",p->getName().c_str());
401                return -1;
402            }
403            break;
404         case freebob_buffer_type_midi:
405            if (!p->setDataType(Port::E_MidiEvent)) {
406                debugWarning("%s: Could not set data type to MidiEvent\n",p->getName().c_str());
407                return -1;
408            }
409            if (!p->setBufferType(Port::E_RingBuffer)) {
410                debugWarning("%s: Could not set buffer type to Ringbuffer\n",p->getName().c_str());
411                return -1;
412            }
413            break;
414         default:
415        debugWarning("%s: Unsupported buffer type\n",p->getName().c_str());
416        return -1;
417         }
418     return 0;
419
420 }
421
422 int freebob_streaming_set_playback_buffer_type(freebob_device_t *dev, int i, freebob_streaming_buffer_type t) {
423     return freebob_streaming_set_stream_buffer_type(dev, i, t, Port::E_Playback);
424 }
425
426 int freebob_streaming_set_capture_buffer_type(freebob_device_t *dev, int i, freebob_streaming_buffer_type t) {
427     return freebob_streaming_set_stream_buffer_type(dev, i, t, Port::E_Capture);
428 }
429
430 int freebob_streaming_stream_onoff(freebob_device_t *dev, int i,
431         int on, enum Port::E_Direction direction) {
432         Port *p=dev->processorManager->getPortByIndex(i, direction);
433         if(!p) {
434                 debugWarning("Could not get %s port at index %d\n",
435                       (direction==Port::E_Playback?"Playback":"Capture"),i);
436                 return -1;
437         }
438         if(on) {
439            p->enable();
440         } else {
441            p->disable();
442         }
443         return 0;
444 }
445
446 int freebob_streaming_playback_stream_onoff(freebob_device_t *dev, int number, int on) {
447     return freebob_streaming_stream_onoff(dev, number, on, Port::E_Playback);
448 }
449
450 int freebob_streaming_capture_stream_onoff(freebob_device_t *dev, int number, int on) {
451     return freebob_streaming_stream_onoff(dev, number, on, Port::E_Capture);
452 }
453
454 // TODO: the way port buffers are set in the C api doesn't satisfy me
455 int freebob_streaming_set_capture_stream_buffer(freebob_device_t *dev, int i, char *buff) {
456         Port *p=dev->processorManager->getPortByIndex(i, Port::E_Capture);
457        
458         // use an assert here performancewise,
459         // it should already have failed before, if not correct
460         assert(p);
461        
462         p->useExternalBuffer(true);
463         p->setExternalBufferAddress((void *)buff);
464
465         return 0;
466
467 }
468
469 int freebob_streaming_set_playback_stream_buffer(freebob_device_t *dev, int i, char *buff) {
470         Port *p=dev->processorManager->getPortByIndex(i, Port::E_Playback);
471         // use an assert here performancewise,
472         // it should already have failed before, if not correct
473         assert(p);
474        
475         p->useExternalBuffer(true);
476         p->setExternalBufferAddress((void *)buff);
477
478         return 0;
479 }
480
Note: See TracBrowser for help on using the browser.