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

Revision 833, 42.3 kB (checked in by ppalmers, 16 years ago)

merge api-cleanup branch (R808:832) into trunk

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