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

Revision 803, 9.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 #ifndef __FFADO_TIMESTAMPEDBUFFER__
25 #define __FFADO_TIMESTAMPEDBUFFER__
26
27 #include "../debugmodule/debugmodule.h"
28 #include "libutil/ringbuffer.h"
29 #include <semaphore.h>
30
31 //typedef float ffado_timestamp_t;
32 //#define TIMESTAMP_FORMAT_SPEC "%14.3f"
33 typedef double ffado_timestamp_t;
34 #define TIMESTAMP_FORMAT_SPEC "%14.3f"
35 // typedef int64_t ffado_timestamp_t;
36 // #define TIMESTAMP_FORMAT_SPEC "%012lld"
37
38 namespace Util
39 {
40
41 class TimestampedBufferClient;
42
43 /**
44     * \brief Class implementing a frame buffer that is time-aware
45     *
46     * This class implements a buffer that is time-aware. Whenever new frames
47     * are written to the buffer, the timestamp corresponding to the last frame
48     * in the buffer is updated. This allows to calculate the timestamp of any
49     * other frame in the buffer.
50     *
51     * The buffer is a frame buffer, having the following parameters defining
52     * it's behaviour:
53     * - buff_size: buffer size in frames (setBufferSize())
54     * - events_per_frame: the number of events per frame (setEventsPerFrame())
55     * - event_size: the storage size of the events (in bytes) (setEventSize())
56     *
57     * The total size of the buffer (in bytes) is at least
58     * buff_size*events_per_frame*event_size.
59     *
60     * Timestamp tracking is done by requiring that a timestamp is specified every
61     * time frames are added to the buffer. In combination with the buffer fill and
62     * the frame rate (calculated internally), this allows to calculate the timestamp
63     * of any frame in the buffer. In order to initialize the internal data structures,
64     * the setNominalRate() and setUpdatePeriod() functions are provided.
65     *
66     * \note Currently the class only supports fixed size writes of size update_period.
67     *       This can change in the future, implementation ideas are already in place.
68     *
69     * The TimestampedBuffer class is time unit agnostic. It can handle any time unit
70     * as long as it fits in a 64 bit unsigned integer. The buffer supports wrapped
71     * timestamps using (...).
72     *
73     * There are two methods of reading and writing to the buffer.
74     *
75     * The first method uses conventional readFrames() and writeFrames() functions.
76     *
77     * The second method makes use of the TimestampedBufferClient interface. When a
78     * TimestampedBuffer is created, it is required that a TimestampedBufferClient is
79     * registered. This client implements the processReadBlock and processWriteBlock
80     * functions. These are block processing 'callbacks' that allow zero-copy processing
81     * of the buffer contents. In order to initiate block processing, the
82     * blockProcessWriteFrames and blockProcessReadFrames functions are provided by
83     * TimestampedBuffer.
84     *
85     */
86 class TimestampedBuffer
87 {
88     public:
89         TimestampedBuffer ( TimestampedBufferClient * );
90         virtual ~TimestampedBuffer();
91
92         /**
93          * @brief waits for the availability of frames (blocking)
94          * @param nframes number of frames
95          *
96          * @return true if frames are available, false if not (e.g. signal occurred)
97          */
98         bool waitForFrames(unsigned int nframes);
99
100         /**
101          * @brief waits for the availability of frames (blocking)
102          *
103          * waits for one update period of frames
104          *
105          * @return true if frames are available, false if not (e.g. signal occurred)
106          */
107         bool waitForFrames();
108
109         /**
110          * @brief waits for the availability of frames (non-blocking)
111          * @param nframes number of frames
112          *
113          * @return true if frames are available, false if not
114          */
115         bool tryWaitForFrames(unsigned int nframes);
116
117         /**
118          * @brief waits for the availability of frames (non-blocking)
119          *
120          * waits for one update period of frames
121          *
122          * @return true if frames are available, false if not
123          */
124         bool tryWaitForFrames();
125
126         bool writeDummyFrame();
127         bool dropFrames ( unsigned int nbframes );
128
129         bool writeFrames ( unsigned int nbframes, char *data, ffado_timestamp_t ts );
130         bool readFrames ( unsigned int nbframes, char *data );
131
132         bool preloadFrames ( unsigned int nbframes, char *data, bool keep_head_ts );
133
134         bool blockProcessWriteFrames ( unsigned int nbframes, ffado_timestamp_t ts );
135         bool blockProcessReadFrames ( unsigned int nbframes );
136
137         bool init();
138         bool prepare();
139         bool clearBuffer();
140
141         bool isEnabled() {return m_enabled;};
142         void enable() {m_enabled=true;};
143         void disable() {m_enabled=false;};
144
145         bool isTransparent() {return m_transparent;};
146         void setTransparent ( bool v ) {m_transparent=v;};
147
148         bool setEventSize ( unsigned int s );
149         bool setEventsPerFrame ( unsigned int s );
150         bool setBufferSize ( unsigned int s );
151         unsigned int getBufferSize() {return m_buffer_size;};
152
153         unsigned int getBytesPerFrame() {return m_bytes_per_frame;};
154
155         bool setWrapValue ( ffado_timestamp_t w );
156
157         unsigned int getBufferFill();
158
159         // timestamp stuff
160         int getFrameCounter() {return m_framecounter;};
161
162         void getBufferHeadTimestamp ( ffado_timestamp_t *ts, signed int *fc );
163         void getBufferTailTimestamp ( ffado_timestamp_t *ts, signed int *fc );
164
165         void setBufferTailTimestamp ( ffado_timestamp_t new_timestamp );
166         void setBufferHeadTimestamp ( ffado_timestamp_t new_timestamp );
167
168         // sync related, also drops or add frames when necessary
169         bool syncBufferHeadToTimestamp ( ffado_timestamp_t ts );
170         bool syncBufferTailToTimestamp ( ffado_timestamp_t ts );
171         bool syncCorrectLag ( int64_t ts );
172
173         ffado_timestamp_t getTimestampFromTail ( int nframes );
174         ffado_timestamp_t getTimestampFromHead ( int nframes );
175
176         // buffer offset stuff
177         /// return the tick offset value
178         ffado_timestamp_t getTickOffset() {return m_tick_offset;};
179
180         bool setFrameOffset ( int nframes );
181         bool setTickOffset ( ffado_timestamp_t );
182
183         // dll stuff
184         bool setNominalRate ( float r );
185         float getNominalRate() {return m_nominal_rate;};
186         float getRate();
187
188         bool setUpdatePeriod ( unsigned int t );
189         unsigned int getUpdatePeriod();
190
191         // misc stuff
192         void dumpInfo();
193         void setVerboseLevel ( int l ) {setDebugLevel ( l );};
194
195     private:
196         void decrementFrameCounter ( int nbframes );
197         void incrementFrameCounter ( int nbframes, ffado_timestamp_t new_timestamp );
198         void resetFrameCounter();
199
200     protected:
201
202         ffado_ringbuffer_t * m_event_buffer;
203         char* m_cluster_buffer;
204
205         unsigned int m_event_size; // the size of one event
206         unsigned int m_events_per_frame; // the number of events in a frame
207         unsigned int m_buffer_size; // the number of frames in the buffer
208         unsigned int m_bytes_per_frame;
209         unsigned int m_bytes_per_buffer;
210         bool m_enabled; // you can get frames FIXME: rename!!
211         bool m_transparent; // the buffer should hold the frames put in it. if true, discards all frames
212
213         ffado_timestamp_t m_wrap_at; // value to wrap at
214
215         TimestampedBufferClient *m_Client;
216
217         DECLARE_DEBUG_MODULE;
218
219     private:
220         // the framecounter gives the number of frames in the buffer
221         signed int m_framecounter;
222
223         // the offset that define the timing of the buffer
224         ffado_timestamp_t m_tick_offset;
225
226         // the buffer tail timestamp gives the timestamp of the last frame
227         // that was put into the buffer
228         ffado_timestamp_t   m_buffer_tail_timestamp;
229         ffado_timestamp_t   m_buffer_next_tail_timestamp;
230
231         // this mutex protects the access to the framecounter
232         // and the buffer head timestamp.
233         pthread_mutex_t m_framecounter_lock;
234
235         // tracking DLL variables
236 // JMW: try double for this too
237 //    float m_dll_e2;
238         double m_dll_e2;
239         float m_dll_b;
240         float m_dll_c;
241
242         float m_nominal_rate;
243         float calculateRate();
244         float m_current_rate;
245         unsigned int m_update_period;
246
247         sem_t m_frame_semaphore;
248 };
249
250 /**
251     * \brief Interface to be implemented by TimestampedBuffer clients
252     */
253 class TimestampedBufferClient
254 {
255     public:
256         TimestampedBufferClient() {};
257         virtual ~TimestampedBufferClient() {};
258
259         virtual bool processReadBlock ( char *data, unsigned int nevents, unsigned int offset ) =0;
260         virtual bool processWriteBlock ( char *data, unsigned int nevents, unsigned int offset ) =0;
261
262 };
263
264 } // end of namespace Util
265
266 #endif /* __FFADO_TIMESTAMPEDBUFFER__ */
267
268
Note: See TracBrowser for help on using the browser.