Add support for ICE/STUN/TURN in res_rtp_asterisk and chan_sip.
[asterisk/asterisk.git] / res / pjproject / pjlib / src / pj / os_timestamp_posix.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/errno.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <ctype.h>
26
27 #if defined(PJ_HAS_UNISTD_H) && PJ_HAS_UNISTD_H != 0
28 #   include <unistd.h>
29
30 #   if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && \
31        defined(_POSIX_MONOTONIC_CLOCK)
32 #       define USE_POSIX_TIMERS 1
33 #   endif
34
35 #endif
36
37 #if defined(PJ_HAS_PENTIUM) && PJ_HAS_PENTIUM!=0 && \
38     defined(PJ_TIMESTAMP_USE_RDTSC) && PJ_TIMESTAMP_USE_RDTSC!=0 && \
39     defined(PJ_M_I386) && PJ_M_I386!=0 && \
40     defined(PJ_LINUX) && PJ_LINUX!=0
41 static int machine_speed_mhz;
42 static pj_timestamp machine_speed;
43
44 static __inline__ unsigned long long int rdtsc()
45 {
46     unsigned long long int x;
47     __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
48     return x;
49 }
50
51 /* Determine machine's CPU MHz to get the counter's frequency.
52  */
53 static int get_machine_speed_mhz()
54 {
55     FILE *strm;
56     char buf[512];
57     int len;
58     char *pos, *end;
59         
60     PJ_CHECK_STACK();
61         
62     /* Open /proc/cpuinfo and read the file */
63     strm = fopen("/proc/cpuinfo", "r");
64     if (!strm)
65         return -1;
66     len = fread(buf, 1, sizeof(buf), strm);
67     fclose(strm);
68     if (len < 1) {
69         return -1;
70     }
71     buf[len] = '\0';
72
73     /* Locate the MHz digit. */
74     pos = strstr(buf, "cpu MHz");
75     if (!pos)
76         return -1;
77     pos = strchr(pos, ':');
78     if (!pos)
79         return -1;
80     end = (pos += 2);
81     while (isdigit(*end)) ++end;
82     *end = '\0';
83
84     /* Return the Mhz part, and give it a +1. */
85     return atoi(pos)+1;
86 }
87
88 PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
89 {
90     if (machine_speed_mhz == 0) {
91         machine_speed_mhz = get_machine_speed_mhz();
92         if (machine_speed_mhz > 0) {
93             machine_speed.u64 = machine_speed_mhz * 1000000.0;
94         }
95     }
96     
97     if (machine_speed_mhz == -1) {
98         ts->u64 = 0;
99         return -1;
100     } 
101     ts->u64 = rdtsc();
102     return 0;
103 }
104
105 PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
106 {
107     if (machine_speed_mhz == 0) {
108         machine_speed_mhz = get_machine_speed_mhz();
109         if (machine_speed_mhz > 0) {
110             machine_speed.u64 = machine_speed_mhz * 1000000.0;
111         }
112     }
113     
114     if (machine_speed_mhz == -1) {
115         freq->u64 = 1;  /* return 1 to prevent division by zero in apps. */
116         return -1;
117     } 
118
119     freq->u64 = machine_speed.u64;
120     return 0;
121 }
122
123 #elif defined(PJ_DARWINOS) && PJ_DARWINOS != 0
124 #include <mach/mach.h>
125 #include <mach/clock.h>
126 #include <errno.h>
127
128 #define NSEC_PER_SEC    1000000000
129
130 PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
131 {
132     mach_timespec_t tp;
133     int ret;
134     clock_serv_t serv;
135
136     ret = host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &serv);
137     if (ret != KERN_SUCCESS) {
138         return PJ_RETURN_OS_ERROR(EINVAL);
139     }
140
141     ret = clock_get_time(serv, &tp);
142     if (ret != KERN_SUCCESS) {
143         return PJ_RETURN_OS_ERROR(EINVAL);
144     }
145
146     ts->u64 = tp.tv_sec;
147     ts->u64 *= NSEC_PER_SEC;
148     ts->u64 += tp.tv_nsec;
149
150     return PJ_SUCCESS;
151 }
152
153 PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
154 {
155     freq->u32.hi = 0;
156     freq->u32.lo = NSEC_PER_SEC;
157
158     return PJ_SUCCESS;
159 }
160
161 #elif defined(USE_POSIX_TIMERS) && USE_POSIX_TIMERS != 0
162 #include <sys/time.h>
163 #include <time.h>
164 #include <errno.h>
165
166 #define NSEC_PER_SEC    1000000000
167
168 PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
169 {
170     struct timespec tp;
171
172     if (clock_gettime(CLOCK_MONOTONIC, &tp) != 0) {
173         return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
174     }
175
176     ts->u64 = tp.tv_sec;
177     ts->u64 *= NSEC_PER_SEC;
178     ts->u64 += tp.tv_nsec;
179
180     return PJ_SUCCESS;
181 }
182
183 PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
184 {
185     freq->u32.hi = 0;
186     freq->u32.lo = NSEC_PER_SEC;
187
188     return PJ_SUCCESS;
189 }
190
191 #else
192 #include <sys/time.h>
193 #include <errno.h>
194
195 #define USEC_PER_SEC    1000000
196
197 PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
198 {
199     struct timeval tv;
200
201     if (gettimeofday(&tv, NULL) != 0) {
202         return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
203     }
204
205     ts->u64 = tv.tv_sec;
206     ts->u64 *= USEC_PER_SEC;
207     ts->u64 += tv.tv_usec;
208
209     return PJ_SUCCESS;
210 }
211
212 PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
213 {
214     freq->u32.hi = 0;
215     freq->u32.lo = USEC_PER_SEC;
216
217     return PJ_SUCCESS;
218 }
219
220 #endif