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

Revision 803, 43.3 kB (checked in by ppalmers, 13 years ago)

more reliable streaming. hackish, but a start for a better implementation

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