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

Revision 858, 42.5 kB (checked in by ppalmers, 16 years ago)

minor fixes

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     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.