Add support for ICE/STUN/TURN in res_rtp_asterisk and chan_sip.
[asterisk/asterisk.git] / res / pjproject / pjlib / src / pj / os_timestamp_common.c
1 /* $Id$ */
2 /* 
3  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
19  */
20 #include <pj/os.h>
21 #include <pj/compat/high_precision.h>
22
23 #if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
24
25 #define U32MAX  (0xFFFFFFFFUL)
26 #define NANOSEC (1000000000UL)
27 #define USEC    (1000000UL)
28 #define MSEC    (1000)
29
30 #define u64tohighprec(u64)      ((pj_highprec_t)((pj_int64_t)(u64)))
31
32 static pj_highprec_t get_elapsed( const pj_timestamp *start,
33                                   const pj_timestamp *stop )
34 {
35 #if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0
36     return u64tohighprec(stop->u64 - start->u64);
37 #else
38     pj_highprec_t elapsed_hi, elapsed_lo;
39
40     elapsed_hi = stop->u32.hi - start->u32.hi;
41     elapsed_lo = stop->u32.lo - start->u32.lo;
42
43     /* elapsed_hi = elapsed_hi * U32MAX */
44     pj_highprec_mul(elapsed_hi, U32MAX);
45
46     return elapsed_hi + elapsed_lo;
47 #endif
48 }
49
50 static pj_highprec_t elapsed_msec( const pj_timestamp *start,
51                                    const pj_timestamp *stop )
52 {
53     pj_timestamp ts_freq;
54     pj_highprec_t freq, elapsed;
55
56     if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS)
57         return 0;
58
59     /* Convert frequency timestamp */
60 #if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0
61     freq = u64tohighprec(ts_freq.u64);
62 #else
63     freq = ts_freq.u32.hi;
64     pj_highprec_mul(freq, U32MAX);
65     freq += ts_freq.u32.lo;
66 #endif
67
68     /* Avoid division by zero. */
69     if (freq == 0) freq = 1;
70
71     /* Get elapsed time in cycles. */
72     elapsed = get_elapsed(start, stop);
73
74     /* usec = elapsed * MSEC / freq */
75     pj_highprec_mul(elapsed, MSEC);
76     pj_highprec_div(elapsed, freq);
77
78     return elapsed;
79 }
80
81 static pj_highprec_t elapsed_usec( const pj_timestamp *start,
82                                    const pj_timestamp *stop )
83 {
84     pj_timestamp ts_freq;
85     pj_highprec_t freq, elapsed;
86
87     if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS)
88         return 0;
89
90     /* Convert frequency timestamp */
91 #if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0
92     freq = u64tohighprec(ts_freq.u64);
93 #else
94     freq = ts_freq.u32.hi;
95     pj_highprec_mul(freq, U32MAX);
96     freq += ts_freq.u32.lo;
97 #endif
98
99     /* Avoid division by zero. */
100     if (freq == 0) freq = 1;
101
102     /* Get elapsed time in cycles. */
103     elapsed = get_elapsed(start, stop);
104
105     /* usec = elapsed * USEC / freq */
106     pj_highprec_mul(elapsed, USEC);
107     pj_highprec_div(elapsed, freq);
108
109     return elapsed;
110 }
111
112 PJ_DEF(pj_uint32_t) pj_elapsed_nanosec( const pj_timestamp *start,
113                                         const pj_timestamp *stop )
114 {
115     pj_timestamp ts_freq;
116     pj_highprec_t freq, elapsed;
117
118     if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS)
119         return 0;
120
121     /* Convert frequency timestamp */
122 #if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0
123     freq = u64tohighprec(ts_freq.u64);
124 #else
125     freq = ts_freq.u32.hi;
126     pj_highprec_mul(freq, U32MAX);
127     freq += ts_freq.u32.lo;
128 #endif
129
130     /* Avoid division by zero. */
131     if (freq == 0) freq = 1;
132
133     /* Get elapsed time in cycles. */
134     elapsed = get_elapsed(start, stop);
135
136     /* usec = elapsed * USEC / freq */
137     pj_highprec_mul(elapsed, NANOSEC);
138     pj_highprec_div(elapsed, freq);
139
140     return (pj_uint32_t)elapsed;
141 }
142
143 PJ_DEF(pj_uint32_t) pj_elapsed_usec( const pj_timestamp *start,
144                                      const pj_timestamp *stop )
145 {
146     return (pj_uint32_t)elapsed_usec(start, stop);
147 }
148
149 PJ_DEF(pj_uint32_t) pj_elapsed_msec( const pj_timestamp *start,
150                                      const pj_timestamp *stop )
151 {
152     return (pj_uint32_t)elapsed_msec(start, stop);
153 }
154
155 PJ_DEF(pj_uint64_t) pj_elapsed_msec64(const pj_timestamp *start,
156                                       const pj_timestamp *stop )
157 {
158     return (pj_uint64_t)elapsed_msec(start, stop);
159 }
160
161 PJ_DEF(pj_time_val) pj_elapsed_time( const pj_timestamp *start,
162                                      const pj_timestamp *stop )
163 {
164     pj_highprec_t elapsed = elapsed_msec(start, stop);
165     pj_time_val tv_elapsed;
166
167     if (PJ_HIGHPREC_VALUE_IS_ZERO(elapsed)) {
168         tv_elapsed.sec = tv_elapsed.msec = 0;
169         return tv_elapsed;
170     } else {
171         pj_highprec_t sec, msec;
172
173         sec = elapsed;
174         pj_highprec_div(sec, MSEC);
175         tv_elapsed.sec = (long)sec;
176
177         msec = elapsed;
178         pj_highprec_mod(msec, MSEC);
179         tv_elapsed.msec = (long)msec;
180
181         return tv_elapsed;
182     }
183 }
184
185 PJ_DEF(pj_uint32_t) pj_elapsed_cycle( const pj_timestamp *start,
186                                       const pj_timestamp *stop )
187 {
188     return stop->u32.lo - start->u32.lo;
189 }
190
191 PJ_DEF(pj_status_t) pj_gettickcount(pj_time_val *tv)
192 {
193     pj_timestamp ts, start;
194     pj_status_t status;
195
196     if ((status = pj_get_timestamp(&ts)) != PJ_SUCCESS)
197         return status;
198
199     pj_set_timestamp32(&start, 0, 0);
200     *tv = pj_elapsed_time(&start, &ts);
201
202     return PJ_SUCCESS;
203 }
204
205 #endif  /* PJ_HAS_HIGH_RES_TIMER */
206