root/trunk/libffado/src/libutil/TimestampedBuffer.cpp

Revision 1012, 35.1 kB (checked in by ppalmers, 15 years ago)

fix segfault when init fails

Line 
1 /*
2  * Copyright (C) 2005-2008 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 program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) version 3 of the License.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 #include "config.h"
25
26 #include "libutil/Atomic.h"
27 #include "libieee1394/cycletimer.h"
28
29 #include "TimestampedBuffer.h"
30 #include "assert.h"
31 #include "errno.h"
32
33
34 #define DLL_PI        (3.141592653589793238)
35 #define DLL_SQRT2     (1.414213562373095049)
36 #define DLL_OMEGA     (2.0*DLL_PI*TIMESTAMPEDBUFFER_DLL_BANDWIDTH)
37 #define DLL_COEFF_B   (DLL_SQRT2 * DLL_OMEGA)
38 #define DLL_COEFF_C   (DLL_OMEGA * DLL_OMEGA)
39
40 #define FRAMES_PER_PROCESS_BLOCK 8
41 /*
42 #define ENTER_CRITICAL_SECTION { \
43     if (pthread_mutex_trylock(&m_framecounter_lock) == EBUSY) { \
44         debugWarning(" (%p) lock clash\n", this); \
45         pthread_mutex_lock(&m_framecounter_lock); \
46     } \
47     }
48 */
49 #define ENTER_CRITICAL_SECTION { \
50     pthread_mutex_lock(&m_framecounter_lock); \
51     }
52 #define EXIT_CRITICAL_SECTION { \
53     pthread_mutex_unlock(&m_framecounter_lock); \
54     }
55
56 namespace Util {
57
58 IMPL_DEBUG_MODULE( TimestampedBuffer, TimestampedBuffer, DEBUG_LEVEL_VERBOSE );
59
60 TimestampedBuffer::TimestampedBuffer(TimestampedBufferClient *c)
61     : m_event_buffer(NULL), m_process_buffer(NULL), m_cluster_size( 0 ),
62       m_process_block_size( 0 ),
63       m_event_size(0), m_events_per_frame(0), m_buffer_size(0),
64       m_bytes_per_frame(0), m_bytes_per_buffer(0),
65       m_enabled( false ), m_transparent ( true ),
66       m_wrap_at(0xFFFFFFFFFFFFFFFFLLU),
67       m_Client(c), m_framecounter(0),
68       m_buffer_tail_timestamp(0.0),
69       m_buffer_next_tail_timestamp(0.0),
70       m_dll_e2(0.0), m_dll_b(DLL_COEFF_B), m_dll_c(DLL_COEFF_C),
71       m_nominal_rate(0.0), m_current_rate(0.0), m_update_period(0)
72 {
73     pthread_mutex_init(&m_framecounter_lock, NULL);
74 }
75
76 TimestampedBuffer::~TimestampedBuffer() {
77     pthread_mutex_destroy(&m_framecounter_lock);
78
79     if(m_event_buffer) ffado_ringbuffer_free(m_event_buffer);
80     if(m_process_buffer) free(m_process_buffer);
81 }
82
83 /**
84  * \brief Set the nominal rate in frames/timeunit
85  *
86  * Sets the nominal rate in frames per time unit. This rate is used
87  * to initialize the DLL that will extract the effective rate based
88  * upon the timestamps it gets fed.
89  *
90  * @param r rate
91  * @return true if successful
92  */
93 bool TimestampedBuffer::setNominalRate(float r) {
94     m_nominal_rate=r;
95     debugOutput(DEBUG_LEVEL_VERBOSE," nominal rate=%e set to %e\n",
96                                     m_nominal_rate, r);
97     return true;
98 }
99
100 /**
101  * \brief Set the nominal update period (in frames)
102  *
103  * Sets the nominal update period. This period is the number of frames
104  * between two timestamp updates (hence buffer writes)
105  *
106  * @param n period in frames
107  * @return true if successful
108  */
109 bool TimestampedBuffer::setUpdatePeriod(unsigned int n) {
110     m_update_period=n;
111     return true;
112 }
113
114 /**
115  * \brief Get the nominal update period (in frames)
116  *
117  * Gets the nominal update period. This period is the number of frames
118  * between two timestamp updates (hence buffer writes)
119  *
120  * @return period in frames
121  */
122 unsigned int TimestampedBuffer::getUpdatePeriod() {
123     return m_update_period;
124 }
125
126 /**
127  * \brief set the value at which timestamps should wrap around
128  * @param w value to wrap at
129  * @return true if successful
130  */
131 bool TimestampedBuffer::setWrapValue(ffado_timestamp_t w) {
132     m_wrap_at=w;
133     return true;
134 }
135 #include <math.h>
136
137 /**
138  * \brief return the effective rate
139  *
140  * Returns the effective rate calculated by the DLL.
141  *
142  * @return rate (in timeunits/frame)
143  */
144 float TimestampedBuffer::getRate() {
145     return m_current_rate;
146 }
147
148 /**
149  * \brief presets the effective rate
150  *
151  * Presets the DLL such that the effective rate is as given
152  * @param rate rate (in timeunits/frame)
153  */
154 void TimestampedBuffer::setRate(float rate) {
155     // we take the current tail timestamp and update the head timestamp
156     // to ensure the rate is ok
157
158     ENTER_CRITICAL_SECTION;
159
160     m_dll_e2 = m_update_period * (double)rate;
161     m_buffer_next_tail_timestamp = (ffado_timestamp_t)((double)m_buffer_tail_timestamp + m_dll_e2);
162
163     EXIT_CRITICAL_SECTION;
164
165     debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
166                        "for (%p) to "TIMESTAMP_FORMAT_SPEC" => "TIMESTAMP_FORMAT_SPEC", "
167                        "NTS="TIMESTAMP_FORMAT_SPEC", DLL2=%f, RATE=%f\n",
168                        this, new_timestamp, ts, m_buffer_next_tail_timestamp, m_dll_e2, getRate());
169 }
170
171 /**
172  * \brief calculate the effective rate
173  *
174  * Returns the effective rate calculated by the DLL.
175  * @note should be called with the lock held
176  * @return rate (in timeunits/frame)
177  */
178 float TimestampedBuffer::calculateRate() {
179     ffado_timestamp_t diff;
180
181     diff=m_buffer_next_tail_timestamp - m_buffer_tail_timestamp;
182
183     debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
184                        "getRate: %f/%f=%f\n",
185                        (float)(diff),
186                        (float)m_update_period,
187                        ((float)(diff))/((float) m_update_period));
188
189     // the maximal difference we can allow (64secs)
190     const ffado_timestamp_t max=m_wrap_at/((ffado_timestamp_t)2);
191
192     if(diff > max) {
193         diff -= m_wrap_at;
194     } else if (diff < -max) {
195         diff += m_wrap_at;
196     }
197
198     float rate=((float)diff)/((float) m_update_period);
199     if (rate<0.0) debugError("rate < 0! (%f)\n",rate);
200     if (fabsf(m_nominal_rate - rate)>(m_nominal_rate*0.1)) {
201         debugWarning("(%p) rate (%10.5f) more that 10%% off nominal "
202                      "(rate=%10.5f, diff="TIMESTAMP_FORMAT_SPEC", update_period=%d)\n",
203                      this, rate,m_nominal_rate,diff, m_update_period);
204
205         return m_nominal_rate;
206     } else {
207         return rate;
208     }
209 }
210
211 /**
212  * \brief Sets the size of the events
213  * @param s event size in bytes
214  * @return true if successful
215  */
216 bool TimestampedBuffer::setEventSize(unsigned int s) {
217     m_event_size=s;
218
219     m_bytes_per_frame=m_event_size*m_events_per_frame;
220     m_bytes_per_buffer=m_bytes_per_frame*m_buffer_size;
221
222     return true;
223 }
224
225 /**
226  * \brief Sets the number of events per frame
227  * @param n number of events per frame
228  * @return true if successful
229  */
230 bool TimestampedBuffer::setEventsPerFrame(unsigned int n) {
231     m_events_per_frame=n;
232
233     m_bytes_per_frame=m_event_size*m_events_per_frame;
234     m_bytes_per_buffer=m_bytes_per_frame*m_buffer_size;
235
236     return true;
237 }
238 /**
239  * \brief Sets the buffer size in frames
240  * @param n number frames
241  * @return true if successful
242  */
243 bool TimestampedBuffer::setBufferSize(unsigned int n) {
244     m_buffer_size=n;
245
246     m_bytes_per_frame=m_event_size*m_events_per_frame;
247     m_bytes_per_buffer=m_bytes_per_frame*m_buffer_size;
248
249     return true;
250 }
251
252 /**
253  * \brief Returns the current fill of the buffer
254  *
255  * This returns the buffer fill of the internal ringbuffer. This
256  * can only be used as an indication because it's state is not
257  * guaranteed to be consistent at all times due to threading issues.
258  *
259  * In order to get the number of frames in the buffer, use the
260  * getBufferHeadTimestamp, getBufferTailTimestamp
261  * functions
262  *
263  * @return the internal buffer fill in frames
264  */
265 unsigned int TimestampedBuffer::getBufferFill() {
266     //return ffado_ringbuffer_read_space(m_event_buffer)/(m_bytes_per_frame);
267     return m_framecounter;
268 }
269
270 /**
271  * \brief Returns the current write space in the buffer
272  *
273  * This returns the buffer free space of the internal ringbuffer. This
274  * can only be used as an indication because it's state is not
275  * guaranteed to be consistent at all times due to threading issues.
276  *
277  * @return the internal buffer fill in frames
278  */
279 unsigned int TimestampedBuffer::getBufferSpace() {
280     //return ffado_ringbuffer_write_space(m_event_buffer)/(m_bytes_per_frame);
281     assert(m_buffer_size-m_framecounter >= 0);
282     return m_buffer_size-m_framecounter;
283 }
284
285 /**
286  * \brief Resets the TimestampedBuffer
287  *
288  * Resets the TimestampedBuffer, clearing the buffers and counters.
289  * (not true yet: Also resets the DLL to the nominal values.)
290  *
291  * \note when this is called, you should make sure that the buffer
292  *       tail timestamp gets set before continuing
293  *
294  * @return true if successful
295  */
296 bool TimestampedBuffer::clearBuffer() {
297     debugOutput(DEBUG_LEVEL_VERBOSE, "Clearing buffer\n");
298     ffado_ringbuffer_reset(m_event_buffer);
299     resetFrameCounter();
300     return true;
301 }
302
303 /**
304  * \brief Prepares the TimestampedBuffer
305  *
306  * Prepare the TimestampedBuffer. This allocates all internal buffers and
307  * initializes all data structures.
308  *
309  * This should be called after parameters such as buffer size, event size etc.. are set,
310  * and before any read/write operations are performed.
311  *
312  * @return true if successful
313  */
314 bool TimestampedBuffer::prepare() {
315     debugOutput(DEBUG_LEVEL_VERBOSE,"Preparing buffer (%p)\n",this);
316     debugOutput(DEBUG_LEVEL_VERBOSE," Size=%u events, events/frame=%u, event size=%ubytes\n",
317                                         m_buffer_size,m_events_per_frame,m_event_size);
318
319     debugOutput(DEBUG_LEVEL_VERBOSE," update period %u\n",
320                                     m_update_period);
321     debugOutput(DEBUG_LEVEL_VERBOSE," nominal rate=%f\n",
322                                     m_nominal_rate);
323
324     debugOutput(DEBUG_LEVEL_VERBOSE," wrapping at "TIMESTAMP_FORMAT_SPEC"\n",m_wrap_at);
325
326     assert(m_buffer_size);
327     assert(m_events_per_frame);
328     assert(m_event_size);
329
330     assert(m_nominal_rate != 0.0L);
331     assert(m_update_period != 0);
332
333     m_current_rate = m_nominal_rate;
334
335     if( !(m_event_buffer=ffado_ringbuffer_create(
336             (m_events_per_frame * m_buffer_size) * m_event_size))) {
337         debugFatal("Could not allocate memory event ringbuffer\n");
338         return false;
339     }
340
341     // allocate the temporary cluster buffer
342     // NOTE: has to be a multiple of 8 in order to
343     //       correctly decode midi bytes (since that
344     //       enforces packet alignment)
345     m_cluster_size = m_events_per_frame * m_event_size;
346     m_process_block_size = m_cluster_size * FRAMES_PER_PROCESS_BLOCK;
347     if( !(m_process_buffer=(char *)calloc(m_process_block_size, 1))) {
348             debugFatal("Could not allocate temporary cluster buffer\n");
349         ffado_ringbuffer_free(m_event_buffer);
350         return false;
351     }
352
353     // init the DLL
354     m_dll_e2=m_nominal_rate * (float)m_update_period;
355
356     m_dll_b=((float)(DLL_COEFF_B));
357     m_dll_c=((float)(DLL_COEFF_C));
358    
359     // this will init the internal timestamps to a sensible value
360     setBufferTailTimestamp(m_buffer_tail_timestamp);
361
362     return true;
363 }
364
365 /**
366  * @brief Insert a dummy frame to the head buffer
367  *
368  * Writes one frame of dummy data to the head of the buffer.
369  * This is to assist the phase sync of several buffers.
370  *
371  * Note: currently the dummy data is added to the tail of the
372  *       buffer, but without updating the timestamp.
373  *
374  * @return true if successful
375  */
376 bool TimestampedBuffer::writeDummyFrame() {
377
378     unsigned int write_size=m_event_size*m_events_per_frame;
379    
380     char dummy[write_size]; // one frame of garbage
381     memset(dummy,0,write_size);
382
383     // add the data payload to the ringbuffer
384     if (ffado_ringbuffer_write(m_event_buffer,dummy,write_size) < write_size)
385     {
386 //         debugWarning("writeFrames buffer overrun\n");
387         return false;
388     }
389
390 //     incrementFrameCounter(nframes,ts);
391    
392     // increment without updating the DLL
393     ENTER_CRITICAL_SECTION;
394     m_framecounter++;
395     EXIT_CRITICAL_SECTION;
396     return true;
397 }
398
399 /**
400  * @brief Write frames to the buffer
401  *
402  * Copies \ref nframes of frames from the buffer pointed to by \ref data to the
403  * internal ringbuffer. The time of the last frame in the buffer is set to \ref ts.
404  *
405  * @param nframes number of frames to copy
406  * @param data pointer to the frame buffer
407  * @param ts timestamp of the last frame copied
408  * @return true if successful
409  */
410 bool TimestampedBuffer::writeFrames(unsigned int nframes, char *data, ffado_timestamp_t ts) {
411
412     unsigned int write_size=nframes*m_event_size*m_events_per_frame;
413
414     if (m_transparent) {
415         // while disabled, we don't update the DLL, nor do we write frames
416         // we just set the correct timestamp for the frames
417         setBufferTailTimestamp(ts);
418     } else {
419         // add the data payload to the ringbuffer
420         size_t written = ffado_ringbuffer_write(m_event_buffer, data, write_size);
421         if (written < write_size)
422         {
423             debugWarning("ringbuffer full, %u, %u\n", write_size, written);
424             return false;
425         }
426         incrementFrameCounter(nframes, ts);
427     }
428     return true;
429 }
430
431 /**
432  * @brief Preload frames into the buffer
433  *
434  * Preload \ref nframes of frames from the buffer pointed to by \ref data to the
435  * internal ringbuffer. Does not care about transparency. Keeps the buffer head or tail
436  * timestamp constant.
437  *
438  * @note not thread safe
439  *
440  * @param nframes number of frames to copy
441  * @param data pointer to the frame buffer
442  * @param keep_head_ts if true, keep the head timestamp constant. If false, keep the
443  *                     tail timestamp constant.
444  * @return true if successful
445  */
446 bool TimestampedBuffer::preloadFrames(unsigned int nframes, char *data, bool keep_head_ts) {
447     unsigned int write_size = nframes * m_event_size * m_events_per_frame;
448     // add the data payload to the ringbuffer
449     size_t written = ffado_ringbuffer_write(m_event_buffer, data, write_size);
450     if (written < write_size)
451     {
452         debugWarning("ringbuffer full, request: %u, actual: %u\n", write_size, written);
453         return false;
454     }
455    
456     // make sure the head timestamp remains identical
457     signed int fc;
458     ffado_timestamp_t ts;
459
460     if (keep_head_ts) {
461         getBufferHeadTimestamp(&ts, &fc);
462     } else {
463         getBufferTailTimestamp(&ts, &fc);
464     }
465     // update frame counter
466     m_framecounter += nframes;
467     if (keep_head_ts) {
468         setBufferHeadTimestamp(ts);
469     } else {
470         setBufferTailTimestamp(ts);
471     }
472     return true;
473 }
474
475 /**
476  * @brief Drop frames from the head of the buffer
477  *
478  * drops \ref nframes of frames from the head of internal buffer
479  *
480  * @param nframes number of frames to drop
481  * @return true if successful
482  */
483 bool
484 TimestampedBuffer::dropFrames(unsigned int nframes) {
485     unsigned int read_size = nframes * m_event_size * m_events_per_frame;
486     ffado_ringbuffer_read_advance(m_event_buffer, read_size);
487     decrementFrameCounter(nframes);
488     return true;
489 }
490
491 /**
492  * @brief Read frames from the buffer
493  *
494  * Copies \ref nframes of frames from the internal buffer to the data buffer pointed
495  * to by \ref data.
496  *
497  * @param nframes number of frames to copy
498  * @param data pointer to the frame buffer
499  * @return true if successful
500  */
501 bool TimestampedBuffer::readFrames(unsigned int nframes, char *data) {
502
503     unsigned int read_size=nframes*m_event_size*m_events_per_frame;
504
505     if (m_transparent) {
506         return true; // FIXME: the data still doesn't make sense!
507     } else {
508         // get the data payload to the ringbuffer
509         if ((ffado_ringbuffer_read(m_event_buffer,data,read_size)) < read_size)
510         {
511             debugWarning("readFrames buffer underrun\n");
512             return false;
513         }
514         decrementFrameCounter(nframes);
515     }
516     return true;
517 }
518
519 /**
520  * @brief Performs block processing write of frames
521  *
522  * This function allows for zero-copy writing into the ringbuffer.
523  * It calls the client's processWriteBlock function to write frames
524  * into the internal buffer's data area, in a thread safe fashion.
525  *
526  * It also updates the timestamp.
527  *
528  * @param nbframes number of frames to process
529  * @param ts timestamp of the last frame written to the buffer
530  * @return true if successful
531  */
532 bool TimestampedBuffer::blockProcessWriteFrames(unsigned int nbframes, ffado_timestamp_t ts) {
533     debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
534                        "(%p) Writing %u frames for ts "TIMESTAMP_FORMAT_SPEC"\n",
535                        this, nbframes, ts);
536     int xrun;
537     unsigned int offset = 0;
538
539     ffado_ringbuffer_data_t vec[2];
540     // we received one period of frames
541     // this is period_size*dimension of events
542     unsigned int events2write = nbframes * m_events_per_frame;
543     unsigned int bytes2write = events2write * m_event_size;
544
545     /* write events2write bytes to the ringbuffer
546     *  first see if it can be done in one read.
547     *  if so, ok.
548     *  otherwise write up to a multiple of clusters directly to the buffer
549     *  then do the buffer wrap around using ringbuffer_write
550     *  then write the remaining data directly to the buffer in a third pass
551     *  Make sure that we cannot end up on a non-cluster aligned position!
552     */
553
554     while(bytes2write > 0) {
555         int byteswritten = 0;
556
557         unsigned int frameswritten = (nbframes * m_cluster_size - bytes2write) / m_cluster_size;
558         offset = frameswritten;
559
560         ffado_ringbuffer_get_write_vector(m_event_buffer, vec);
561
562         if(vec[0].len + vec[1].len < m_process_block_size) { // this indicates a full event buffer
563             debugError("Event buffer overrun in buffer %p, fill: %u, bytes2write: %u \n",
564                        this, ffado_ringbuffer_read_space(m_event_buffer), bytes2write);
565             debugShowBackLog();
566             return false;
567         }
568
569         /* if we don't take care we will get stuck in an infinite loop
570         * because we align to a cluster boundary later
571         * the remaining nb of bytes in one write operation can be
572         * smaller than one cluster
573         * this can happen because the ringbuffer size is always a power of 2
574         */
575         if(vec[0].len < m_process_block_size) {
576
577             // encode to the temporary buffer
578             // note that we always process 8 frames at once, in order to ensure that
579             // we don't have to care about the DBC field
580             xrun = m_Client->processWriteBlock(m_process_buffer, FRAMES_PER_PROCESS_BLOCK, offset);
581
582             if(xrun < 0) {
583                 // xrun detected
584                 debugError("Frame buffer underrun in buffer %p\n",this);
585                 return false;
586             }
587
588             // use the ringbuffer function to write one cluster
589             // the write function handles the wrap around.
590             ffado_ringbuffer_write(m_event_buffer,
591                                    m_process_buffer,
592                                    m_process_block_size);
593
594             // we advanced one cluster_size
595             bytes2write -= m_process_block_size;
596
597         } else { //
598
599             if(bytes2write > vec[0].len) {
600                 // align to a cluster boundary
601                 byteswritten = vec[0].len - (vec[0].len % m_process_block_size);
602             } else {
603                 byteswritten = bytes2write;
604             }
605
606             xrun = m_Client->processWriteBlock(vec[0].buf,
607                                                byteswritten / m_cluster_size,
608                                                offset);
609
610             if(xrun < 0 ) {
611                 // xrun detected
612                 debugError("Frame buffer underrun in buffer %p\n",this);
613                 return false; // FIXME: return false ?
614             }
615
616             ffado_ringbuffer_write_advance(m_event_buffer, byteswritten);
617             bytes2write -= byteswritten;
618         }
619
620         // the bytes2write should always be process block aligned
621         assert(bytes2write % m_process_block_size == 0);
622
623     }
624
625     incrementFrameCounter(nbframes,ts);
626
627     return true;
628
629 }
630
631 /**
632  * @brief Performs block processing read of frames
633  *
634  * This function allows for zero-copy reading from the ringbuffer.
635  * It calls the client's processReadBlock function to read frames
636  * directly from the internal buffer's data area, in a thread safe
637  * fashion.
638  *
639  * @param nbframes number of frames to process
640  * @return true if successful
641  */
642 bool TimestampedBuffer::blockProcessReadFrames(unsigned int nbframes) {
643
644     debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
645                        "(%p) Reading %u frames\n",
646                        this, nbframes);
647
648     int xrun;
649     unsigned int offset = 0;
650
651     ffado_ringbuffer_data_t vec[2];
652     // we received one period of frames on each connection
653     // this is period_size*dimension of events
654
655     unsigned int events2read = nbframes * m_events_per_frame;
656     unsigned int bytes2read = events2read * m_event_size;
657     /* read events2read bytes from the ringbuffer
658     *  first see if it can be done in one read.
659     *  if so, ok.
660     *  otherwise read up to a multiple of clusters directly from the buffer
661     *  then do the buffer wrap around using ringbuffer_read
662     *  then read the remaining data directly from the buffer in a third pass
663     *  Make sure that we cannot end up on a non-cluster aligned position!
664     */
665
666     while(bytes2read > 0) {
667         unsigned int framesread = (nbframes * m_cluster_size - bytes2read) / m_cluster_size;
668         offset = framesread;
669
670         int bytesread = 0;
671
672         ffado_ringbuffer_get_read_vector(m_event_buffer, vec);
673
674         if(vec[0].len + vec[1].len < m_process_block_size) { // this indicates an empty event buffer
675             debugError("Event buffer underrun in buffer %p\n",this);
676             return false;
677         }
678
679         /* if we don't take care we will get stuck in an infinite loop
680         * because we align to a cluster boundary later
681         * the remaining nb of bytes in one read operation can be smaller than one cluster
682         * this can happen because the ringbuffer size is always a power of 2
683                 */
684         if(vec[0].len < m_process_block_size) {
685             // use the ringbuffer function to read one cluster
686             // the read function handles wrap around
687             ffado_ringbuffer_read(m_event_buffer, m_process_buffer, m_process_block_size);
688
689             assert(m_Client);
690             // note that we always process 8 frames at once, in order to ensure that
691             // we don't have to care about the DBC field
692             xrun = m_Client->processReadBlock(m_process_buffer, FRAMES_PER_PROCESS_BLOCK, offset);
693
694             if(xrun < 0) {
695                 // xrun detected
696                 debugError("Frame buffer overrun in buffer %p\n",this);
697                     return false;
698             }
699
700             // we advanced one cluster_size
701             bytes2read -= m_process_block_size;
702
703         } else { //
704
705             if(bytes2read > vec[0].len) {
706                 // align to a cluster boundary
707                 bytesread = vec[0].len - (vec[0].len % m_process_block_size);
708             } else {
709                 bytesread = bytes2read;
710             }
711
712             assert(m_Client);
713             xrun = m_Client->processReadBlock(vec[0].buf, bytesread/m_cluster_size, offset);
714
715             if(xrun < 0) {
716                 // xrun detected
717                 debugError("Frame buffer overrun in buffer %p\n",this);
718                 return false;
719             }
720
721             ffado_ringbuffer_read_advance(m_event_buffer, bytesread);
722             bytes2read -= bytesread;
723         }
724
725         // the bytes2read should always be cluster aligned
726         assert(bytes2read % m_process_block_size == 0);
727     }
728
729     decrementFrameCounter(nbframes);
730
731     return true;
732 }
733
734 /**
735  * @brief Sets the buffer tail timestamp.
736  *
737  * Set the buffer tail timestamp to \ref new_timestamp. This will recalculate
738  * the internal state such that the buffer's timeframe starts at
739  * \ref new_timestamp.
740  *
741  * This is thread safe.
742  *
743  * @note considers offsets
744  *
745  * @param new_timestamp
746  */
747 void TimestampedBuffer::setBufferTailTimestamp(ffado_timestamp_t new_timestamp) {
748
749     // add the offsets
750     ffado_timestamp_t ts=new_timestamp;
751
752     if (ts >= m_wrap_at) {
753         ts -= m_wrap_at;
754     } else if (ts < 0) {
755         ts += m_wrap_at;
756     }
757
758 #ifdef DEBUG
759     if (new_timestamp >= m_wrap_at) {
760         debugWarning("timestamp not wrapped: "TIMESTAMP_FORMAT_SPEC"\n",new_timestamp);
761     }
762     if ((ts >= m_wrap_at) || (ts < 0 )) {
763         debugWarning("ts not wrapped correctly: "TIMESTAMP_FORMAT_SPEC"\n",ts);
764     }
765 #endif
766
767     ENTER_CRITICAL_SECTION;
768
769     m_buffer_tail_timestamp = ts;
770
771     m_dll_e2=m_update_period * (double)m_nominal_rate;
772     m_buffer_next_tail_timestamp = (ffado_timestamp_t)((double)m_buffer_tail_timestamp + m_dll_e2);
773
774     EXIT_CRITICAL_SECTION;
775
776     debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
777                        "for (%p) to "TIMESTAMP_FORMAT_SPEC" => "TIMESTAMP_FORMAT_SPEC", "
778                        "NTS="TIMESTAMP_FORMAT_SPEC", DLL2=%f, RATE=%f\n",
779                        this, new_timestamp, ts, m_buffer_next_tail_timestamp, m_dll_e2, getRate());
780 }
781
782 /**
783  * @brief Sets the buffer head timestamp.
784  *
785  * Set the buffer tail timestamp such that the buffer head timestamp becomes
786  * \ref new_timestamp. This does not consider offsets, because it's use is to
787  * make sure the following is true after setBufferHeadTimestamp(x):
788  *   x == getBufferHeadTimestamp()
789  *
790  * This is thread safe.
791  *
792  * @param new_timestamp
793  */
794 void TimestampedBuffer::setBufferHeadTimestamp(ffado_timestamp_t new_timestamp) {
795
796 #ifdef DEBUG
797     if (new_timestamp >= m_wrap_at) {
798         debugWarning("timestamp not wrapped: "TIMESTAMP_FORMAT_SPEC"\n",new_timestamp);
799     }
800 #endif
801
802     ffado_timestamp_t ts = new_timestamp;
803
804     ENTER_CRITICAL_SECTION;
805
806     // add the time
807     ts += (ffado_timestamp_t)(m_nominal_rate * (float)m_framecounter);
808
809     if (ts >= m_wrap_at) {
810         ts -= m_wrap_at;
811     } else if (ts < 0) {
812         ts += m_wrap_at;
813     }
814
815     m_buffer_tail_timestamp = ts;
816
817     m_dll_e2=m_update_period * (double)m_nominal_rate;
818     m_buffer_next_tail_timestamp = (ffado_timestamp_t)((double)m_buffer_tail_timestamp + m_dll_e2);
819
820     EXIT_CRITICAL_SECTION;
821
822     debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
823                        "for (%p) to "TIMESTAMP_FORMAT_SPEC" => "TIMESTAMP_FORMAT_SPEC", "
824                        "NTS="TIMESTAMP_FORMAT_SPEC", DLL2=%f, RATE=%f\n",
825                        this, new_timestamp, ts, m_buffer_next_tail_timestamp, m_dll_e2, getRate());
826 }
827
828 /**
829  * \brief return the timestamp of the first frame in the buffer
830  *
831  * This function returns the timestamp of the very first sample in
832  * the StreamProcessor's buffer. It also returns the framecounter value
833  * for which this timestamp is valid.
834  *
835  * @param ts address to store the timestamp in
836  * @param fc address to store the associated framecounter in
837  */
838 void TimestampedBuffer::getBufferHeadTimestamp(ffado_timestamp_t *ts, signed int *fc) {
839     ENTER_CRITICAL_SECTION;
840     *fc = m_framecounter;
841     *ts = getTimestampFromTail(*fc);
842     EXIT_CRITICAL_SECTION;
843 }
844
845 /**
846  * \brief return the timestamp of the last frame in the buffer
847  *
848  * This function returns the timestamp of the last frame in
849  * the StreamProcessor's buffer. It also returns the framecounter
850  * value for which this timestamp is valid.
851  *
852  * @param ts address to store the timestamp in
853  * @param fc address to store the associated framecounter in
854  */
855 void TimestampedBuffer::getBufferTailTimestamp(ffado_timestamp_t *ts, signed int *fc) {
856     ENTER_CRITICAL_SECTION;
857     *fc = m_framecounter;
858     *ts = getTimestampFromTail(0);
859     EXIT_CRITICAL_SECTION;
860 }
861
862 /**
863  * @brief Get timestamp for a specific position from the buffer tail
864  *
865  * Returns the timestamp for a position that is nframes earlier than the
866  * buffer tail
867  *
868  * @param nframes number of frames
869  * @return timestamp value
870  */
871 ffado_timestamp_t TimestampedBuffer::getTimestampFromTail(int nframes)
872 {
873     // ts(x) = m_buffer_tail_timestamp -
874     //         (m_buffer_next_tail_timestamp - m_buffer_tail_timestamp)/(samples_between_updates)*(x)
875     ffado_timestamp_t timestamp;
876     timestamp = m_buffer_tail_timestamp;
877
878     timestamp -= (ffado_timestamp_t)((nframes) * m_current_rate);
879
880     if(timestamp >= m_wrap_at) {
881         timestamp -= m_wrap_at;
882     } else if(timestamp < 0) {
883         timestamp += m_wrap_at;
884     }
885
886     return timestamp;
887 }
888
889 /**
890  * @brief Get timestamp for a specific position from the buffer head
891  *
892  * Returns the timestamp for a position that is nframes later than the
893  * buffer head
894  *
895  * @param nframes number of frames
896  * @return timestamp value
897  */
898 ffado_timestamp_t TimestampedBuffer::getTimestampFromHead(int nframes)
899 {
900     ffado_timestamp_t retval;
901     ENTER_CRITICAL_SECTION;
902     retval = getTimestampFromTail(m_framecounter-nframes);
903     EXIT_CRITICAL_SECTION;
904     return retval;
905 }
906
907 /**
908  * Resets the frame counter, in a atomic way. This
909  * is thread safe.
910  */
911 void TimestampedBuffer::resetFrameCounter() {
912     ENTER_CRITICAL_SECTION;
913     m_framecounter = 0;
914     EXIT_CRITICAL_SECTION;
915 }
916
917 /**
918  * Decrements the frame counter in a thread safe way.
919  *
920  * @param nbframes number of frames to decrement
921  */
922 void TimestampedBuffer::decrementFrameCounter(unsigned int nbframes) {
923     ENTER_CRITICAL_SECTION;
924     m_framecounter -= nbframes;
925     EXIT_CRITICAL_SECTION;
926 }
927
928 /**
929  * Increments the frame counter in a thread safe way.
930  * Also updates the timestamp.
931  *
932  * @note the offsets defined by setTicksOffset and setFrameOffset
933  *       are added here.
934  *
935  * @param nbframes the number of frames to add
936  * @param new_timestamp the new timestamp
937  */
938 void TimestampedBuffer::incrementFrameCounter(unsigned int nbframes, ffado_timestamp_t new_timestamp) {
939
940     // require the timestamps to be in the correct range
941     assert(new_timestamp < m_wrap_at);
942     assert(new_timestamp >= 0);
943     // if this is not true the timestamps have to be corrected
944     // to account for the non-uniform update period
945     assert(nbframes == m_update_period);
946
947     // the difference between the given TS and the one predicted for this time instant
948     // this is the error for the DLL
949     ffado_timestamp_t diff = new_timestamp - m_buffer_next_tail_timestamp;
950
951 #ifdef DEBUG
952     // check whether the update is within the allowed bounds
953 /*    const float max_deviation = (50.0/100.0); // maximal relative difference considered normal
954     ffado_timestamp_t one_update_step = nbframes * getRate();
955     ffado_timestamp_t max_abs_diff = one_update_step * (1.0 + max_deviation);*/
956     ffado_timestamp_t max_abs_diff = 200;
957
958     debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
959                        " nbframes: %d, m_update_period: %d \n",
960                        nbframes, m_update_period);
961     debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
962                        " tail TS: "TIMESTAMP_FORMAT_SPEC", next tail TS: "TIMESTAMP_FORMAT_SPEC"\n",
963                        m_buffer_tail_timestamp, m_buffer_next_tail_timestamp);
964     debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
965                        " new TS: "TIMESTAMP_FORMAT_SPEC", diff: "TIMESTAMP_FORMAT_SPEC"\n",
966                        new_timestamp, diff);
967
968     if (diff > max_abs_diff) {
969         //debugShowBackLogLines(100);
970         debugWarning("(%p) difference rather large (+): diff="TIMESTAMP_FORMAT_SPEC", max="TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC"\n",
971             this, diff, max_abs_diff, new_timestamp, m_buffer_next_tail_timestamp);
972     } else if (diff < -max_abs_diff) {
973         //debugShowBackLogLines(100);
974         debugWarning("(%p) difference rather large (-): diff="TIMESTAMP_FORMAT_SPEC", max="TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC"\n",
975             this, diff, -max_abs_diff, new_timestamp, m_buffer_next_tail_timestamp);
976     }
977
978     debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
979                        "(%p): diff="TIMESTAMP_FORMAT_SPEC" ",
980                        this, diff);
981 #endif
982
983     double err = diff;
984     debugOutputShortExtreme(DEBUG_LEVEL_VERY_VERBOSE,
985                             "diff2="TIMESTAMP_FORMAT_SPEC" err=%f\n",
986                             diff, err);
987     debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
988                        "B: FC=%10u, TS="TIMESTAMP_FORMAT_SPEC", NTS="TIMESTAMP_FORMAT_SPEC"\n",
989                        m_framecounter, m_buffer_tail_timestamp, m_buffer_next_tail_timestamp);
990
991     ENTER_CRITICAL_SECTION;
992     m_framecounter += nbframes;
993     m_buffer_tail_timestamp = m_buffer_next_tail_timestamp;
994     m_buffer_next_tail_timestamp = m_buffer_next_tail_timestamp + (ffado_timestamp_t)(m_dll_b * err + m_dll_e2);
995     m_dll_e2 += m_dll_c*err;
996
997     if (m_buffer_next_tail_timestamp >= m_wrap_at) {
998         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
999                            "Unwrapping next tail timestamp: "TIMESTAMP_FORMAT_SPEC"",
1000                            m_buffer_next_tail_timestamp);
1001
1002         m_buffer_next_tail_timestamp -= m_wrap_at;
1003
1004         debugOutputShortExtreme(DEBUG_LEVEL_VERY_VERBOSE,
1005                                 " => "TIMESTAMP_FORMAT_SPEC"\n",
1006                                 m_buffer_next_tail_timestamp);
1007
1008     }
1009     m_current_rate = calculateRate();
1010     EXIT_CRITICAL_SECTION;
1011
1012     debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
1013                        "A: TS="TIMESTAMP_FORMAT_SPEC", NTS="TIMESTAMP_FORMAT_SPEC", DLLe2=%f, RATE=%f\n",
1014                        m_buffer_tail_timestamp, m_buffer_next_tail_timestamp, m_dll_e2, m_current_rate);
1015
1016
1017     if(m_buffer_tail_timestamp>=m_wrap_at) {
1018         debugError("Wrapping failed for m_buffer_tail_timestamp! "TIMESTAMP_FORMAT_SPEC"\n",m_buffer_tail_timestamp);
1019         debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " IN="TIMESTAMP_FORMAT_SPEC", TS="TIMESTAMP_FORMAT_SPEC", NTS="TIMESTAMP_FORMAT_SPEC"\n",
1020                     new_timestamp, m_buffer_tail_timestamp, m_buffer_next_tail_timestamp);
1021
1022     }
1023     if(m_buffer_next_tail_timestamp>=m_wrap_at) {
1024         debugError("Wrapping failed for m_buffer_next_tail_timestamp! "TIMESTAMP_FORMAT_SPEC"\n",m_buffer_next_tail_timestamp);
1025         debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " IN="TIMESTAMP_FORMAT_SPEC", TS="TIMESTAMP_FORMAT_SPEC", NTS="TIMESTAMP_FORMAT_SPEC"\n",
1026                     new_timestamp, m_buffer_tail_timestamp, m_buffer_next_tail_timestamp);
1027     }
1028    
1029     if(m_buffer_tail_timestamp==m_buffer_next_tail_timestamp) {
1030         debugError("Current and next timestamps are equal: "TIMESTAMP_FORMAT_SPEC" "TIMESTAMP_FORMAT_SPEC"\n",
1031                    m_buffer_tail_timestamp,m_buffer_next_tail_timestamp);
1032     }
1033
1034     // this DLL allows the calculation of any sample timestamp relative to the buffer tail,
1035     // to the next period and beyond (through extrapolation)
1036     //
1037     // ts(x) = m_buffer_tail_timestamp +
1038     //         (m_buffer_next_tail_timestamp - m_buffer_tail_timestamp)/(samples_between_updates)*x
1039 }
1040
1041 /**
1042  * @brief Print status info.
1043  */
1044 void TimestampedBuffer::dumpInfo() {
1045
1046     ffado_timestamp_t ts_head;
1047     signed int fc;
1048     getBufferHeadTimestamp(&ts_head,&fc);
1049
1050 #ifdef DEBUG
1051     ffado_timestamp_t diff=(ffado_timestamp_t)ts_head - (ffado_timestamp_t)m_buffer_tail_timestamp;
1052 #endif
1053
1054     debugOutputShort( DEBUG_LEVEL_NORMAL, "  TimestampedBuffer (%p): %04d frames, %04d events\n",
1055                                           this, m_framecounter, getBufferFill());
1056     debugOutputShort( DEBUG_LEVEL_NORMAL, "   Timestamps           : head: "TIMESTAMP_FORMAT_SPEC", Tail: "TIMESTAMP_FORMAT_SPEC", Next tail: "TIMESTAMP_FORMAT_SPEC"\n",
1057                                           ts_head, m_buffer_tail_timestamp, m_buffer_next_tail_timestamp);
1058     debugOutputShort( DEBUG_LEVEL_NORMAL, "    Head - Tail         : "TIMESTAMP_FORMAT_SPEC"\n", diff);
1059     debugOutputShort( DEBUG_LEVEL_NORMAL, "   DLL Rate             : %f (%f)\n", m_dll_e2, m_dll_e2/m_update_period);
1060 }
1061
1062 } // end of namespace Util
Note: See TracBrowser for help on using the browser.