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

Revision 1531, 36.6 kB (checked in by ppalmers, 13 years ago)

svn merge -r 1506:HEAD svn+ssh://ffadosvn@ffado.org/ffado/branches/libffado-2.0

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