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

Revision 807, 41.7 kB (checked in by ppalmers, 15 years ago)

more reliability things

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 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 3 of the License, or
12  * (at your option) any later version.
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 /*
41 #define ENTER_CRITICAL_SECTION { \
42     if (pthread_mutex_trylock(&m_framecounter_lock) == EBUSY) { \
43         debugWarning(" (%p) lock clash\n", this); \
44         pthread_mutex_lock(&m_framecounter_lock); \
45     } \
46     }
47 */
48 #define ENTER_CRITICAL_SECTION { \
49     pthread_mutex_lock(&m_framecounter_lock); \
50     }
51 #define EXIT_CRITICAL_SECTION { \
52     pthread_mutex_unlock(&m_framecounter_lock); \
53     }
54
55 namespace Util {
56
57 IMPL_DEBUG_MODULE( TimestampedBuffer, TimestampedBuffer, DEBUG_LEVEL_VERBOSE );
58
59 TimestampedBuffer::TimestampedBuffer(TimestampedBufferClient *c)
60     : m_event_buffer(NULL), m_cluster_buffer(NULL),
61       m_event_size(0), m_events_per_frame(0), m_buffer_size(0),
62       m_bytes_per_frame(0), m_bytes_per_buffer(0),
63       m_enabled( false ), m_transparent ( true ),
64       m_wrap_at(0xFFFFFFFFFFFFFFFFLLU),
65       m_Client(c), m_framecounter(0),
66       m_tick_offset(0.0),
67       m_buffer_tail_timestamp(0.0),
68       m_buffer_next_tail_timestamp(0.0),
69       m_dll_e2(0.0), m_dll_b(DLL_COEFF_B), m_dll_c(DLL_COEFF_C),
70       m_nominal_rate(0.0), m_current_rate(0.0), m_update_period(0)
71 {
72     pthread_mutex_init(&m_framecounter_lock, NULL);
73 }
74
75 TimestampedBuffer::~TimestampedBuffer() {
76     ffado_ringbuffer_free(m_event_buffer);
77     free(m_cluster_buffer);
78 }
79
80 /**
81  * \brief Set the nominal rate in frames/timeunit
82  *
83  * Sets the nominal rate in frames per time unit. This rate is used
84  * to initialize the DLL that will extract the effective rate based
85  * upon the timestamps it gets fed.
86  *
87  * @param r rate
88  * @return true if successful
89  */
90 bool TimestampedBuffer::setNominalRate(float r) {
91     m_nominal_rate=r;
92     debugOutput(DEBUG_LEVEL_VERBOSE," nominal rate=%e set to %e\n",
93                                     m_nominal_rate, r);
94     return true;
95 }
96
97 /**
98  * \brief Set the nominal update period (in frames)
99  *
100  * Sets the nominal update period. This period is the number of frames
101  * between two timestamp updates (hence buffer writes)
102  *
103  * @param n period in frames
104  * @return true if successful
105  */
106 bool TimestampedBuffer::setUpdatePeriod(unsigned int n) {
107     m_update_period=n;
108     return true;
109 }
110
111 /**
112  * \brief Get the nominal update period (in frames)
113  *
114  * Gets the nominal update period. This period is the number of frames
115  * between two timestamp updates (hence buffer writes)
116  *
117  * @return period in frames
118  */
119 unsigned int TimestampedBuffer::getUpdatePeriod() {
120     return m_update_period;
121 }
122
123 /**
124  * \brief set the value at which timestamps should wrap around
125  * @param w value to wrap at
126  * @return true if successful
127  */
128 bool TimestampedBuffer::setWrapValue(ffado_timestamp_t w) {
129     m_wrap_at=w;
130     return true;
131 }
132 #include <math.h>
133
134 /**
135  * \brief return the effective rate
136  *
137  * Returns the effective rate calculated by the DLL.
138  *
139  * @return rate (in timeunits/frame)
140  */
141 float TimestampedBuffer::getRate() {
142     return m_current_rate;
143 }
144
145 /**
146  * \brief calculate the effective rate
147  *
148  * Returns the effective rate calculated by the DLL.
149  * @note should be called with the lock held
150  * @return rate (in timeunits/frame)
151  */
152 float TimestampedBuffer::calculateRate() {
153     ffado_timestamp_t diff;
154    
155     diff=m_buffer_next_tail_timestamp - m_buffer_tail_timestamp;
156    
157     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"getRate: %f/%f=%f\n",
158         (float)(diff),
159         (float)m_update_period,
160         ((float)(diff))/((float) m_update_period));
161    
162     // the maximal difference we can allow (64secs)
163     const ffado_timestamp_t max=m_wrap_at/((ffado_timestamp_t)2);
164
165     if(diff > max) {
166         diff -= m_wrap_at;
167     } else if (diff < -max) {
168         diff += m_wrap_at;
169     }
170
171     float rate=((float)diff)/((float) m_update_period);
172     if (rate<0.0) debugError("rate < 0! (%f)\n",rate);
173     if (fabsf(m_nominal_rate - rate)>(m_nominal_rate*0.1)) {
174         debugWarning("(%p) rate (%10.5f) more that 10%% off nominal (rate=%10.5f, diff="TIMESTAMP_FORMAT_SPEC", update_period=%d)\n",
175                      this, rate,m_nominal_rate,diff, m_update_period);
176
177         return m_nominal_rate;
178     } else {
179         return rate;
180     }
181 }
182
183 /**
184  * \brief Sets the size of the events
185  * @param s event size in bytes
186  * @return true if successful
187  */
188 bool TimestampedBuffer::setEventSize(unsigned int s) {
189     m_event_size=s;
190
191     m_bytes_per_frame=m_event_size*m_events_per_frame;
192     m_bytes_per_buffer=m_bytes_per_frame*m_buffer_size;
193
194     return true;
195 }
196
197 /**
198  * \brief Sets the number of events per frame
199  * @param n number of events per frame
200  * @return true if successful
201  */
202 bool TimestampedBuffer::setEventsPerFrame(unsigned int n) {
203     m_events_per_frame=n;
204
205     m_bytes_per_frame=m_event_size*m_events_per_frame;
206     m_bytes_per_buffer=m_bytes_per_frame*m_buffer_size;
207
208     return true;
209 }
210 /**
211  * \brief Sets the buffer size in frames
212  * @param n number frames
213  * @return true if successful
214  */
215 bool TimestampedBuffer::setBufferSize(unsigned int n) {
216     m_buffer_size=n;
217
218     m_bytes_per_frame=m_event_size*m_events_per_frame;
219     m_bytes_per_buffer=m_bytes_per_frame*m_buffer_size;
220
221     return true;
222 }
223
224 /**
225  * Sets the buffer offset in ticks.
226  *
227  * A positive value means that the buffer is 'delayed' for nticks ticks.
228  *
229  * @note These offsets are only used when reading timestamps. Any function
230  *       that returns a timestamp will incorporate this offset.
231  * @param nframes the number of ticks (positive = delay buffer)
232  * @return true if successful
233  */
234 bool TimestampedBuffer::setTickOffset(ffado_timestamp_t nticks) {
235     debugOutput(DEBUG_LEVEL_VERBOSE,"Setting ticks offset to "TIMESTAMP_FORMAT_SPEC"\n",nticks);
236
237     // JMW: I think we need to update the internal DLL state to take account
238     // of the new offset.  Doing so certainly makes for a smoother MOTU
239     // startup.
240     ENTER_CRITICAL_SECTION;
241     m_buffer_tail_timestamp = m_buffer_tail_timestamp - m_tick_offset + nticks;
242     m_buffer_next_tail_timestamp = (ffado_timestamp_t)((double)m_buffer_tail_timestamp + m_dll_e2);
243     m_tick_offset=nticks;
244     EXIT_CRITICAL_SECTION;
245
246     return true;
247 }
248
249 /**
250  * \brief Returns the current fill of the buffer
251  *
252  * This returns the buffer fill of the internal ringbuffer. This
253  * can only be used as an indication because it's state is not
254  * guaranteed to be consistent at all times due to threading issues.
255  *
256  * In order to get the number of frames in the buffer, use the
257  * getBufferHeadTimestamp, getBufferTailTimestamp
258  * functions
259  *
260  * @return the internal buffer fill in frames
261  */
262 unsigned int TimestampedBuffer::getBufferFill() {
263     return ffado_ringbuffer_read_space(m_event_buffer)/(m_bytes_per_frame);
264 }
265
266 /**
267  * \brief Returns the current write space in the buffer
268  *
269  * This returns the buffer free space of the internal ringbuffer. This
270  * can only be used as an indication because it's state is not
271  * guaranteed to be consistent at all times due to threading issues.
272  *
273  * @return the internal buffer fill in frames
274  */
275 unsigned int TimestampedBuffer::getBufferSpace() {
276     return ffado_ringbuffer_write_space(m_event_buffer)/(m_bytes_per_frame);
277 }
278
279 /**
280  * \brief Initializes the TimestampedBuffer
281  *
282  * Initializes the TimestampedBuffer, should be called before anything else
283  * is done.
284  *
285  * @return true if successful
286  */
287 bool TimestampedBuffer::init() {
288     return true;
289 }
290
291 /**
292  * \brief Resets the TimestampedBuffer
293  *
294  * Resets the TimestampedBuffer, clearing the buffers and counters.
295  * (not true yet: Also resets the DLL to the nominal values.)
296  *
297  * \note when this is called, you should make sure that the buffer
298  *       tail timestamp gets set before continuing
299  *
300  * @return true if successful
301  */
302 bool TimestampedBuffer::clearBuffer() {
303     debugOutput(DEBUG_LEVEL_VERBOSE, "Clearing buffer\n");
304     ffado_ringbuffer_reset(m_event_buffer);
305     resetFrameCounter();
306     return true;
307 }
308
309 /**
310  * \brief Prepares the TimestampedBuffer
311  *
312  * Prepare the TimestampedBuffer. This allocates all internal buffers and
313  * initializes all data structures.
314  *
315  * This should be called after parameters such as buffer size, event size etc.. are set,
316  * and before any read/write operations are performed.
317  *
318  * @return true if successful
319  */
320 bool TimestampedBuffer::prepare() {
321     debugOutput(DEBUG_LEVEL_VERBOSE,"Preparing buffer (%p)\n",this);
322     debugOutput(DEBUG_LEVEL_VERBOSE," Size=%u events, events/frame=%u, event size=%ubytes\n",
323                                         m_buffer_size,m_events_per_frame,m_event_size);
324
325     debugOutput(DEBUG_LEVEL_VERBOSE," update period %u\n",
326                                     m_update_period);
327     debugOutput(DEBUG_LEVEL_VERBOSE," nominal rate=%f\n",
328                                     m_nominal_rate);
329
330     debugOutput(DEBUG_LEVEL_VERBOSE," wrapping at "TIMESTAMP_FORMAT_SPEC"\n",m_wrap_at);
331
332     assert(m_buffer_size);
333     assert(m_events_per_frame);
334     assert(m_event_size);
335
336     assert(m_nominal_rate != 0.0L);
337     assert(m_update_period != 0);
338
339     m_current_rate = m_nominal_rate;
340
341     if( !(m_event_buffer=ffado_ringbuffer_create(
342             (m_events_per_frame * m_buffer_size) * m_event_size))) {
343         debugFatal("Could not allocate memory event ringbuffer\n");
344         return false;
345     }
346
347     // allocate the temporary cluster buffer
348     if( !(m_cluster_buffer=(char *)calloc(m_events_per_frame,m_event_size))) {
349             debugFatal("Could not allocate temporary cluster buffer\n");
350         ffado_ringbuffer_free(m_event_buffer);
351         return false;
352     }
353
354     // init the DLL
355     m_dll_e2=m_nominal_rate * (float)m_update_period;
356
357     m_dll_b=((float)(DLL_COEFF_B));
358     m_dll_c=((float)(DLL_COEFF_C));
359    
360     // this will init the internal timestamps to a sensible value
361     setBufferTailTimestamp(m_buffer_tail_timestamp);
362    
363     return true;
364 }
365
366 /**
367  * @brief Insert a dummy frame to the head buffer
368  *
369  * Writes one frame of dummy data to the head of the buffer.
370  * This is to assist the phase sync of several buffers.
371  *
372  * Note: currently the dummy data is added to the tail of the
373  *       buffer, but without updating the timestamp.
374  *
375  * @return true if successful
376  */
377 bool TimestampedBuffer::writeDummyFrame() {
378
379     unsigned int write_size=m_event_size*m_events_per_frame;
380    
381     char dummy[write_size]; // one frame of garbage
382     memset(dummy,0,write_size);
383
384     // add the data payload to the ringbuffer
385     if (ffado_ringbuffer_write(m_event_buffer,dummy,write_size) < write_size)
386     {
387 //         debugWarning("writeFrames buffer overrun\n");
388         return false;
389     }
390
391 //     incrementFrameCounter(nframes,ts);
392    
393     // increment without updating the DLL
394     ENTER_CRITICAL_SECTION;
395     m_framecounter++;
396     EXIT_CRITICAL_SECTION;
397     return true;
398 }
399
400 /**
401  * @brief Write frames to the buffer
402  *
403  * Copies \ref nframes of frames from the buffer pointed to by \ref data to the
404  * internal ringbuffer. The time of the last frame in the buffer is set to \ref ts.
405  *
406  * @param nframes number of frames to copy
407  * @param data pointer to the frame buffer
408  * @param ts timestamp of the last frame copied
409  * @return true if successful
410  */
411 bool TimestampedBuffer::writeFrames(unsigned int nframes, char *data, ffado_timestamp_t ts) {
412
413     unsigned int write_size=nframes*m_event_size*m_events_per_frame;
414
415     if (m_transparent) {
416         // while disabled, we don't update the DLL, nor do we write frames
417         // we just set the correct timestamp for the frames
418         setBufferTailTimestamp(ts);
419     } else {
420         // add the data payload to the ringbuffer
421         size_t written = ffado_ringbuffer_write(m_event_buffer, data, write_size);
422         if (written < write_size)
423         {
424             debugWarning("ringbuffer full, %u, %u\n", write_size, written);
425             return false;
426         }
427         incrementFrameCounter(nframes,ts);
428     }
429     return true;
430 }
431
432 /**
433  * @brief Preload frames into the buffer
434  *
435  * Preload \ref nframes of frames from the buffer pointed to by \ref data to the
436  * internal ringbuffer. Does not care about transparency. Keeps the buffer head or tail
437  * timestamp constant.
438  *
439  * @note not thread safe
440  *
441  * @param nframes number of frames to copy
442  * @param data pointer to the frame buffer
443  * @param keep_head_ts if true, keep the head timestamp constant. If false, keep the
444  *                     tail timestamp constant.
445  * @return true if successful
446  */
447 bool TimestampedBuffer::preloadFrames(unsigned int nframes, char *data, bool keep_head_ts) {
448     unsigned int write_size = nframes * m_event_size * m_events_per_frame;
449     // add the data payload to the ringbuffer
450     size_t written = ffado_ringbuffer_write(m_event_buffer, data, write_size);
451     if (written < write_size)
452     {
453         debugWarning("ringbuffer full, request: %u, actual: %u\n", write_size, written);
454         return false;
455     }
456    
457     // make sure the head timestamp remains identical
458     signed int fc;
459     ffado_timestamp_t ts;
460
461     if (keep_head_ts) {
462         getBufferHeadTimestamp(&ts, &fc);
463     } else {
464         getBufferTailTimestamp(&ts, &fc);
465     }
466     // update frame counter
467     m_framecounter += nframes;
468     if (keep_head_ts) {
469         setBufferHeadTimestamp(ts);
470     } else {
471         setBufferTailTimestamp(ts);
472     }
473     return true;
474 }
475
476 /**
477  * @brief Drop frames from the head of the buffer
478  *
479  * drops \ref nframes of frames from the head of internal buffer
480  *
481  * @param nframes number of frames to drop
482  * @return true if successful
483  */
484 bool
485 TimestampedBuffer::dropFrames(unsigned int nframes) {
486     unsigned int read_size = nframes * m_event_size * m_events_per_frame;
487     ffado_ringbuffer_read_advance(m_event_buffer, read_size);
488     decrementFrameCounter(nframes);
489     return true;
490 }
491
492 /**
493  * @brief Read frames from the buffer
494  *
495  * Copies \ref nframes of frames from the internal buffer to the data buffer pointed
496  * to by \ref data.
497  *
498  * @param nframes number of frames to copy
499  * @param data pointer to the frame buffer
500  * @return true if successful
501  */
502 bool TimestampedBuffer::readFrames(unsigned int nframes, char *data) {
503
504     unsigned int read_size=nframes*m_event_size*m_events_per_frame;
505
506     if (m_transparent) {
507         return true; // FIXME: the data still doesn't make sense!
508     } else {
509         // get the data payload to the ringbuffer
510         if ((ffado_ringbuffer_read(m_event_buffer,data,read_size)) < read_size)
511         {
512             debugWarning("readFrames buffer underrun\n");
513             return false;
514         }
515         decrementFrameCounter(nframes);
516     }
517     return true;
518 }
519
520 /**
521  * @brief Performs block processing write of frames
522  *
523  * This function allows for zero-copy writing into the ringbuffer.
524  * It calls the client's processWriteBlock function to write frames
525  * into the internal buffer's data area, in a thread safe fashion.
526  *
527  * It also updates the timestamp.
528  *
529  * @param nbframes number of frames to process
530  * @param ts timestamp of the last frame written to the buffer
531  * @return true if successful
532  */
533 bool TimestampedBuffer::blockProcessWriteFrames(unsigned int nbframes, ffado_timestamp_t ts) {
534
535     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Transferring period...\n");
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     unsigned int cluster_size=m_events_per_frame*m_event_size;
554
555     while(bytes2write>0) {
556         int byteswritten=0;
557
558         unsigned int frameswritten=(nbframes*cluster_size-bytes2write)/cluster_size;
559         offset=frameswritten;
560
561         ffado_ringbuffer_get_write_vector(m_event_buffer, vec);
562
563         if(vec[0].len==0) { // this indicates a full event buffer
564             debugError("Event buffer overrun in buffer %p, fill: %u, bytes2write: %u \n",
565                        this, ffado_ringbuffer_read_space(m_event_buffer), bytes2write);
566             debugShowBackLog();
567             return false;
568         }
569
570         /* if we don't take care we will get stuck in an infinite loop
571         * because we align to a cluster boundary later
572         * the remaining nb of bytes in one write operation can be
573         * smaller than one cluster
574         * this can happen because the ringbuffer size is always a power of 2
575         */
576         if(vec[0].len<cluster_size) {
577
578             // encode to the temporary buffer
579             xrun = m_Client->processWriteBlock(m_cluster_buffer, 1, offset);
580
581             if(xrun<0) {
582                 // xrun detected
583                 debugError("Frame buffer underrun in buffer %p\n",this);
584                 return false;
585             }
586
587             // use the ringbuffer function to write one cluster
588             // the write function handles the wrap around.
589             ffado_ringbuffer_write(m_event_buffer,
590                          m_cluster_buffer,
591                          cluster_size);
592
593             // we advanced one cluster_size
594             bytes2write-=cluster_size;
595
596         } else { //
597
598             if(bytes2write>vec[0].len) {
599                 // align to a cluster boundary
600                 byteswritten=vec[0].len-(vec[0].len%cluster_size);
601             } else {
602                 byteswritten=bytes2write;
603             }
604
605             xrun = m_Client->processWriteBlock(vec[0].buf,
606                          byteswritten/cluster_size,
607                          offset);
608
609             if(xrun<0) {
610                     // xrun detected
611                 debugError("Frame buffer underrun in buffer %p\n",this);
612                 return false; // FIXME: return false ?
613             }
614
615             ffado_ringbuffer_write_advance(m_event_buffer, byteswritten);
616             bytes2write -= byteswritten;
617         }
618
619         // the bytes2write should always be cluster aligned
620         assert(bytes2write%cluster_size==0);
621
622     }
623
624     incrementFrameCounter(nbframes,ts);
625
626     return true;
627
628 }
629
630 /**
631  * @brief Performs block processing read of frames
632  *
633  * This function allows for zero-copy reading from the ringbuffer.
634  * It calls the client's processReadBlock function to read frames
635  * directly from the internal buffer's data area, in a thread safe
636  * fashion.
637  *
638  * @param nbframes number of frames to process
639  * @return true if successful
640  */
641 bool TimestampedBuffer::blockProcessReadFrames(unsigned int nbframes) {
642
643     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Reading %u from buffer (%p)...\n", nbframes, this);
644
645     int xrun;
646     unsigned int offset=0;
647
648     ffado_ringbuffer_data_t vec[2];
649     // we received one period of frames on each connection
650     // this is period_size*dimension of events
651
652     unsigned int events2read=nbframes*m_events_per_frame;
653     unsigned int bytes2read=events2read*m_event_size;
654     /* read events2read bytes from the ringbuffer
655     *  first see if it can be done in one read.
656     *  if so, ok.
657     *  otherwise read up to a multiple of clusters directly from the buffer
658     *  then do the buffer wrap around using ringbuffer_read
659     *  then read the remaining data directly from the buffer in a third pass
660     *  Make sure that we cannot end up on a non-cluster aligned position!
661     */
662     unsigned int cluster_size=m_events_per_frame*m_event_size;
663
664     while(bytes2read>0) {
665         unsigned int framesread=(nbframes*cluster_size-bytes2read)/cluster_size;
666         offset=framesread;
667
668         int bytesread=0;
669
670         ffado_ringbuffer_get_read_vector(m_event_buffer, vec);
671
672         if(vec[0].len==0) { // this indicates an empty event buffer
673             debugError("Event buffer underrun in buffer %p\n",this);
674             return false;
675         }
676
677         /* if we don't take care we will get stuck in an infinite loop
678         * because we align to a cluster boundary later
679         * the remaining nb of bytes in one read operation can be smaller than one cluster
680         * this can happen because the ringbuffer size is always a power of 2
681                 */
682         if(vec[0].len<cluster_size) {
683             // use the ringbuffer function to read one cluster
684             // the read function handles wrap around
685             ffado_ringbuffer_read(m_event_buffer,m_cluster_buffer,cluster_size);
686
687             assert(m_Client);
688             xrun = m_Client->processReadBlock(m_cluster_buffer, 1, offset);
689
690             if(xrun<0) {
691                 // xrun detected
692                 debugError("Frame buffer overrun in buffer %p\n",this);
693                     return false;
694             }
695
696             // we advanced one cluster_size
697             bytes2read-=cluster_size;
698
699         } else { //
700
701             if(bytes2read>vec[0].len) {
702                 // align to a cluster boundary
703                 bytesread=vec[0].len-(vec[0].len%cluster_size);
704             } else {
705                 bytesread=bytes2read;
706             }
707
708             assert(m_Client);
709             xrun = m_Client->processReadBlock(vec[0].buf, bytesread/cluster_size, offset);
710
711             if(xrun<0) {
712                 // xrun detected
713                 debugError("Frame buffer overrun in buffer %p\n",this);
714                 return false;
715             }
716
717             ffado_ringbuffer_read_advance(m_event_buffer, bytesread);
718             bytes2read -= bytesread;
719         }
720
721         // the bytes2read should always be cluster aligned
722         assert(bytes2read%cluster_size==0);
723     }
724
725     decrementFrameCounter(nbframes);
726
727     return true;
728 }
729
730 /**
731  * @brief Sets the buffer tail timestamp.
732  *
733  * Set the buffer tail timestamp to \ref new_timestamp. This will recalculate
734  * the internal state such that the buffer's timeframe starts at
735  * \ref new_timestamp.
736  *
737  * This is thread safe.
738  *
739  * @note considers offsets
740  *
741  * @param new_timestamp
742  */
743 void TimestampedBuffer::setBufferTailTimestamp(ffado_timestamp_t new_timestamp) {
744
745     // add the offsets
746     ffado_timestamp_t ts=new_timestamp;
747     ts += m_tick_offset;
748
749     if (ts >= m_wrap_at) {
750         ts -= m_wrap_at;
751     } else if (ts < 0) {
752         ts += m_wrap_at;
753     }
754
755 #ifdef DEBUG
756     if (new_timestamp >= m_wrap_at) {
757         debugWarning("timestamp not wrapped: "TIMESTAMP_FORMAT_SPEC"\n",new_timestamp);
758     }
759     if ((ts >= m_wrap_at) || (ts < 0 )) {
760         debugWarning("ts not wrapped correctly: "TIMESTAMP_FORMAT_SPEC"\n",ts);
761     }
762 #endif
763
764     ENTER_CRITICAL_SECTION;
765
766     m_buffer_tail_timestamp = ts;
767
768     m_dll_e2=m_update_period * (double)m_nominal_rate;
769     m_buffer_next_tail_timestamp = (ffado_timestamp_t)((double)m_buffer_tail_timestamp + m_dll_e2);
770
771     EXIT_CRITICAL_SECTION;
772
773     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "for (%p) to "
774                                           TIMESTAMP_FORMAT_SPEC" => "TIMESTAMP_FORMAT_SPEC", NTS="
775                                           TIMESTAMP_FORMAT_SPEC", DLL2=%f, RATE=%f\n",
776                 this, new_timestamp, ts, m_buffer_next_tail_timestamp, m_dll_e2, getRate());
777
778 }
779
780 /**
781  * @brief Sets the buffer head timestamp.
782  *
783  * Set the buffer tail timestamp such that the buffer head timestamp becomes
784  * \ref new_timestamp. This does not consider offsets, because it's use is to
785  * make sure the following is true after setBufferHeadTimestamp(x):
786  *   x == getBufferHeadTimestamp()
787  *
788  * This is thread safe.
789  *
790  * @param new_timestamp
791  */
792 void TimestampedBuffer::setBufferHeadTimestamp(ffado_timestamp_t new_timestamp) {
793
794 #ifdef DEBUG
795     if (new_timestamp >= m_wrap_at) {
796         debugWarning("timestamp not wrapped: "TIMESTAMP_FORMAT_SPEC"\n",new_timestamp);
797     }
798 #endif
799
800     ffado_timestamp_t ts = new_timestamp;
801
802     ENTER_CRITICAL_SECTION;
803
804     // add the time
805     ts += (ffado_timestamp_t)(m_nominal_rate * (float)m_framecounter);
806
807     if (ts >= m_wrap_at) {
808         ts -= m_wrap_at;
809     } else if (ts < 0) {
810         ts += m_wrap_at;
811     }
812
813     m_buffer_tail_timestamp = ts;
814
815     m_dll_e2=m_update_period * (double)m_nominal_rate;
816     m_buffer_next_tail_timestamp = (ffado_timestamp_t)((double)m_buffer_tail_timestamp + m_dll_e2);
817
818     EXIT_CRITICAL_SECTION;
819
820     debugOutput(DEBUG_LEVEL_VERBOSE, "for (%p) to "TIMESTAMP_FORMAT_SPEC" => "
821                                           TIMESTAMP_FORMAT_SPEC", NTS="TIMESTAMP_FORMAT_SPEC", DLL2=%f, RATE=%f\n",
822                 this, new_timestamp, ts, m_buffer_next_tail_timestamp, m_dll_e2, getRate());
823
824 }
825
826 /**
827  * @brief Synchronize the buffer head to a specified timestamp
828  *
829  * Try to synchronize the buffer head to a specific timestamp. This
830  * can mean adding or removing samples to/from the buffer such that
831  * the buffer head aligns with the specified timestamp. The alignment
832  * is within ts +/- Tsample/2
833  *
834  * @param target the timestamp to align to
835  * @return true if alignment succeeded, false if not
836  */
837 bool
838 TimestampedBuffer::syncBufferHeadToTimestamp(ffado_timestamp_t target)
839 {
840     uint64_t ts_head;
841     uint64_t ts_target=(uint64_t)target;
842     signed int fc;
843     int32_t lag_ticks;
844     float lag_frames;
845
846     ffado_timestamp_t ts_head_tmp;
847     getBufferHeadTimestamp(&ts_head_tmp, &fc);
848     ts_head=(uint64_t)ts_head_tmp;
849     // if target > ts_head then the wanted buffer head timestamp
850     // is later than the actual. This means that we (might) have to drop
851     // some frames.
852     lag_ticks=diffTicks(ts_target, ts_head);
853     float rate=getRate();
854    
855     assert(rate!=0.0);
856
857     lag_frames=(((float)lag_ticks)/rate);
858    
859     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): HEAD=%llu, TS=%llu, diff=%ld = %10.5f frames (rate=%10.5f)\n",
860                                       this, ts_head, ts_target, lag_ticks, lag_frames, rate);
861
862     if (lag_frames>=1.0) {
863         // the buffer head is too early
864         // ditch frames until the buffer head is on time
865         char dummy[getBytesPerFrame()]; // one frame of garbage
866         int frames_to_ditch=(int)roundf(lag_frames);
867         debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): ditching %d frames (@ ts=%lld)\n",this,frames_to_ditch,ts_target);
868        
869         while (frames_to_ditch--) {
870             readFrames(1, dummy);
871         }
872        
873     } else if (lag_frames<=-1.0) {
874         // the buffer head is too late
875         // add some padding frames
876         int frames_to_add=(int)roundf(lag_frames);
877         debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): adding %d frames (@ ts=%lld)\n",this,-frames_to_add,ts_target);
878        
879         while (frames_to_add++) {
880              writeDummyFrame();
881         }
882     }
883     getBufferHeadTimestamp(&ts_head_tmp, &fc);
884     ts_head=(uint64_t)ts_head_tmp;
885     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): new HEAD=%llu, fc=%d, target=%llu, new diff=%lld\n",
886                                       this, ts_head, fc, ts_target, diffTicks(ts_target, ts_head));
887     // FIXME: of course this doesn't always succeed
888     return true;
889 }
890
891 /**
892  * @brief Synchronize the buffer tail to a specified timestamp
893  *
894  * Try to synchronize the buffer tail to a specific timestamp. This
895  * can mean adding or removing samples to/from the buffer such that
896  * the buffer tail aligns with the specified timestamp. The alignment
897  * is within ts +/- Tsample/2
898  *
899  * @param target the timestamp to align to
900  * @return true if alignment succeeded, false if not
901  */
902 bool
903 TimestampedBuffer::syncBufferTailToTimestamp(ffado_timestamp_t target)
904 {
905     uint64_t ts_tail;
906     uint64_t ts_target=(uint64_t)target;
907     signed int fc;
908     int32_t lag_ticks;
909     float lag_frames;
910
911     debugWarning("Untested\n");
912    
913     ffado_timestamp_t ts_tail_tmp;
914     getBufferTailTimestamp(&ts_tail_tmp, &fc);
915     ts_tail=(uint64_t)ts_tail_tmp;
916     // if target < ts_tail then the wanted buffer head timestamp
917     // is later than the actual. This means that we (might) have to drop
918     // some frames.
919     lag_ticks=diffTicks(ts_tail, ts_target);
920     float rate=getRate();
921    
922     assert(rate!=0.0);
923
924     lag_frames=(((float)lag_ticks)/rate);
925    
926     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): HEAD=%llu, TS=%llu, diff=%ld = %10.5f frames (rate=%10.5f)\n",
927                                       this, ts_tail, ts_target, lag_ticks, lag_frames, rate);
928
929     if (lag_frames>=1.0) {
930         // the buffer head is too early
931         // ditch frames until the buffer head is on time
932         char dummy[getBytesPerFrame()]; // one frame of garbage
933         int frames_to_ditch=(int)roundf(lag_frames);
934         debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): ditching %d frames (@ ts=%lld)\n",this,frames_to_ditch,ts_target);
935        
936         while (frames_to_ditch--) {
937             readFrames(1, dummy);
938         }
939        
940     } else if (lag_frames<=-1.0) {
941         // the buffer head is too late
942         // add some padding frames
943         int frames_to_add=(int)roundf(lag_frames);
944         debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): adding %d frames (@ ts=%lld)\n",this,-frames_to_add,ts_target);
945        
946         while (frames_to_add++) {
947              writeDummyFrame();
948         }
949     }
950     getBufferHeadTimestamp(&ts_tail_tmp, &fc);
951     ts_tail=(uint64_t)ts_tail_tmp;
952     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): new HEAD=%llu, fc=%d, target=%llu, new diff=%lld\n",
953                                       this, ts_tail, fc, ts_target, diffTicks(ts_target, ts_tail));
954     // FIXME: of course this doesn't always succeed
955     return true;
956 }
957
958 /**
959  * @brief correct lag
960  *
961  * Try to synchronize the buffer tail to a specific timestamp. This
962  * can mean adding or removing samples to/from the buffer such that
963  * the buffer tail aligns with the specified timestamp. The alignment
964  * is within ts +/- Tsample/2
965  *
966  * @param target the timestamp to align to
967  * @return true if alignment succeeded, false if not
968  */
969 bool
970 TimestampedBuffer::syncCorrectLag(int64_t lag_ticks)
971 {
972     float lag_frames;
973     float rate=getRate();
974     assert(rate!=0.0);
975
976     lag_frames=(((float)lag_ticks)/rate);
977     if (lag_frames >= 1.0) {
978         // the buffer head is too late
979         // add some padding frames
980         int frames_to_add=(int)roundf(lag_frames);
981         debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): adding %d frames\n",this,frames_to_add);
982
983         while (frames_to_add++) {
984              writeDummyFrame();
985         }
986     } else if (lag_frames <= -1.0) {
987         // the buffer head is too early
988         // ditch frames until the buffer head is on time
989         char dummy[getBytesPerFrame()]; // one frame of garbage
990         int frames_to_ditch=(int)roundf(lag_frames);
991         debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): ditching %d frames\n",this,-frames_to_ditch);
992
993         while (frames_to_ditch--) {
994             readFrames(1, dummy);
995         }
996     }
997     return true;
998 }
999
1000 /**
1001  * \brief return the timestamp of the first frame in the buffer
1002  *
1003  * This function returns the timestamp of the very first sample in
1004  * the StreamProcessor's buffer. It also returns the framecounter value
1005  * for which this timestamp is valid.
1006  *
1007  * @param ts address to store the timestamp in
1008  * @param fc address to store the associated framecounter in
1009  */
1010 void TimestampedBuffer::getBufferHeadTimestamp(ffado_timestamp_t *ts, signed int *fc) {
1011     // NOTE: this is still ok with threads, because we use *fc to compute
1012     //       the timestamp
1013     *fc = m_framecounter;
1014     *ts = getTimestampFromTail(*fc);
1015 }
1016
1017 /**
1018  * \brief return the timestamp of the last frame in the buffer
1019  *
1020  * This function returns the timestamp of the last frame in
1021  * the StreamProcessor's buffer. It also returns the framecounter
1022  * value for which this timestamp is valid.
1023  *
1024  * @param ts address to store the timestamp in
1025  * @param fc address to store the associated framecounter in
1026  */
1027 void TimestampedBuffer::getBufferTailTimestamp(ffado_timestamp_t *ts, signed int *fc) {
1028     // NOTE: this is still ok with threads, because we use *fc to compute
1029     //       the timestamp
1030     *fc = m_framecounter;
1031     *ts = getTimestampFromTail(0);
1032 }
1033
1034 /**
1035  * @brief Get timestamp for a specific position from the buffer tail
1036  *
1037  * Returns the timestamp for a position that is nframes earlier than the
1038  * buffer tail
1039  *
1040  * @param nframes number of frames
1041  * @return timestamp value
1042  */
1043 ffado_timestamp_t TimestampedBuffer::getTimestampFromTail(int nframes)
1044 {
1045     // ts(x) = m_buffer_tail_timestamp -
1046     //         (m_buffer_next_tail_timestamp - m_buffer_tail_timestamp)/(samples_between_updates)*(x)
1047     ffado_timestamp_t timestamp;
1048     timestamp = m_buffer_tail_timestamp;
1049
1050     timestamp -= (ffado_timestamp_t)((nframes) * m_current_rate);
1051
1052     if(timestamp >= m_wrap_at) {
1053         timestamp -= m_wrap_at;
1054     } else if(timestamp < 0) {
1055         timestamp += m_wrap_at;
1056     }
1057
1058     return timestamp;
1059 }
1060
1061 /**
1062  * @brief Get timestamp for a specific position from the buffer head
1063  *
1064  * Returns the timestamp for a position that is nframes later than the
1065  * buffer head
1066  *
1067  * @param nframes number of frames
1068  * @return timestamp value
1069  */
1070 ffado_timestamp_t TimestampedBuffer::getTimestampFromHead(int nframes)
1071 {
1072     return getTimestampFromTail(m_framecounter-nframes);
1073 }
1074
1075 /**
1076  * Resets the frame counter, in a atomic way. This
1077  * is thread safe.
1078  */
1079 void TimestampedBuffer::resetFrameCounter() {
1080     ENTER_CRITICAL_SECTION;
1081     m_framecounter = 0;
1082     EXIT_CRITICAL_SECTION;
1083 }
1084
1085 /**
1086  * Decrements the frame counter in a thread safe way.
1087  *
1088  * @param nbframes number of frames to decrement
1089  */
1090 void TimestampedBuffer::decrementFrameCounter(int nbframes) {
1091     ENTER_CRITICAL_SECTION;
1092     m_framecounter -= nbframes;
1093     EXIT_CRITICAL_SECTION;
1094 }
1095
1096 /**
1097  * Increments the frame counter in a thread safe way.
1098  * Also updates the timestamp.
1099  *
1100  * @note the offsets defined by setTicksOffset and setFrameOffset
1101  *       are added here.
1102  *
1103  * @param nbframes the number of frames to add
1104  * @param new_timestamp the new timestamp
1105  */
1106 void TimestampedBuffer::incrementFrameCounter(int nbframes, ffado_timestamp_t new_timestamp) {
1107
1108     // add the offsets
1109     ffado_timestamp_t diff;
1110    
1111     ENTER_CRITICAL_SECTION;
1112     diff = m_buffer_next_tail_timestamp - m_buffer_tail_timestamp;
1113     EXIT_CRITICAL_SECTION;
1114
1115     if (diff < 0) diff += m_wrap_at;
1116
1117     ffado_timestamp_t ts = new_timestamp;
1118     ts += m_tick_offset;
1119
1120     if (ts >= m_wrap_at) {
1121         ts -= m_wrap_at;
1122     } else if (ts < 0) {
1123         ts += m_wrap_at;
1124     }
1125
1126 #ifdef DEBUG
1127     if (new_timestamp >= m_wrap_at) {
1128         debugWarning("timestamp not wrapped: "TIMESTAMP_FORMAT_SPEC"\n", new_timestamp);
1129     }
1130     if ((ts >= m_wrap_at) || (ts < 0 )) {
1131         debugWarning("ts not wrapped correctly: "TIMESTAMP_FORMAT_SPEC"\n",ts);
1132     }
1133 #endif
1134 // FIXME: JMW: at some points during startup the timestamp doesn't change.
1135 // This still needs to be verified in more detail. 
1136 // if (ts>m_buffer_tail_timestamp-1 && ts<m_buffer_tail_timestamp+1) {
1137 //   ENTER_CRITICAL_SECTION;
1138 //   m_framecounter += nbframes;
1139 //   EXIT_CRITICAL_SECTION;
1140 //   return;
1141 // }
1142     ffado_timestamp_t pred_buffer_next_tail_timestamp;
1143     if(nbframes == m_update_period) {
1144         pred_buffer_next_tail_timestamp = m_buffer_next_tail_timestamp;
1145     } else {
1146         debugOutput( DEBUG_LEVEL_VERBOSE,
1147                      "Number of frames (%u) != update period (%u)\n",
1148                      nbframes, m_update_period );
1149         // calculate the predicted timestamp for nframes (instead of m_update_period)
1150         // after the previous update.
1151         float rel_step = ((float)nbframes)/((float)m_update_period);
1152         ENTER_CRITICAL_SECTION; // FIXME: do we need these?
1153         ffado_timestamp_t corrected_step = (m_buffer_next_tail_timestamp - m_buffer_tail_timestamp) * rel_step;
1154         pred_buffer_next_tail_timestamp = m_buffer_tail_timestamp + corrected_step;
1155         EXIT_CRITICAL_SECTION;
1156        
1157         debugOutput( DEBUG_LEVEL_VERBOSE,
1158                      "Updated ("TIMESTAMP_FORMAT_SPEC","TIMESTAMP_FORMAT_SPEC") to ("TIMESTAMP_FORMAT_SPEC","TIMESTAMP_FORMAT_SPEC")\n",
1159                      m_buffer_tail_timestamp, m_buffer_next_tail_timestamp,
1160                      m_buffer_tail_timestamp, pred_buffer_next_tail_timestamp);
1161     }
1162    
1163     // the difference between the given TS and the one predicted for this time instant
1164     // this is the error for the DLL
1165     diff = ts - pred_buffer_next_tail_timestamp;
1166
1167     // check whether the update is within the allowed bounds
1168     const float max_deviation = (50.0/100.0); // maximal relative difference considered normal
1169     ffado_timestamp_t one_update_step = nbframes * getRate();
1170     ffado_timestamp_t max_abs_diff = one_update_step * (1.0 + max_deviation);
1171    
1172     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " nbframes: %d, m_update_period: %d \n", nbframes, m_update_period);
1173     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " tail TS: "TIMESTAMP_FORMAT_SPEC", next tail TS: "TIMESTAMP_FORMAT_SPEC"\n",
1174                                           m_buffer_tail_timestamp, m_buffer_next_tail_timestamp);
1175     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " new TS: "TIMESTAMP_FORMAT_SPEC", wrapped new TS: "TIMESTAMP_FORMAT_SPEC"\n",
1176                                           new_timestamp, ts);
1177
1178     if (diff > max_abs_diff) {
1179         debugShowBackLogLines(100);
1180         debugWarning("(%p) difference rather large (+): diff="TIMESTAMP_FORMAT_SPEC", max="TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC"\n",
1181             this, diff, max_abs_diff, ts, pred_buffer_next_tail_timestamp);
1182     } else if (diff < -max_abs_diff) {
1183         debugShowBackLogLines(100);
1184         debugWarning("(%p) difference rather large (-): diff="TIMESTAMP_FORMAT_SPEC", max="TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC"\n",
1185             this, diff, -max_abs_diff, ts, pred_buffer_next_tail_timestamp);
1186     }
1187
1188     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "(%p): diff="TIMESTAMP_FORMAT_SPEC" ",
1189                 this, diff);
1190
1191     double err = diff;
1192
1193     debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, "diff2="TIMESTAMP_FORMAT_SPEC" err=%f\n",
1194                     diff, err);
1195     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "B: FC=%10u, TS="TIMESTAMP_FORMAT_SPEC", NTS="TIMESTAMP_FORMAT_SPEC"\n",
1196                     m_framecounter, m_buffer_tail_timestamp, pred_buffer_next_tail_timestamp);
1197
1198     ENTER_CRITICAL_SECTION;
1199     m_framecounter += nbframes;
1200     m_buffer_tail_timestamp = pred_buffer_next_tail_timestamp;
1201     m_buffer_next_tail_timestamp = pred_buffer_next_tail_timestamp + (ffado_timestamp_t)(m_dll_b * err + m_dll_e2);
1202     m_dll_e2 += m_dll_c*err;
1203
1204     if (m_buffer_next_tail_timestamp >= m_wrap_at) {
1205         debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Unwrapping next tail timestamp: "TIMESTAMP_FORMAT_SPEC"",
1206                 m_buffer_next_tail_timestamp);
1207
1208         m_buffer_next_tail_timestamp -= m_wrap_at;
1209
1210         debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, " => "TIMESTAMP_FORMAT_SPEC"\n",
1211                 m_buffer_next_tail_timestamp);
1212
1213     }
1214     m_current_rate = calculateRate();
1215     EXIT_CRITICAL_SECTION;
1216
1217     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "A: TS="TIMESTAMP_FORMAT_SPEC", NTS="TIMESTAMP_FORMAT_SPEC", DLLe2=%f, RATE=%f\n",
1218                 m_buffer_tail_timestamp, m_buffer_next_tail_timestamp, m_dll_e2, m_current_rate);
1219
1220
1221     if(m_buffer_tail_timestamp>=m_wrap_at) {
1222         debugError("Wrapping failed for m_buffer_tail_timestamp! "TIMESTAMP_FORMAT_SPEC"\n",m_buffer_tail_timestamp);
1223         debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " IN="TIMESTAMP_FORMAT_SPEC", TS="TIMESTAMP_FORMAT_SPEC", NTS="TIMESTAMP_FORMAT_SPEC"\n",
1224                     ts, m_buffer_tail_timestamp, m_buffer_next_tail_timestamp);
1225
1226     }
1227     if(m_buffer_next_tail_timestamp>=m_wrap_at) {
1228         debugError("Wrapping failed for m_buffer_next_tail_timestamp! "TIMESTAMP_FORMAT_SPEC"\n",m_buffer_next_tail_timestamp);
1229         debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " IN="TIMESTAMP_FORMAT_SPEC", TS="TIMESTAMP_FORMAT_SPEC", NTS="TIMESTAMP_FORMAT_SPEC"\n",
1230                     ts, m_buffer_tail_timestamp, m_buffer_next_tail_timestamp);
1231     }
1232    
1233     if(m_buffer_tail_timestamp==m_buffer_next_tail_timestamp) {
1234         debugError("Current and next timestamps are equal: "TIMESTAMP_FORMAT_SPEC" "TIMESTAMP_FORMAT_SPEC"\n",
1235                    m_buffer_tail_timestamp,m_buffer_next_tail_timestamp);
1236    
1237     }
1238
1239     // this DLL allows the calculation of any sample timestamp relative to the buffer tail,
1240     // to the next period and beyond (through extrapolation)
1241     //
1242     // ts(x) = m_buffer_tail_timestamp +
1243     //         (m_buffer_next_tail_timestamp - m_buffer_tail_timestamp)/(samples_between_updates)*x
1244 }
1245
1246 /**
1247  * @brief Print status info.
1248  */
1249 void TimestampedBuffer::dumpInfo() {
1250
1251     ffado_timestamp_t ts_head;
1252     signed int fc;
1253     getBufferHeadTimestamp(&ts_head,&fc);
1254
1255 #ifdef DEBUG
1256     ffado_timestamp_t diff=(ffado_timestamp_t)ts_head - (ffado_timestamp_t)m_buffer_tail_timestamp;
1257 #endif
1258
1259     debugOutputShort( DEBUG_LEVEL_NORMAL, "  TimestampedBuffer (%p): %04d frames, %04d events\n",
1260                                           this, m_framecounter, getBufferFill());
1261     debugOutputShort( DEBUG_LEVEL_NORMAL, "   Timestamps           : head: "TIMESTAMP_FORMAT_SPEC", Tail: "TIMESTAMP_FORMAT_SPEC", Next tail: "TIMESTAMP_FORMAT_SPEC"\n",
1262                                           ts_head, m_buffer_tail_timestamp, m_buffer_next_tail_timestamp);
1263     debugOutputShort( DEBUG_LEVEL_NORMAL, "    Head - Tail         : "TIMESTAMP_FORMAT_SPEC"\n", diff);
1264     debugOutputShort( DEBUG_LEVEL_NORMAL, "   DLL Rate             : %f (%f)\n", m_dll_e2, m_dll_e2/m_update_period);
1265 }
1266
1267 } // end of namespace Util
Note: See TracBrowser for help on using the browser.