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

Revision 795, 41.1 kB (checked in by ppalmers, 13 years ago)

small bugfixes + debug print changes

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