root/branches/streaming-rework/src/libutil/TimeSource.cpp

Revision 419, 9.2 kB (checked in by pieterpalmers, 17 years ago)

namespace simplification

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