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

Revision 864, 8.7 kB (checked in by ppalmers, 16 years ago)

update license to GPLv2 or GPLv3 instead of GPLv2 or any later version. Update copyrights to reflect the new year

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 "TimeSource.h"
25
26 #include <time.h>
27
28 #include <assert.h>
29
30 #include "libutil/Time.h"
31
32 namespace Util {
33
34 IMPL_DEBUG_MODULE( TimeSource, TimeSource, DEBUG_LEVEL_NORMAL );
35
36 TimeSource::TimeSource() :
37     m_Master(NULL), m_last_master_time(0), m_last_time(0),
38     m_slave_rate(0.0), m_slave_offset(0), m_last_err(0.0)
39 {
40
41 }
42
43 TimeSource::~TimeSource() {
44
45 }
46 /**
47  * (re)Initializes the TimeSource
48  *
49  * @return true if successful
50  */
51 void TimeSource::initSlaveTimeSource() {
52     ffado_microsecs_t my_time;
53     ffado_microsecs_t master_time;
54     ffado_microsecs_t my_time2;
55     ffado_microsecs_t master_time2;
56
57     if (m_Master) {
58         my_time=getCurrentTime();
59         master_time=m_Master->getCurrentTime();
60
61         struct timespec ts;
62
63         // sleep for ten milliseconds
64         ts.tv_sec=0;
65         ts.tv_nsec=10000000L;
66
67         nanosleep(&ts,NULL);
68
69         my_time2=getCurrentTime();
70         master_time2=m_Master->getCurrentTime();
71
72         float diff_slave=my_time2-my_time;
73         float diff_master=master_time2-master_time;
74
75         m_slave_rate=diff_slave/diff_master;
76
77         // average of the two offset estimates
78         m_slave_offset  = my_time-wrapTime((ffado_microsecs_t)(master_time*m_slave_rate));
79         m_slave_offset += my_time2-wrapTime((ffado_microsecs_t)(master_time2*m_slave_rate));
80         m_slave_offset /= 2;
81
82         m_last_master_time=master_time2;
83         m_last_time=my_time2;
84
85         debugOutput(DEBUG_LEVEL_NORMAL,"init slave: master=%lu, master2=%lu, diff=%f\n",
86             master_time, master_time2, diff_master);
87         debugOutput(DEBUG_LEVEL_NORMAL,"init slave: slave =%lu, slave2 =%lu, diff=%f\n",
88             my_time, my_time2, diff_slave);
89         debugOutput(DEBUG_LEVEL_NORMAL,"init slave: slave rate=%f, slave_offset=%lu\n",
90             m_slave_rate, m_slave_offset
91             );
92     }
93
94
95 }
96
97 /**
98  * Maps a time point of the master to a time point
99  * on it's own timeline
100  *
101  * @return the mapped time point
102  */
103 ffado_microsecs_t TimeSource::mapMasterTime(ffado_microsecs_t master_time) {
104     if(m_Master) {
105         // calculate the slave based upon the master
106         // and the estimated rate
107
108         // linear interpolation
109         int delta_master=master_time-m_last_master_time;
110
111         float offset=m_slave_rate * ((float)delta_master);
112
113         ffado_microsecs_t mapped=m_last_time+(int)offset;
114
115         debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"map time: master=%d, offset=%f, slave_base=%lu, pred_ticks=%lu\n",
116             master_time, offset, m_last_time,mapped
117             );
118
119         return wrapTime(mapped);
120
121     } else {
122         debugOutput( DEBUG_LEVEL_VERBOSE, "Requested map for non-slave TimeSource\n");
123
124         return master_time;
125     }
126 }
127
128 /**
129  * Update the internal state of the TimeSource
130  *
131  */
132 bool TimeSource::updateTimeSource() {
133     // update all slaves
134     for ( TimeSourceVectorIterator it = m_Slaves.begin();
135           it != m_Slaves.end(); ++it ) {
136
137         // update the slave with the current
138         // master time
139         if (!(*it)->updateTimeSource()) return false;
140     }
141
142     // this TimeSource has a master
143     if(m_Master) {
144         ffado_microsecs_t my_time=getCurrentTime();
145         ffado_microsecs_t master_time=m_Master->getCurrentTime();
146
147         // we assume that the master and slave time are
148         // measured at the same time, but that of course is
149         // not really true. The DLL will have to filter this
150         // out.
151
152         // the difference in master time
153         int64_t delta_master;
154         if (master_time > m_last_master_time) {
155             delta_master=master_time-m_last_master_time;
156         } else { // wraparound
157             delta_master=m_Master->unWrapTime(master_time)-m_last_master_time;
158         }
159
160         // the difference in slave time
161         int64_t delta_slave;
162         if (my_time > m_last_time) {
163             delta_slave=my_time-m_last_time;
164         } else { // wraparound
165             delta_slave=unWrapTime(my_time)-m_last_time;
166         }
167
168         // the estimated slave difference
169         int delta_slave_est=(int)(m_slave_rate * ((double)delta_master));
170
171         // the measured & estimated rate
172         double rate_meas=((double)delta_slave/(double)delta_master);
173         double rate_est=((double)m_slave_rate);
174
175         m_last_err=(rate_meas-rate_est);
176
177         m_slave_rate += 0.01*m_last_err;
178
179         debugOutput(DEBUG_LEVEL_VERBOSE,"update slave: master=%llu, master2=%llu, diff=%lld\n",
180             master_time, m_last_master_time, delta_master);
181         debugOutput(DEBUG_LEVEL_VERBOSE,"update slave: slave =%llu, slave2 =%llu, diff=%lld, diff_est=%d\n",
182             my_time, m_last_time, delta_slave, delta_slave_est);
183         debugOutput(DEBUG_LEVEL_VERBOSE,"update slave: slave rate meas=%f, slave rate est=%f, err=%f, slave rate=%f\n",
184             rate_meas, rate_est, m_last_err, m_slave_rate
185             );
186
187
188         m_last_master_time=master_time;
189
190         int64_t tmp = delta_slave_est;
191         tmp += m_last_time;
192
193         m_last_time = tmp;
194
195
196
197     }
198
199     return true;
200 }
201
202 /**
203  * Sets the master TimeSource for this timesource.
204  * This TimeSource will sync to the master TimeSource,
205  * making that it will be able to map a time point of
206  * the master to a time point on it's own timeline
207  *
208  * @param ts master TimeSource
209  * @return true if successful
210  */
211 bool TimeSource::setMaster(TimeSource *ts) {
212     if (m_Master==NULL) {
213         m_Master=ts;
214
215         // initialize ourselves.
216         initSlaveTimeSource();
217
218         return true;
219     } else return false;
220 }
221
222 /**
223  * Clears the master TimeSource for this timesource.
224  *
225  * @return true if successful
226  */
227 void TimeSource::clearMaster() {
228     m_Master=NULL;
229 }
230
231 /**
232  * Registers a slave timesource to this master.
233  * A slave TimeSource will sync to this TimeSource,
234  * making that it will be able to map a time point of
235  * the master (this) TimeSource to a time point on
236  * it's own timeline
237  *
238  * @param ts slave TimeSource to register
239  * @return true if successful
240  */
241 bool TimeSource::registerSlave(TimeSource *ts) {
242     // TODO: we should check for circular master-slave relationships.
243
244     debugOutput( DEBUG_LEVEL_VERBOSE, "Registering slave (%p)\n", ts);
245     assert(ts);
246
247     // inherit debug level
248     ts->setVerboseLevel(getDebugLevel());
249
250     if(ts->setMaster(this)) {
251         m_Slaves.push_back(ts);
252         return true;
253     } else {
254         return false;
255     }
256 }
257
258 /**
259  * Unregisters a slave TimeSource
260  *
261  * @param ts slave TimeSource to unregister
262  * @return true if successful
263  */
264 bool TimeSource::unregisterSlave(TimeSource *ts) {
265     debugOutput( DEBUG_LEVEL_VERBOSE, "Unregistering TimeSource (%p)\n", ts);
266     assert(ts);
267
268     for ( TimeSourceVectorIterator it = m_Slaves.begin();
269           it != m_Slaves.end(); ++it ) {
270
271         if ( *it == ts ) {
272             m_Slaves.erase(it);
273             ts->clearMaster();
274             return true;
275         }
276     }
277
278     debugOutput( DEBUG_LEVEL_VERBOSE, " TimeSource (%p) not found\n", ts);
279
280     return false;
281 }
282
283 /**
284  * Set verbosity level.
285  * All slave timesources get the same verbosity level
286  *
287  * @param l verbosity level
288  */
289 void TimeSource::setVerboseLevel(int l) {
290     setDebugLevel(l);
291
292     for ( TimeSourceVectorIterator it = m_Slaves.begin();
293           it != m_Slaves.end(); ++it ) {
294
295         (*it)->setVerboseLevel(l);
296     }
297
298 }
299
300 void TimeSource::printTimeSourceInfo() {
301     debugOutputShort( DEBUG_LEVEL_NORMAL, "TimeSource (%p) info\n", this);
302     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Master           : %p\n", m_Master);
303     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Slave rate       : %f\n", m_slave_rate);
304     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Slave offset     : %lld\n", m_slave_offset);
305     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Last error       : %f\n", m_last_err);
306     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Last master time : %llu\n",m_last_master_time );
307     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Last slave time  : %llu\n",m_last_time );
308
309
310     for ( TimeSourceVectorIterator it = m_Slaves.begin();
311           it != m_Slaves.end(); ++it ) {
312
313         (*it)->printTimeSourceInfo();
314     }
315 }
316
317 } // end of namespace Util
Note: See TracBrowser for help on using the browser.