root/branches/libffado-2.0/src/libutil/TimestampedBuffer.cpp

Revision 1529, 36.4 kB (checked in by ppalmers, 15 years ago)

- don't use DEFER when we have sufficient frames. This is a huge performance killer. This might result in worse latency performance though...
- Also update the Timestampedbuffer DLL when dry-running such that we have a decent estimate of the samplerate. Use a large bandwidth for

this estimation to ensure that it tracks fast enough. Switch to a lower bandwidth once we start the actual streaming.

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