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

Revision 864, 42.5 kB (checked in by ppalmers, 15 years ago)

update license to GPLv2 or GPLv3 instead of GPLv2 or any later version. Update copyrights to reflect the new year

Line 
1 /*
2  * Copyright (C) 2005-2008 by Pieter Palmers
3  *
4  * This file is part of FFADO
5  * FFADO = Free Firewire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB.
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) version 3 of the License.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 #include "config.h"
25
26 #include "libutil/Atomic.h"
27 #include "libieee1394/cycletimer.h"
28
29 #include "TimestampedBuffer.h"
30 #include "assert.h"
31 #include "errno.h"
32
33
34 #define DLL_PI        (3.141592653589793238)
35 #define DLL_SQRT2     (1.414213562373095049)
36 #define DLL_OMEGA     (2.0*DLL_PI*TIMESTAMPEDBUFFER_DLL_BANDWIDTH)
37 #define DLL_COEFF_B   (DLL_SQRT2 * DLL_OMEGA)
38 #define DLL_COEFF_C   (DLL_OMEGA * DLL_OMEGA)
39
40 #define FRAMES_PER_PROCESS_BLOCK 8
41 /*
42 #define ENTER_CRITICAL_SECTION { \
43     if (pthread_mutex_trylock(&m_framecounter_lock) == EBUSY) { \
44         debugWarning(" (%p) lock clash\n", this); \
45         pthread_mutex_lock(&m_framecounter_lock); \
46     } \
47     }
48 */
49 #define ENTER_CRITICAL_SECTION { \
50     pthread_mutex_lock(&m_framecounter_lock); \
51     }
52 #define EXIT_CRITICAL_SECTION { \
53     pthread_mutex_unlock(&m_framecounter_lock); \
54     }
55
56 namespace Util {
57
58 IMPL_DEBUG_MODULE( TimestampedBuffer, TimestampedBuffer, DEBUG_LEVEL_VERBOSE );
59
60 TimestampedBuffer::TimestampedBuffer(TimestampedBufferClient *c)
61     : m_event_buffer(NULL), m_process_buffer(NULL), m_cluster_size( 0 ),
62       m_process_block_size( 0 ),
63       m_event_size(0), m_events_per_frame(0), m_buffer_size(0),
64       m_bytes_per_frame(0), m_bytes_per_buffer(0),
65       m_enabled( false ), m_transparent ( true ),
66       m_wrap_at(0xFFFFFFFFFFFFFFFFLLU),
67       m_Client(c), m_framecounter(0),
68       m_tick_offset(0.0),
69       m_buffer_tail_timestamp(0.0),
70       m_buffer_next_tail_timestamp(0.0),
71       m_dll_e2(0.0), m_dll_b(DLL_COEFF_B), m_dll_c(DLL_COEFF_C),
72       m_nominal_rate(0.0), m_current_rate(0.0), m_update_period(0)
73 {
74     pthread_mutex_init(&m_framecounter_lock, NULL);
75 }
76
77 TimestampedBuffer::~TimestampedBuffer() {
78     pthread_mutex_destroy(&m_framecounter_lock);
79
80     ffado_ringbuffer_free(m_event_buffer);
81     free(m_process_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 Get the nominal update period (in frames)
117  *
118  * Gets the nominal update period. This period is the number of frames
119  * between two timestamp updates (hence buffer writes)
120  *
121  * @return period in frames
122  */
123 unsigned int TimestampedBuffer::getUpdatePeriod() {
124     return m_update_period;
125 }
126
127 /**
128  * \brief set the value at which timestamps should wrap around
129  * @param w value to wrap at
130  * @return true if successful
131  */
132 bool TimestampedBuffer::setWrapValue(ffado_timestamp_t w) {
133     m_wrap_at=w;
134     return true;
135 }
136 #include <math.h>
137
138 /**
139  * \brief return the effective rate
140  *
141  * Returns the effective rate calculated by the DLL.
142  *
143  * @return rate (in timeunits/frame)
144  */
145 float TimestampedBuffer::getRate() {
146     return m_current_rate;
147 }
148
149 /**
150  * \brief calculate the effective rate
151  *
152  * Returns the effective rate calculated by the DLL.
153  * @note should be called with the lock held
154  * @return rate (in timeunits/frame)
155  */
156 float TimestampedBuffer::calculateRate() {
157     ffado_timestamp_t diff;
158    
159     diff=m_buffer_next_tail_timestamp - m_buffer_tail_timestamp;
160    
161     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"getRate: %f/%f=%f\n",
162         (float)(diff),
163         (float)m_update_period,
164         ((float)(diff))/((float) m_update_period));
165    
166     // the maximal difference we can allow (64secs)
167     const ffado_timestamp_t max=m_wrap_at/((ffado_timestamp_t)2);
168
169     if(diff > max) {
170         diff -= m_wrap_at;
171     } else if (diff < -max) {
172         diff += m_wrap_at;
173     }
174
175     float rate=((float)diff)/((float) m_update_period);
176     if (rate<0.0) debugError("rate < 0! (%f)\n",rate);
177     if (fabsf(m_nominal_rate - rate)>(m_nominal_rate*0.1)) {
178         debugWarning("(%p) rate (%10.5f) more that 10%% off nominal (rate=%10.5f, diff="TIMESTAMP_FORMAT_SPEC", update_period=%d)\n",
179                      this, rate,m_nominal_rate,diff, m_update_period);
180
181         return m_nominal_rate;
182     } else {
183         return rate;
184     }
185 }
186
187 /**
188  * \brief Sets the size of the events
189  * @param s event size in bytes
190  * @return true if successful
191  */
192 bool TimestampedBuffer::setEventSize(unsigned int s) {
193     m_event_size=s;
194
195     m_bytes_per_frame=m_event_size*m_events_per_frame;
196     m_bytes_per_buffer=m_bytes_per_frame*m_buffer_size;
197
198     return true;
199 }
200
201 /**
202  * \brief Sets the number of events per frame
203  * @param n number of events per frame
204  * @return true if successful
205  */
206 bool TimestampedBuffer::setEventsPerFrame(unsigned int n) {
207     m_events_per_frame=n;
208
209     m_bytes_per_frame=m_event_size*m_events_per_frame;
210     m_bytes_per_buffer=m_bytes_per_frame*m_buffer_size;
211
212     return true;
213 }
214 /**
215  * \brief Sets the buffer size in frames
216  * @param n number frames
217  * @return true if successful
218  */
219 bool TimestampedBuffer::setBufferSize(unsigned int n) {
220     m_buffer_size=n;
221
222     m_bytes_per_frame=m_event_size*m_events_per_frame;
223     m_bytes_per_buffer=m_bytes_per_frame*m_buffer_size;
224
225     return true;
226 }
227
228 /**
229  * Sets the buffer offset in ticks.
230  *
231  * A positive value means that the buffer is 'delayed' for nticks ticks.
232  *
233  * @note These offsets are only used when reading timestamps. Any function
234  *       that returns a timestamp will incorporate this offset.
235  * @param nframes the number of ticks (positive = delay buffer)
236  * @return true if successful
237  */
238 bool TimestampedBuffer::setTickOffset(ffado_timestamp_t nticks) {
239     debugOutput(DEBUG_LEVEL_VERBOSE,"Setting ticks offset to "TIMESTAMP_FORMAT_SPEC"\n",nticks);
240
241     // JMW: I think we need to update the internal DLL state to take account
242     // of the new offset.  Doing so certainly makes for a smoother MOTU
243     // startup.
244     ENTER_CRITICAL_SECTION;
245     m_buffer_tail_timestamp = m_buffer_tail_timestamp - m_tick_offset + nticks;
246     m_buffer_next_tail_timestamp = (ffado_timestamp_t)((double)m_buffer_tail_timestamp + m_dll_e2);
247     m_tick_offset=nticks;
248     EXIT_CRITICAL_SECTION;
249
250     return true;
251 }
252
253 /**
254  * \brief Returns the current fill of the buffer
255  *
256  * This returns the buffer fill of the internal ringbuffer. This
257  * can only be used as an indication because it's state is not
258  * guaranteed to be consistent at all times due to threading issues.
259  *
260  * In order to get the number of frames in the buffer, use the
261  * getBufferHeadTimestamp, getBufferTailTimestamp
262  * functions
263  *
264  * @return the internal buffer fill in frames
265  */
266 unsigned int TimestampedBuffer::getBufferFill() {
267     //return ffado_ringbuffer_read_space(m_event_buffer)/(m_bytes_per_frame);
268     return m_framecounter;
269 }
270
271 /**
272  * \brief Returns the current write space in the buffer
273  *
274  * This returns the buffer free space of the internal ringbuffer. This
275  * can only be used as an indication because it's state is not
276  * guaranteed to be consistent at all times due to threading issues.
277  *
278  * @return the internal buffer fill in frames
279  */
280 unsigned int TimestampedBuffer::getBufferSpace() {
281     //return ffado_ringbuffer_write_space(m_event_buffer)/(m_bytes_per_frame);
282     assert(m_buffer_size-m_framecounter >= 0);
283     return m_buffer_size-m_framecounter;
284 }
285
286 /**
287  * \brief Resets the TimestampedBuffer
288  *
289  * Resets the TimestampedBuffer, clearing the buffers and counters.
290  * (not true yet: Also resets the DLL to the nominal values.)
291  *
292  * \note when this is called, you should make sure that the buffer
293  *       tail timestamp gets set before continuing
294  *
295  * @return true if successful
296  */
297 bool TimestampedBuffer::clearBuffer() {
298     debugOutput(DEBUG_LEVEL_VERBOSE, "Clearing buffer\n");
299     ffado_ringbuffer_reset(m_event_buffer);
300     resetFrameCounter();
301     return true;
302 }
303
304 /**
305  * \brief Prepares the TimestampedBuffer
306  *
307  * Prepare the TimestampedBuffer. This allocates all internal buffers and
308  * initializes all data structures.
309  *
310  * This should be called after parameters such as buffer size, event size etc.. are set,
311  * and before any read/write operations are performed.
312  *
313  * @return true if successful
314  */
315 bool TimestampedBuffer::prepare() {
316     debugOutput(DEBUG_LEVEL_VERBOSE,"Preparing buffer (%p)\n",this);
317     debugOutput(DEBUG_LEVEL_VERBOSE," Size=%u events, events/frame=%u, event size=%ubytes\n",
318                                         m_buffer_size,m_events_per_frame,m_event_size);
319
320     debugOutput(DEBUG_LEVEL_VERBOSE," update period %u\n",
321                                     m_update_period);
322     debugOutput(DEBUG_LEVEL_VERBOSE," nominal rate=%f\n",
323                                     m_nominal_rate);
324
325     debugOutput(DEBUG_LEVEL_VERBOSE," wrapping at "TIMESTAMP_FORMAT_SPEC"\n",m_wrap_at);
326
327     assert(m_buffer_size);
328     assert(m_events_per_frame);
329     assert(m_event_size);
330
331     assert(m_nominal_rate != 0.0L);
332     assert(m_update_period != 0);
333
334     m_current_rate = m_nominal_rate;
335
336     if( !(m_event_buffer=ffado_ringbuffer_create(
337             (m_events_per_frame * m_buffer_size) * m_event_size))) {
338         debugFatal("Could not allocate memory event ringbuffer\n");
339         return false;
340     }
341
342     // allocate the temporary cluster buffer
343     // NOTE: has to be a multiple of 8 in order to
344     //       correctly decode midi bytes (since that
345     //       enforces packet alignment)
346     m_cluster_size = m_events_per_frame * m_event_size;
347     m_process_block_size = m_cluster_size * FRAMES_PER_PROCESS_BLOCK;
348     if( !(m_process_buffer=(char *)calloc(m_process_block_size, 1))) {
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
554     while(bytes2write > 0) {
555         int byteswritten = 0;
556
557         unsigned int frameswritten = (nbframes * m_cluster_size - bytes2write) / m_cluster_size;
558         offset = frameswritten;
559
560         ffado_ringbuffer_get_write_vector(m_event_buffer, vec);
561
562         if(vec[0].len + vec[1].len < m_process_block_size) { // this indicates a full event buffer
563             debugError("Event buffer overrun in buffer %p, fill: %u, bytes2write: %u \n",
564                        this, ffado_ringbuffer_read_space(m_event_buffer), bytes2write);
565             debugShowBackLog();
566             return false;
567         }
568
569         /* if we don't take care we will get stuck in an infinite loop
570         * because we align to a cluster boundary later
571         * the remaining nb of bytes in one write operation can be
572         * smaller than one cluster
573         * this can happen because the ringbuffer size is always a power of 2
574         */
575         if(vec[0].len < m_process_block_size) {
576
577             // encode to the temporary buffer
578             // note that we always process 8 frames at once, in order to ensure that
579             // we don't have to care about the DBC field
580             xrun = m_Client->processWriteBlock(m_process_buffer, FRAMES_PER_PROCESS_BLOCK, offset);
581
582             if(xrun < 0) {
583                 // xrun detected
584                 debugError("Frame buffer underrun in buffer %p\n",this);
585                 return false;
586             }
587
588             // use the ringbuffer function to write one cluster
589             // the write function handles the wrap around.
590             ffado_ringbuffer_write(m_event_buffer,
591                                    m_process_buffer,
592                                    m_process_block_size);
593
594             // we advanced one cluster_size
595             bytes2write -= m_process_block_size;
596
597         } else { //
598
599             if(bytes2write > vec[0].len) {
600                 // align to a cluster boundary
601                 byteswritten = vec[0].len - (vec[0].len % m_process_block_size);
602             } else {
603                 byteswritten = bytes2write;
604             }
605
606             xrun = m_Client->processWriteBlock(vec[0].buf,
607                                                byteswritten / m_cluster_size,
608                                                offset);
609
610             if(xrun < 0 ) {
611                 // xrun detected
612                 debugError("Frame buffer underrun in buffer %p\n",this);
613                 return false; // FIXME: return false ?
614             }
615
616             ffado_ringbuffer_write_advance(m_event_buffer, byteswritten);
617             bytes2write -= byteswritten;
618         }
619
620         // the bytes2write should always be process block aligned
621         assert(bytes2write % m_process_block_size == 0);
622
623     }
624
625     incrementFrameCounter(nbframes,ts);
626
627     return true;
628
629 }
630
631 /**
632  * @brief Performs block processing read of frames
633  *
634  * This function allows for zero-copy reading from the ringbuffer.
635  * It calls the client's processReadBlock function to read frames
636  * directly from the internal buffer's data area, in a thread safe
637  * fashion.
638  *
639  * @param nbframes number of frames to process
640  * @return true if successful
641  */
642 bool TimestampedBuffer::blockProcessReadFrames(unsigned int nbframes) {
643
644     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Reading %u from buffer (%p)...\n", nbframes, this);
645
646     int xrun;
647     unsigned int offset = 0;
648
649     ffado_ringbuffer_data_t vec[2];
650     // we received one period of frames on each connection
651     // this is period_size*dimension of events
652
653     unsigned int events2read = nbframes * m_events_per_frame;
654     unsigned int bytes2read = events2read * m_event_size;
655     /* read events2read bytes from the ringbuffer
656     *  first see if it can be done in one read.
657     *  if so, ok.
658     *  otherwise read up to a multiple of clusters directly from the buffer
659     *  then do the buffer wrap around using ringbuffer_read
660     *  then read the remaining data directly from the buffer in a third pass
661     *  Make sure that we cannot end up on a non-cluster aligned position!
662     */
663
664     while(bytes2read > 0) {
665         unsigned int framesread = (nbframes * m_cluster_size - bytes2read) / m_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 + vec[1].len < m_process_block_size) { // 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 < m_process_block_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_process_buffer, m_process_block_size);
686
687             assert(m_Client);
688             // note that we always process 8 frames at once, in order to ensure that
689             // we don't have to care about the DBC field
690             xrun = m_Client->processReadBlock(m_process_buffer, FRAMES_PER_PROCESS_BLOCK, 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             // we advanced one cluster_size
699             bytes2read -= m_process_block_size;
700
701         } else { //
702
703             if(bytes2read > vec[0].len) {
704                 // align to a cluster boundary
705                 bytesread = vec[0].len - (vec[0].len % m_process_block_size);
706             } else {
707                 bytesread = bytes2read;
708             }
709
710             assert(m_Client);
711             xrun = m_Client->processReadBlock(vec[0].buf, bytesread/m_cluster_size, offset);
712
713             if(xrun < 0) {
714                 // xrun detected
715                 debugError("Frame buffer overrun in buffer %p\n",this);
716                 return false;
717             }
718
719             ffado_ringbuffer_read_advance(m_event_buffer, bytesread);
720             bytes2read -= bytesread;
721         }
722
723         // the bytes2read should always be cluster aligned
724         assert(bytes2read % m_process_block_size == 0);
725     }
726
727     decrementFrameCounter(nbframes);
728
729     return true;
730 }
731
732 /**
733  * @brief Sets the buffer tail timestamp.
734  *
735  * Set the buffer tail timestamp to \ref new_timestamp. This will recalculate
736  * the internal state such that the buffer's timeframe starts at
737  * \ref new_timestamp.
738  *
739  * This is thread safe.
740  *
741  * @note considers offsets
742  *
743  * @param new_timestamp
744  */
745 void TimestampedBuffer::setBufferTailTimestamp(ffado_timestamp_t new_timestamp) {
746
747     // add the offsets
748     ffado_timestamp_t ts=new_timestamp;
749     ts += m_tick_offset;
750
751     if (ts >= m_wrap_at) {
752         ts -= m_wrap_at;
753     } else if (ts < 0) {
754         ts += m_wrap_at;
755     }
756
757 #ifdef DEBUG
758     if (new_timestamp >= m_wrap_at) {
759         debugWarning("timestamp not wrapped: "TIMESTAMP_FORMAT_SPEC"\n",new_timestamp);
760     }
761     if ((ts >= m_wrap_at) || (ts < 0 )) {
762         debugWarning("ts not wrapped correctly: "TIMESTAMP_FORMAT_SPEC"\n",ts);
763     }
764 #endif
765
766     ENTER_CRITICAL_SECTION;
767
768     m_buffer_tail_timestamp = ts;
769
770     m_dll_e2=m_update_period * (double)m_nominal_rate;
771     m_buffer_next_tail_timestamp = (ffado_timestamp_t)((double)m_buffer_tail_timestamp + m_dll_e2);
772
773     EXIT_CRITICAL_SECTION;
774
775     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "for (%p) to "
776                                           TIMESTAMP_FORMAT_SPEC" => "TIMESTAMP_FORMAT_SPEC", NTS="
777                                           TIMESTAMP_FORMAT_SPEC", DLL2=%f, RATE=%f\n",
778                 this, new_timestamp, ts, m_buffer_next_tail_timestamp, m_dll_e2, getRate());
779
780 }
781
782 /**
783  * @brief Sets the buffer head timestamp.
784  *
785  * Set the buffer tail timestamp such that the buffer head timestamp becomes
786  * \ref new_timestamp. This does not consider offsets, because it's use is to
787  * make sure the following is true after setBufferHeadTimestamp(x):
788  *   x == getBufferHeadTimestamp()
789  *
790  * This is thread safe.
791  *
792  * @param new_timestamp
793  */
794 void TimestampedBuffer::setBufferHeadTimestamp(ffado_timestamp_t new_timestamp) {
795
796 #ifdef DEBUG
797     if (new_timestamp >= m_wrap_at) {
798         debugWarning("timestamp not wrapped: "TIMESTAMP_FORMAT_SPEC"\n",new_timestamp);
799     }
800 #endif
801
802     ffado_timestamp_t ts = new_timestamp;
803
804     ENTER_CRITICAL_SECTION;
805
806     // add the time
807     ts += (ffado_timestamp_t)(m_nominal_rate * (float)m_framecounter);
808
809     if (ts >= m_wrap_at) {
810         ts -= m_wrap_at;
811     } else if (ts < 0) {
812         ts += m_wrap_at;
813     }
814
815     m_buffer_tail_timestamp = ts;
816
817     m_dll_e2=m_update_period * (double)m_nominal_rate;
818     m_buffer_next_tail_timestamp = (ffado_timestamp_t)((double)m_buffer_tail_timestamp + m_dll_e2);
819
820     EXIT_CRITICAL_SECTION;
821
822     debugOutput(DEBUG_LEVEL_VERBOSE, "for (%p) to "TIMESTAMP_FORMAT_SPEC" => "
823                                           TIMESTAMP_FORMAT_SPEC", NTS="TIMESTAMP_FORMAT_SPEC", DLL2=%f, RATE=%f\n",
824                 this, new_timestamp, ts, m_buffer_next_tail_timestamp, m_dll_e2, getRate());
825
826 }
827
828 /**
829  * @brief Synchronize the buffer head to a specified timestamp
830  *
831  * Try to synchronize the buffer head to a specific timestamp. This
832  * can mean adding or removing samples to/from the buffer such that
833  * the buffer head aligns with the specified timestamp. The alignment
834  * is within ts +/- Tsample/2
835  *
836  * @param target the timestamp to align to
837  * @return true if alignment succeeded, false if not
838  */
839 bool
840 TimestampedBuffer::syncBufferHeadToTimestamp(ffado_timestamp_t target)
841 {
842     uint64_t ts_head;
843     uint64_t ts_target=(uint64_t)target;
844     signed int fc;
845     int32_t lag_ticks;
846     float lag_frames;
847
848     ffado_timestamp_t ts_head_tmp;
849     getBufferHeadTimestamp(&ts_head_tmp, &fc);
850     ts_head=(uint64_t)ts_head_tmp;
851     // if target > ts_head then the wanted buffer head timestamp
852     // is later than the actual. This means that we (might) have to drop
853     // some frames.
854     lag_ticks=diffTicks(ts_target, ts_head);
855     float rate=getRate();
856    
857     assert(rate!=0.0);
858
859     lag_frames=(((float)lag_ticks)/rate);
860    
861     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): HEAD=%llu, TS=%llu, diff=%ld = %10.5f frames (rate=%10.5f)\n",
862                                       this, ts_head, ts_target, lag_ticks, lag_frames, rate);
863
864     if (lag_frames>=1.0) {
865         // the buffer head is too early
866         // ditch frames until the buffer head is on time
867         char dummy[getBytesPerFrame()]; // one frame of garbage
868         int frames_to_ditch=(int)roundf(lag_frames);
869         debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): ditching %d frames (@ ts=%lld)\n",this,frames_to_ditch,ts_target);
870        
871         while (frames_to_ditch--) {
872             readFrames(1, dummy);
873         }
874        
875     } else if (lag_frames<=-1.0) {
876         // the buffer head is too late
877         // add some padding frames
878         int frames_to_add=(int)roundf(lag_frames);
879         debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): adding %d frames (@ ts=%lld)\n",this,-frames_to_add,ts_target);
880        
881         while (frames_to_add++) {
882              writeDummyFrame();
883         }
884     }
885     getBufferHeadTimestamp(&ts_head_tmp, &fc);
886     ts_head=(uint64_t)ts_head_tmp;
887     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): new HEAD=%llu, fc=%d, target=%llu, new diff=%lld\n",
888                                       this, ts_head, fc, ts_target, diffTicks(ts_target, ts_head));
889     // FIXME: of course this doesn't always succeed
890     return true;
891 }
892
893 /**
894  * @brief Synchronize the buffer tail to a specified timestamp
895  *
896  * Try to synchronize the buffer tail to a specific timestamp. This
897  * can mean adding or removing samples to/from the buffer such that
898  * the buffer tail aligns with the specified timestamp. The alignment
899  * is within ts +/- Tsample/2
900  *
901  * @param target the timestamp to align to
902  * @return true if alignment succeeded, false if not
903  */
904 bool
905 TimestampedBuffer::syncBufferTailToTimestamp(ffado_timestamp_t target)
906 {
907     uint64_t ts_tail;
908     uint64_t ts_target=(uint64_t)target;
909     signed int fc;
910     int32_t lag_ticks;
911     float lag_frames;
912
913     debugWarning("Untested\n");
914    
915     ffado_timestamp_t ts_tail_tmp;
916     getBufferTailTimestamp(&ts_tail_tmp, &fc);
917     ts_tail=(uint64_t)ts_tail_tmp;
918     // if target < ts_tail then the wanted buffer head timestamp
919     // is later than the actual. This means that we (might) have to drop
920     // some frames.
921     lag_ticks=diffTicks(ts_tail, ts_target);
922     float rate=getRate();
923    
924     assert(rate!=0.0);
925
926     lag_frames=(((float)lag_ticks)/rate);
927    
928     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): HEAD=%llu, TS=%llu, diff=%ld = %10.5f frames (rate=%10.5f)\n",
929                                       this, ts_tail, ts_target, lag_ticks, lag_frames, rate);
930
931     if (lag_frames>=1.0) {
932         // the buffer head is too early
933         // ditch frames until the buffer head is on time
934         char dummy[getBytesPerFrame()]; // one frame of garbage
935         int frames_to_ditch=(int)roundf(lag_frames);
936         debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): ditching %d frames (@ ts=%lld)\n",this,frames_to_ditch,ts_target);
937        
938         while (frames_to_ditch--) {
939             readFrames(1, dummy);
940         }
941        
942     } else if (lag_frames<=-1.0) {
943         // the buffer head is too late
944         // add some padding frames
945         int frames_to_add=(int)roundf(lag_frames);
946         debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): adding %d frames (@ ts=%lld)\n",this,-frames_to_add,ts_target);
947        
948         while (frames_to_add++) {
949              writeDummyFrame();
950         }
951     }
952     getBufferHeadTimestamp(&ts_tail_tmp, &fc);
953     ts_tail=(uint64_t)ts_tail_tmp;
954     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): new HEAD=%llu, fc=%d, target=%llu, new diff=%lld\n",
955                                       this, ts_tail, fc, ts_target, diffTicks(ts_target, ts_tail));
956     // FIXME: of course this doesn't always succeed
957     return true;
958 }
959
960 /**
961  * @brief correct lag
962  *
963  * Try to synchronize the buffer tail to a specific timestamp. This
964  * can mean adding or removing samples to/from the buffer such that
965  * the buffer tail aligns with the specified timestamp. The alignment
966  * is within ts +/- Tsample/2
967  *
968  * @param target the timestamp to align to
969  * @return true if alignment succeeded, false if not
970  */
971 bool
972 TimestampedBuffer::syncCorrectLag(int64_t lag_ticks)
973 {
974     float lag_frames;
975     float rate=getRate();
976     assert(rate!=0.0);
977
978     lag_frames=(((float)lag_ticks)/rate);
979     if (lag_frames >= 1.0) {
980         // the buffer head is too late
981         // add some padding frames
982         int frames_to_add=(int)roundf(lag_frames);
983         debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): adding %d frames\n",this,frames_to_add);
984
985         while (frames_to_add++) {
986              writeDummyFrame();
987         }
988     } else if (lag_frames <= -1.0) {
989         // the buffer head is too early
990         // ditch frames until the buffer head is on time
991         char dummy[getBytesPerFrame()]; // one frame of garbage
992         int frames_to_ditch=(int)roundf(lag_frames);
993         debugOutput( DEBUG_LEVEL_VERBOSE, "(%p): ditching %d frames\n",this,-frames_to_ditch);
994
995         while (frames_to_ditch--) {
996             readFrames(1, dummy);
997         }
998     }
999     return true;
1000 }
1001
1002 /**
1003  * \brief return the timestamp of the first frame in the buffer
1004  *
1005  * This function returns the timestamp of the very first sample in
1006  * the StreamProcessor's buffer. It also returns the framecounter value
1007  * for which this timestamp is valid.
1008  *
1009  * @param ts address to store the timestamp in
1010  * @param fc address to store the associated framecounter in
1011  */
1012 void TimestampedBuffer::getBufferHeadTimestamp(ffado_timestamp_t *ts, signed int *fc) {
1013     // NOTE: this is still ok with threads, because we use *fc to compute
1014     //       the timestamp
1015     *fc = m_framecounter;
1016     *ts = getTimestampFromTail(*fc);
1017 }
1018
1019 /**
1020  * \brief return the timestamp of the last frame in the buffer
1021  *
1022  * This function returns the timestamp of the last frame in
1023  * the StreamProcessor's buffer. It also returns the framecounter
1024  * value for which this timestamp is valid.
1025  *
1026  * @param ts address to store the timestamp in
1027  * @param fc address to store the associated framecounter in
1028  */
1029 void TimestampedBuffer::getBufferTailTimestamp(ffado_timestamp_t *ts, signed int *fc) {
1030     // NOTE: this is still ok with threads, because we use *fc to compute
1031     //       the timestamp
1032     *fc = m_framecounter;
1033     *ts = getTimestampFromTail(0);
1034 }
1035
1036 /**
1037  * @brief Get timestamp for a specific position from the buffer tail
1038  *
1039  * Returns the timestamp for a position that is nframes earlier than the
1040  * buffer tail
1041  *
1042  * @param nframes number of frames
1043  * @return timestamp value
1044  */
1045 ffado_timestamp_t TimestampedBuffer::getTimestampFromTail(int nframes)
1046 {
1047     // ts(x) = m_buffer_tail_timestamp -
1048     //         (m_buffer_next_tail_timestamp - m_buffer_tail_timestamp)/(samples_between_updates)*(x)
1049     ffado_timestamp_t timestamp;
1050     timestamp = m_buffer_tail_timestamp;
1051
1052     timestamp -= (ffado_timestamp_t)((nframes) * m_current_rate);
1053
1054     if(timestamp >= m_wrap_at) {
1055         timestamp -= m_wrap_at;
1056     } else if(timestamp < 0) {
1057         timestamp += m_wrap_at;
1058     }
1059
1060     return timestamp;
1061 }
1062
1063 /**
1064  * @brief Get timestamp for a specific position from the buffer head
1065  *
1066  * Returns the timestamp for a position that is nframes later than the
1067  * buffer head
1068  *
1069  * @param nframes number of frames
1070  * @return timestamp value
1071  */
1072 ffado_timestamp_t TimestampedBuffer::getTimestampFromHead(int nframes)
1073 {
1074     return getTimestampFromTail(m_framecounter-nframes);
1075 }
1076
1077 /**
1078  * Resets the frame counter, in a atomic way. This
1079  * is thread safe.
1080  */
1081 void TimestampedBuffer::resetFrameCounter() {
1082     ENTER_CRITICAL_SECTION;
1083     m_framecounter = 0;
1084     EXIT_CRITICAL_SECTION;
1085 }
1086
1087 /**
1088  * Decrements the frame counter in a thread safe way.
1089  *
1090  * @param nbframes number of frames to decrement
1091  */
1092 void TimestampedBuffer::decrementFrameCounter(unsigned int nbframes) {
1093     ENTER_CRITICAL_SECTION;
1094     m_framecounter -= nbframes;
1095     EXIT_CRITICAL_SECTION;
1096 }
1097
1098 /**
1099  * Increments the frame counter in a thread safe way.
1100  * Also updates the timestamp.
1101  *
1102  * @note the offsets defined by setTicksOffset and setFrameOffset
1103  *       are added here.
1104  *
1105  * @param nbframes the number of frames to add
1106  * @param new_timestamp the new timestamp
1107  */
1108 void TimestampedBuffer::incrementFrameCounter(unsigned int nbframes, ffado_timestamp_t new_timestamp) {
1109
1110     // add the offsets
1111     ffado_timestamp_t diff;
1112    
1113     ENTER_CRITICAL_SECTION;
1114     diff = m_buffer_next_tail_timestamp - m_buffer_tail_timestamp;
1115     EXIT_CRITICAL_SECTION;
1116
1117     if (diff < 0) diff += m_wrap_at;
1118
1119     ffado_timestamp_t ts = new_timestamp;
1120     ts += m_tick_offset;
1121
1122     if (ts >= m_wrap_at) {
1123         ts -= m_wrap_at;
1124     } else if (ts < 0) {
1125         ts += m_wrap_at;
1126     }
1127
1128 #ifdef DEBUG
1129     if (new_timestamp >= m_wrap_at) {
1130         debugWarning("timestamp not wrapped: "TIMESTAMP_FORMAT_SPEC"\n", new_timestamp);
1131     }
1132     if ((ts >= m_wrap_at) || (ts < 0 )) {
1133         debugWarning("ts not wrapped correctly: "TIMESTAMP_FORMAT_SPEC"\n",ts);
1134     }
1135 #endif
1136 // FIXME: JMW: at some points during startup the timestamp doesn't change.
1137 // This still needs to be verified in more detail. 
1138 // if (ts>m_buffer_tail_timestamp-1 && ts<m_buffer_tail_timestamp+1) {
1139 //   ENTER_CRITICAL_SECTION;
1140 //   m_framecounter += nbframes;
1141 //   EXIT_CRITICAL_SECTION;
1142 //   return;
1143 // }
1144     ffado_timestamp_t pred_buffer_next_tail_timestamp;
1145     if(nbframes == m_update_period) {
1146         pred_buffer_next_tail_timestamp = m_buffer_next_tail_timestamp;
1147     } else {
1148         debugOutput( DEBUG_LEVEL_VERBOSE,
1149                      "Number of frames (%u) != update period (%u)\n",
1150                      nbframes, m_update_period );
1151         // calculate the predicted timestamp for nframes (instead of m_update_period)
1152         // after the previous update.
1153         float rel_step = ((float)nbframes)/((float)m_update_period);
1154         ENTER_CRITICAL_SECTION; // FIXME: do we need these?
1155         ffado_timestamp_t corrected_step = (m_buffer_next_tail_timestamp - m_buffer_tail_timestamp) * rel_step;
1156         pred_buffer_next_tail_timestamp = m_buffer_tail_timestamp + corrected_step;
1157         EXIT_CRITICAL_SECTION;
1158        
1159         debugOutput( DEBUG_LEVEL_VERBOSE,
1160                      "Updated ("TIMESTAMP_FORMAT_SPEC","TIMESTAMP_FORMAT_SPEC") to ("TIMESTAMP_FORMAT_SPEC","TIMESTAMP_FORMAT_SPEC")\n",
1161                      m_buffer_tail_timestamp, m_buffer_next_tail_timestamp,
1162                      m_buffer_tail_timestamp, pred_buffer_next_tail_timestamp);
1163     }
1164    
1165     // the difference between the given TS and the one predicted for this time instant
1166     // this is the error for the DLL
1167     diff = ts - pred_buffer_next_tail_timestamp;
1168
1169     // check whether the update is within the allowed bounds
1170     const float max_deviation = (50.0/100.0); // maximal relative difference considered normal
1171     ffado_timestamp_t one_update_step = nbframes * getRate();
1172     ffado_timestamp_t max_abs_diff = one_update_step * (1.0 + max_deviation);
1173    
1174     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " nbframes: %d, m_update_period: %d \n", nbframes, m_update_period);
1175     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " tail TS: "TIMESTAMP_FORMAT_SPEC", next tail TS: "TIMESTAMP_FORMAT_SPEC"\n",
1176                                           m_buffer_tail_timestamp, m_buffer_next_tail_timestamp);
1177     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " new TS: "TIMESTAMP_FORMAT_SPEC", wrapped new TS: "TIMESTAMP_FORMAT_SPEC"\n",
1178                                           new_timestamp, ts);
1179
1180     if (diff > max_abs_diff) {
1181 //         debugShowBackLogLines(100);
1182         debugWarning("(%p) difference rather large (+): diff="TIMESTAMP_FORMAT_SPEC", max="TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC"\n",
1183             this, diff, max_abs_diff, ts, pred_buffer_next_tail_timestamp);
1184     } else if (diff < -max_abs_diff) {
1185 //         debugShowBackLogLines(100);
1186         debugWarning("(%p) difference rather large (-): diff="TIMESTAMP_FORMAT_SPEC", max="TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC", "TIMESTAMP_FORMAT_SPEC"\n",
1187             this, diff, -max_abs_diff, ts, pred_buffer_next_tail_timestamp);
1188     }
1189
1190     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "(%p): diff="TIMESTAMP_FORMAT_SPEC" ",
1191                 this, diff);
1192
1193     double err = diff;
1194
1195     debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, "diff2="TIMESTAMP_FORMAT_SPEC" err=%f\n",
1196                     diff, err);
1197     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "B: FC=%10u, TS="TIMESTAMP_FORMAT_SPEC", NTS="TIMESTAMP_FORMAT_SPEC"\n",
1198                     m_framecounter, m_buffer_tail_timestamp, pred_buffer_next_tail_timestamp);
1199
1200     ENTER_CRITICAL_SECTION;
1201     m_framecounter += nbframes;
1202     m_buffer_tail_timestamp = pred_buffer_next_tail_timestamp;
1203     m_buffer_next_tail_timestamp = pred_buffer_next_tail_timestamp + (ffado_timestamp_t)(m_dll_b * err + m_dll_e2);
1204     m_dll_e2 += m_dll_c*err;
1205
1206     if (m_buffer_next_tail_timestamp >= m_wrap_at) {
1207         debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Unwrapping next tail timestamp: "TIMESTAMP_FORMAT_SPEC"",
1208                 m_buffer_next_tail_timestamp);
1209
1210         m_buffer_next_tail_timestamp -= m_wrap_at;
1211
1212         debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, " => "TIMESTAMP_FORMAT_SPEC"\n",
1213                 m_buffer_next_tail_timestamp);
1214
1215     }
1216     m_current_rate = calculateRate();
1217     EXIT_CRITICAL_SECTION;
1218
1219     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "A: TS="TIMESTAMP_FORMAT_SPEC", NTS="TIMESTAMP_FORMAT_SPEC", DLLe2=%f, RATE=%f\n",
1220                 m_buffer_tail_timestamp, m_buffer_next_tail_timestamp, m_dll_e2, m_current_rate);
1221
1222
1223     if(m_buffer_tail_timestamp>=m_wrap_at) {
1224         debugError("Wrapping failed for m_buffer_tail_timestamp! "TIMESTAMP_FORMAT_SPEC"\n",m_buffer_tail_timestamp);
1225         debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " IN="TIMESTAMP_FORMAT_SPEC", TS="TIMESTAMP_FORMAT_SPEC", NTS="TIMESTAMP_FORMAT_SPEC"\n",
1226                     ts, m_buffer_tail_timestamp, m_buffer_next_tail_timestamp);
1227
1228     }
1229     if(m_buffer_next_tail_timestamp>=m_wrap_at) {
1230         debugError("Wrapping failed for m_buffer_next_tail_timestamp! "TIMESTAMP_FORMAT_SPEC"\n",m_buffer_next_tail_timestamp);
1231         debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " IN="TIMESTAMP_FORMAT_SPEC", TS="TIMESTAMP_FORMAT_SPEC", NTS="TIMESTAMP_FORMAT_SPEC"\n",
1232                     ts, m_buffer_tail_timestamp, m_buffer_next_tail_timestamp);
1233     }
1234    
1235     if(m_buffer_tail_timestamp==m_buffer_next_tail_timestamp) {
1236         debugError("Current and next timestamps are equal: "TIMESTAMP_FORMAT_SPEC" "TIMESTAMP_FORMAT_SPEC"\n",
1237                    m_buffer_tail_timestamp,m_buffer_next_tail_timestamp);
1238    
1239     }
1240
1241     // this DLL allows the calculation of any sample timestamp relative to the buffer tail,
1242     // to the next period and beyond (through extrapolation)
1243     //
1244     // ts(x) = m_buffer_tail_timestamp +
1245     //         (m_buffer_next_tail_timestamp - m_buffer_tail_timestamp)/(samples_between_updates)*x
1246 }
1247
1248 /**
1249  * @brief Print status info.
1250  */
1251 void TimestampedBuffer::dumpInfo() {
1252
1253     ffado_timestamp_t ts_head;
1254     signed int fc;
1255     getBufferHeadTimestamp(&ts_head,&fc);
1256
1257 #ifdef DEBUG
1258     ffado_timestamp_t diff=(ffado_timestamp_t)ts_head - (ffado_timestamp_t)m_buffer_tail_timestamp;
1259 #endif
1260
1261     debugOutputShort( DEBUG_LEVEL_NORMAL, "  TimestampedBuffer (%p): %04d frames, %04d events\n",
1262                                           this, m_framecounter, getBufferFill());
1263     debugOutputShort( DEBUG_LEVEL_NORMAL, "   Timestamps           : head: "TIMESTAMP_FORMAT_SPEC", Tail: "TIMESTAMP_FORMAT_SPEC", Next tail: "TIMESTAMP_FORMAT_SPEC"\n",
1264                                           ts_head, m_buffer_tail_timestamp, m_buffer_next_tail_timestamp);
1265     debugOutputShort( DEBUG_LEVEL_NORMAL, "    Head - Tail         : "TIMESTAMP_FORMAT_SPEC"\n", diff);
1266     debugOutputShort( DEBUG_LEVEL_NORMAL, "   DLL Rate             : %f (%f)\n", m_dll_e2, m_dll_e2/m_update_period);
1267 }
1268
1269 } // end of namespace Util
Note: See TracBrowser for help on using the browser.