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

Revision 230, 12.0 kB (checked in by pieterpalmers, 18 years ago)

- xrun handling now works

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