root/branches/streaming-rework/src/libstreaming/Port.cpp

Revision 386, 12.6 kB (checked in by pieterpalmers, 16 years ago)

- moved files around to the place they belong
- fixed all compile warnings

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_disabled(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         // If called on an initialised stream but the request isn't for a change silently
264         // allow it (relied on by C API as used by jack backend driver)
265         if (m_initialized && m_use_external_buffer==b)
266                 return true;
267        
268         debugOutput( DEBUG_LEVEL_VERBOSE, "Setting external buffer use to %d for port %s\n",(int)b,m_Name.c_str());
269        
270         if (m_initialized) {
271                 debugFatal("Port already initialized... (%s)\n",m_Name.c_str());
272                 return false;
273         }
274
275         m_use_external_buffer=b;
276         return true;
277 }
278
279 // buffer handling api's for pointer buffers
280 /**
281  * Get the buffer address (being the external or the internal one).
282  *
283  * @param buff
284  */
285 void *Port::getBufferAddress() {
286         assert(m_BufferType==E_PointerBuffer);
287         return m_buffer;
288 };
289
290 /**
291  * Set the external buffer address.
292  * only call this when specifying an external buffer before init()
293  *
294  * @param buff
295  */
296 void Port::setExternalBufferAddress(void *buff) {
297         assert(m_BufferType==E_PointerBuffer);
298         assert(m_use_external_buffer); // don't call this with an internal buffer!
299         m_buffer=buff;
300 };
301
302 // buffer handling api's for ringbuffers
303 bool Port::writeEvent(void *event) {
304         assert(m_BufferType==E_RingBuffer);
305         assert(m_ringbuffer);
306        
307         debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Writing event %08X with size %d to port %s\n",*((quadlet_t *)event),m_eventsize, m_Name.c_str());
308        
309         return (freebob_ringbuffer_write(m_ringbuffer, (char *)event, m_eventsize)==m_eventsize);
310 }
311
312 bool Port::readEvent(void *event) {
313         assert(m_ringbuffer);
314        
315         unsigned int read=freebob_ringbuffer_read(m_ringbuffer, (char *)event, m_eventsize);
316        
317         debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Reading event %X with size %d from port %s\n",*((quadlet_t *)event),m_eventsize,m_Name.c_str());
318         return (read==m_eventsize);
319 }
320
321 int Port::writeEvents(void *event, unsigned int nevents) {
322         assert(m_BufferType==E_RingBuffer);
323         assert(m_ringbuffer);
324        
325         unsigned int bytes2write=m_eventsize*nevents;
326        
327         unsigned int written=freebob_ringbuffer_write(m_ringbuffer, (char *)event,bytes2write)/m_eventsize;
328        
329         if(written) {
330                 unsigned int i=0;
331                 quadlet_t * tmp=(quadlet_t *)event;
332                 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Written %d events (",written);
333                 for (i=0;i<written;i++) {
334                         debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, "%X ", *(tmp+i));
335                 }
336                 debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, ") to port %s\n",m_Name.c_str());
337         }
338        
339         return written;
340
341 }
342
343 int Port::readEvents(void *event, unsigned int nevents) {
344         assert(m_ringbuffer);
345        
346         unsigned int bytes2read=m_eventsize*nevents;
347        
348         unsigned int read=freebob_ringbuffer_read(m_ringbuffer, (char *)event, bytes2read)/m_eventsize;
349        
350         if(read) {
351                 unsigned int i=0;
352                 quadlet_t * tmp=(quadlet_t *)event;
353                 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Read %d events (",read);
354                 for (i=0;i<read;i++) {
355                         debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, "%X ", *(tmp+i));
356                 }
357                 debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, ") from port %s\n",m_Name.c_str());
358         }
359        
360         return read;
361 }
362
363 /* rate control */
364 bool Port::canRead() {
365         bool byte_present_in_buffer;
366        
367         bool retval=false;
368        
369         assert(m_ringbuffer);
370        
371         byte_present_in_buffer=(freebob_ringbuffer_read_space(m_ringbuffer) >= m_eventsize);
372        
373         if(byte_present_in_buffer) {
374                
375                 if(!m_do_ratecontrol) {
376                         return true;
377                 }
378                
379                 if(m_rate_counter <= 0) {
380                         // update the counter
381                         if(m_average_ratecontrol) {
382                                 m_rate_counter += m_event_interval;
383                                 assert(m_rate_counter<m_event_interval);
384                         } else {
385                                 m_rate_counter = m_event_interval;
386                         }
387                
388                         retval=true;
389                 } else {
390                         debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Rate limit (%s)! rate_counter=%d \n",m_Name.c_str(),m_rate_counter);
391                
392                 }
393         }
394        
395        
396         m_rate_counter -= m_slot_interval;
397        
398         // we have to limit the decrement of the ratecounter somehow.
399         // m_rate_counter_minimum is initialized when enabling ratecontrol
400         if(m_rate_counter < m_rate_counter_minimum) {
401                 m_rate_counter = m_rate_counter_minimum;
402         }
403        
404         return retval;
405 }
406
407 bool Port::useRateControl(bool use, unsigned int slot_interval,
408                                     unsigned int event_interval, bool average) {
409
410         if (use) {
411                 debugOutput(DEBUG_LEVEL_VERBOSE, "Enabling rate control for port %s...\n",m_Name.c_str());
412                 if(slot_interval>event_interval) {
413                         debugWarning("Rate control not needed!\n",m_Name.c_str());
414                         m_do_ratecontrol=false;
415                         return false;
416                 }
417                 if(slot_interval==0) {
418                         debugFatal("Cannot have slot interval == 0!\n");
419                         m_do_ratecontrol=false;
420                         return false;
421                 }
422                 if(event_interval==0) {
423                         debugFatal("Cannot have event interval == 0!\n");
424                         m_do_ratecontrol=false;
425                         return false;
426                 }
427                 m_do_ratecontrol=use;
428                 m_event_interval=event_interval;
429                 m_slot_interval=slot_interval;
430                 m_rate_counter=0;
431                
432                 // NOTE: pretty arbitrary, but in average mode this limits the peak stream rate
433                 m_rate_counter_minimum=-(2*event_interval);
434                
435                 m_average_ratecontrol=average;
436
437         } else {
438                 debugOutput(DEBUG_LEVEL_VERBOSE, "Disabling rate control for port %s...\n",m_Name.c_str());
439                 m_do_ratecontrol=use;
440         }
441         return true;
442 }
443
444 /// Enable the port. (this can be called anytime)
445 void
446 Port::enable()  {
447         debugOutput(DEBUG_LEVEL_VERBOSE, "Enabling port %s...\n",m_Name.c_str());
448         m_disabled=false;
449 };
450
451 /// Disable the port. (this can be called anytime)
452 void
453 Port::disable() {
454         debugOutput(DEBUG_LEVEL_VERBOSE, "Disabling port %s...\n",m_Name.c_str());
455     m_disabled=false;
456 };
457
458
459 /* Private functions */
460
461 bool Port::allocateInternalBuffer() {
462         int event_size=getEventSize();
463        
464         debugOutput(DEBUG_LEVEL_VERBOSE,
465                     "Allocating internal buffer of %d events with size %d (%s)\n",
466                     m_buffersize, event_size, m_Name.c_str());
467
468         if(m_buffer) {
469                 debugWarning("already has an internal buffer attached, re-allocating\n");
470                 freeInternalBuffer();
471         }
472
473         m_buffer=calloc(m_buffersize,event_size);
474         if (!m_buffer) {
475                 debugFatal("could not allocate internal buffer\n");
476                 m_buffersize=0;
477                 return false;
478         }
479
480         return true;
481 }
482
483 void Port::freeInternalBuffer() {
484         debugOutput(DEBUG_LEVEL_VERBOSE,
485                     "Freeing internal buffer (%s)\n",m_Name.c_str());
486
487         if(m_buffer) {
488                 free(m_buffer);
489                 m_buffer=0;
490         }
491 }
492
493 bool Port::allocateInternalRingBuffer() {
494         int event_size=getEventSize();
495        
496         debugOutput(DEBUG_LEVEL_VERBOSE,
497                     "Allocating internal buffer of %d events with size %d (%s)\n",
498                     m_buffersize, event_size, m_Name.c_str());
499
500         if(m_ringbuffer) {
501                 debugWarning("already has an internal ringbuffer attached, re-allocating\n");
502                 freeInternalRingBuffer();
503         }
504
505         m_ringbuffer=freebob_ringbuffer_create(m_buffersize * event_size);
506         if (!m_ringbuffer) {
507                 debugFatal("could not allocate internal ringbuffer\n");
508                 m_buffersize=0;
509                 return false;
510         }
511
512         return true;
513 }
514
515 void Port::freeInternalRingBuffer() {
516         debugOutput(DEBUG_LEVEL_VERBOSE,
517                     "Freeing internal ringbuffer (%s)\n",m_Name.c_str());
518
519         if(m_ringbuffer) {
520                 freebob_ringbuffer_free(m_ringbuffer);
521                 m_ringbuffer=0;
522         }
523 }
524
525 }
Note: See TracBrowser for help on using the browser.