root/trunk/libffado/src/libstreaming/Port.cpp

Revision 445, 14.1 kB (checked in by pieterpalmers, 15 years ago)

* name change from FreeBoB to FFADO
* replaced tabs by 4 spaces
* got rid of end-of-line spaces
* made all license and copyrights conform

library becomes LGPL, apps become GPL
explicitly state LGPL v2.1 and GPL v2 (don't like v3 draft)

copyrights are 2005-2007 Daniel & Pieter
except for the MotU stuff (C) Jonathan, Pieter

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 #include "Port.h"
25 #include <stdlib.h>
26 #include <assert.h>
27
28 namespace Streaming {
29
30 IMPL_DEBUG_MODULE( Port, Port, DEBUG_LEVEL_NORMAL );
31
32 Port::Port(std::string name, enum E_PortType porttype, enum E_Direction direction)
33       : m_Name(name),
34     m_SignalType(E_PeriodSignalled),
35     m_BufferType(E_PointerBuffer),
36     m_disabled(true),
37     m_initialized(false),
38     m_buffersize(0),
39     m_eventsize(0),
40     m_DataType(E_Int24),
41     m_PortType(porttype),
42     m_Direction(direction),
43     m_buffer(0),
44     m_ringbuffer(0),
45     m_use_external_buffer(false),
46     m_do_ratecontrol(false),
47     m_event_interval(0),
48     m_slot_interval(0),
49     m_rate_counter(0),
50     m_rate_counter_minimum(0),
51     m_average_ratecontrol(false)
52
53 {
54
55 }
56
57 /**
58  * The idea is that you set all port parameters, and then initialize the port.
59  * This allocates all resources and makes the port usable. However, you can't
60  * change the port properties anymore after this.
61  *
62  * @return true if successfull. false if not (all resources are freed).
63  */
64 bool Port::init() {
65     if (m_initialized) {
66         debugFatal("Port already initialized... (%s)\n",m_Name.c_str());
67         return false;
68     }
69
70     if (m_buffersize==0) {
71         debugFatal("Cannot initialize a port with buffersize=0\n");
72         return false;
73     }
74
75     switch (m_BufferType) {
76         case E_PointerBuffer:
77             if (m_use_external_buffer) {
78                 // don't do anything
79             } else if (!allocateInternalBuffer()) {
80                 debugFatal("Could not allocate internal buffer!\n");
81                 return false;
82             }
83             break;
84
85         case E_RingBuffer:
86             if (m_use_external_buffer) {
87                 debugFatal("Cannot use an external ringbuffer! \n");
88                 return false;
89             } else if (!allocateInternalRingBuffer()) {
90                 debugFatal("Could not allocate internal ringbuffer!\n");
91                 return false;
92             }
93             break;
94         default:
95             debugFatal("Unsupported buffer type! (%d)\n",(int)m_BufferType);
96             return false;
97             break;
98     }
99
100     m_initialized=true;
101
102     m_eventsize=getEventSize(); // this won't change, so cache it
103
104     return m_initialized;
105 }
106
107 bool Port::reset() {
108     if (m_BufferType==E_RingBuffer) {
109         ffado_ringbuffer_reset(m_ringbuffer);
110     }
111     return true;
112 };
113
114
115 void Port::setVerboseLevel(int l) {
116     setDebugLevel(l);
117 }
118
119 bool Port::setName(std::string name) {
120     debugOutput( DEBUG_LEVEL_VERBOSE, "Setting name to %s for port %s\n",name.c_str(),m_Name.c_str());
121
122     if (m_initialized) {
123         debugFatal("Port already initialized... (%s)\n",m_Name.c_str());
124         return false;
125     }
126
127     m_Name=name;
128
129     return true;
130 }
131
132 bool Port::setBufferSize(unsigned int newsize) {
133     debugOutput( DEBUG_LEVEL_VERBOSE, "Setting buffersize to %d for port %s\n",newsize,m_Name.c_str());
134     if (m_initialized) {
135         debugFatal("Port already initialized... (%s)\n",m_Name.c_str());
136         return false;
137     }
138
139     m_buffersize=newsize;
140     return true;
141
142 }
143
144 unsigned int Port::getEventSize() {
145     switch (m_DataType) {
146         case E_Float:
147             return sizeof(float);
148         case E_Int24: // 24 bit 2's complement, packed in a 32bit integer (LSB's)
149             return sizeof(uint32_t);
150         case E_MidiEvent:
151             return sizeof(uint32_t);
152         default:
153             return 0;
154     }
155 }
156
157 bool Port::setDataType(enum E_DataType d) {
158     debugOutput( DEBUG_LEVEL_VERBOSE, "Setting datatype to %d for port %s\n",(int) d,m_Name.c_str());
159     if (m_initialized) {
160         debugFatal("Port already initialized... (%s)\n",m_Name.c_str());
161         return false;
162     }
163
164     // do some sanity checks
165     bool type_is_ok=false;
166     switch (m_PortType) {
167         case E_Audio:
168             if(d == E_Int24) type_is_ok=true;
169             if(d == E_Float) type_is_ok=true;
170             break;
171         case E_Midi:
172             if(d == E_MidiEvent) type_is_ok=true;
173             break;
174         case E_Control:
175             if(d == E_Default) type_is_ok=true;
176             break;
177         default:
178             break;
179     }
180
181     if(!type_is_ok) {
182         debugFatal("Datatype not supported by this type of port!\n");
183         return false;
184     }
185
186     m_DataType=d;
187     return true;
188 }
189
190 bool Port::setSignalType(enum E_SignalType s) {
191     debugOutput( DEBUG_LEVEL_VERBOSE, "Setting signaltype to %d for port %s\n",(int)s,m_Name.c_str());
192     if (m_initialized) {
193         debugFatal("Port already initialized... (%s)\n",m_Name.c_str());
194         return false;
195     }
196
197     // do some sanity checks
198     bool type_is_ok=false;
199     switch (m_PortType) {
200         case E_Audio:
201             if(s == E_PeriodSignalled) type_is_ok=true;
202             break;
203         case E_Midi:
204             if(s == E_PacketSignalled) type_is_ok=true;
205             break;
206         case E_Control:
207             if(s == E_PeriodSignalled) type_is_ok=true;
208             break;
209         default:
210             break;
211     }
212
213     if(!type_is_ok) {
214         debugFatal("Signalling type not supported by this type of port!\n");
215         return false;
216     }
217
218     m_SignalType=s;
219     return true;
220
221 }
222
223 bool Port::setBufferType(enum E_BufferType b) {
224     debugOutput( DEBUG_LEVEL_VERBOSE, "Setting buffer type to %d for port %s\n",(int)b,m_Name.c_str());
225     if (m_initialized) {
226         debugFatal("Port already initialized... (%s)\n",m_Name.c_str());
227         return false;
228     }
229
230     // do some sanity checks
231     bool type_is_ok=false;
232     switch (m_PortType) {
233         case E_Audio:
234             if(b == E_PointerBuffer) type_is_ok=true;
235             break;
236         case E_Midi:
237             if(b == E_RingBuffer) type_is_ok=true;
238             break;
239         case E_Control:
240             break;
241         default:
242             break;
243     }
244
245     if(!type_is_ok) {
246         debugFatal("Buffer type not supported by this type of port!\n");
247         return false;
248     }
249
250     m_BufferType=b;
251     return true;
252
253 }
254
255 bool Port::useExternalBuffer(bool b) {
256
257     // If called on an initialised stream but the request isn't for a change silently
258     // allow it (relied on by C API as used by jack backend driver)
259     if (m_initialized && m_use_external_buffer==b)
260         return true;
261
262     debugOutput( DEBUG_LEVEL_VERBOSE, "Setting external buffer use to %d for port %s\n",(int)b,m_Name.c_str());
263
264     if (m_initialized) {
265         debugFatal("Port already initialized... (%s)\n",m_Name.c_str());
266         return false;
267     }
268
269     m_use_external_buffer=b;
270     return true;
271 }
272
273 // buffer handling api's for pointer buffers
274 /**
275  * Get the buffer address (being the external or the internal one).
276  *
277  * @param buff
278  */
279 void *Port::getBufferAddress() {
280     assert(m_BufferType==E_PointerBuffer);
281     return m_buffer;
282 };
283
284 /**
285  * Set the external buffer address.
286  * only call this when specifying an external buffer before init()
287  *
288  * @param buff
289  */
290 void Port::setExternalBufferAddress(void *buff) {
291     assert(m_BufferType==E_PointerBuffer);
292     assert(m_use_external_buffer); // don't call this with an internal buffer!
293     m_buffer=buff;
294 };
295
296 // buffer handling api's for ringbuffers
297 bool Port::writeEvent(void *event) {
298     assert(m_BufferType==E_RingBuffer);
299     assert(m_ringbuffer);
300
301     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Writing event %08X with size %d to port %s\n",*((quadlet_t *)event),m_eventsize, m_Name.c_str());
302
303     return (ffado_ringbuffer_write(m_ringbuffer, (char *)event, m_eventsize)==m_eventsize);
304 }
305
306 bool Port::readEvent(void *event) {
307     assert(m_ringbuffer);
308
309     unsigned int read=ffado_ringbuffer_read(m_ringbuffer, (char *)event, m_eventsize);
310
311     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Reading event %X with size %d from port %s\n",*((quadlet_t *)event),m_eventsize,m_Name.c_str());
312     return (read==m_eventsize);
313 }
314
315 int Port::writeEvents(void *event, unsigned int nevents) {
316     assert(m_BufferType==E_RingBuffer);
317     assert(m_ringbuffer);
318
319     unsigned int bytes2write=m_eventsize*nevents;
320
321     unsigned int written=ffado_ringbuffer_write(m_ringbuffer, (char *)event,bytes2write)/m_eventsize;
322
323 #ifdef DEBUG
324     if(written) {
325         unsigned int i=0;
326         quadlet_t * tmp=(quadlet_t *)event;
327         debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Written %d events (",written);
328         for (i=0;i<written;i++) {
329             debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, "%X ", *(tmp+i));
330         }
331         debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, ") to port %s\n",m_Name.c_str());
332     }
333 #endif
334
335     return written;
336
337 }
338
339 int Port::readEvents(void *event, unsigned int nevents) {
340     assert(m_ringbuffer);
341
342     unsigned int bytes2read=m_eventsize*nevents;
343
344     unsigned int read=ffado_ringbuffer_read(m_ringbuffer, (char *)event, bytes2read)/m_eventsize;
345
346 #ifdef DEBUG
347     if(read) {
348         unsigned int i=0;
349         quadlet_t * tmp=(quadlet_t *)event;
350         debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Read %d events (",read);
351         for (i=0;i<read;i++) {
352             debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, "%X ", *(tmp+i));
353         }
354         debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, ") from port %s\n",m_Name.c_str());
355     }
356 #endif
357
358     return read;
359 }
360
361 /* rate control */
362 bool Port::canRead() {
363     bool byte_present_in_buffer;
364
365     bool retval=false;
366
367     assert(m_ringbuffer);
368
369     byte_present_in_buffer=(ffado_ringbuffer_read_space(m_ringbuffer) >= m_eventsize);
370
371     if(byte_present_in_buffer) {
372
373         if(!m_do_ratecontrol) {
374             return true;
375         }
376
377         if(m_rate_counter <= 0) {
378             // update the counter
379             if(m_average_ratecontrol) {
380                 m_rate_counter += m_event_interval;
381                 assert(m_rate_counter<m_event_interval);
382             } else {
383                 m_rate_counter = m_event_interval;
384             }
385
386             retval=true;
387         } else {
388             debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Rate limit (%s)! rate_counter=%d \n",m_Name.c_str(),m_rate_counter);
389
390         }
391     }
392
393
394     m_rate_counter -= m_slot_interval;
395
396     // we have to limit the decrement of the ratecounter somehow.
397     // m_rate_counter_minimum is initialized when enabling ratecontrol
398     if(m_rate_counter < m_rate_counter_minimum) {
399         m_rate_counter = m_rate_counter_minimum;
400     }
401
402     return retval;
403 }
404
405 bool Port::useRateControl(bool use, unsigned int slot_interval,
406                                 unsigned int event_interval, bool average) {
407
408     if (use) {
409         debugOutput(DEBUG_LEVEL_VERBOSE, "Enabling rate control for port %s...\n",m_Name.c_str());
410         if(slot_interval>event_interval) {
411             debugWarning("Rate control not needed!\n",m_Name.c_str());
412             m_do_ratecontrol=false;
413             return false;
414         }
415         if(slot_interval==0) {
416             debugFatal("Cannot have slot interval == 0!\n");
417             m_do_ratecontrol=false;
418             return false;
419         }
420         if(event_interval==0) {
421             debugFatal("Cannot have event interval == 0!\n");
422             m_do_ratecontrol=false;
423             return false;
424         }
425         m_do_ratecontrol=use;
426         m_event_interval=event_interval;
427         m_slot_interval=slot_interval;
428         m_rate_counter=0;
429
430         // NOTE: pretty arbitrary, but in average mode this limits the peak stream rate
431         m_rate_counter_minimum=-(2*event_interval);
432
433         m_average_ratecontrol=average;
434
435     } else {
436         debugOutput(DEBUG_LEVEL_VERBOSE, "Disabling rate control for port %s...\n",m_Name.c_str());
437         m_do_ratecontrol=use;
438     }
439     return true;
440 }
441
442 /// Enable the port. (this can be called anytime)
443 void
444 Port::enable()  {
445     debugOutput(DEBUG_LEVEL_VERBOSE, "Enabling port %s...\n",m_Name.c_str());
446     m_disabled=false;
447 };
448
449 /// Disable the port. (this can be called anytime)
450 void
451 Port::disable() {
452     debugOutput(DEBUG_LEVEL_VERBOSE, "Disabling port %s...\n",m_Name.c_str());
453     m_disabled=false;
454 };
455
456
457 /* Private functions */
458
459 bool Port::allocateInternalBuffer() {
460     int event_size=getEventSize();
461
462     debugOutput(DEBUG_LEVEL_VERBOSE,
463                 "Allocating internal buffer of %d events with size %d (%s)\n",
464                 m_buffersize, event_size, m_Name.c_str());
465
466     if(m_buffer) {
467         debugWarning("already has an internal buffer attached, re-allocating\n");
468         freeInternalBuffer();
469     }
470
471     m_buffer=calloc(m_buffersize,event_size);
472     if (!m_buffer) {
473         debugFatal("could not allocate internal buffer\n");
474         m_buffersize=0;
475         return false;
476     }
477
478     return true;
479 }
480
481 void Port::freeInternalBuffer() {
482     debugOutput(DEBUG_LEVEL_VERBOSE,
483                 "Freeing internal buffer (%s)\n",m_Name.c_str());
484
485     if(m_buffer) {
486         free(m_buffer);
487         m_buffer=0;
488     }
489 }
490
491 bool Port::allocateInternalRingBuffer() {
492     int event_size=getEventSize();
493
494     debugOutput(DEBUG_LEVEL_VERBOSE,
495                 "Allocating internal buffer of %d events with size %d (%s)\n",
496                 m_buffersize, event_size, m_Name.c_str());
497
498     if(m_ringbuffer) {
499         debugWarning("already has an internal ringbuffer attached, re-allocating\n");
500         freeInternalRingBuffer();
501     }
502
503     m_ringbuffer=ffado_ringbuffer_create(m_buffersize * event_size);
504     if (!m_ringbuffer) {
505         debugFatal("could not allocate internal ringbuffer\n");
506         m_buffersize=0;
507         return false;
508     }
509
510     return true;
511 }
512
513 void Port::freeInternalRingBuffer() {
514     debugOutput(DEBUG_LEVEL_VERBOSE,
515                 "Freeing internal ringbuffer (%s)\n",m_Name.c_str());
516
517     if(m_ringbuffer) {
518         ffado_ringbuffer_free(m_ringbuffer);
519         m_ringbuffer=0;
520     }
521 }
522
523 }
Note: See TracBrowser for help on using the browser.