1 /*
2 * Copyright 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef ANDROID_AUDIO_CLOCK_H
18 #define ANDROID_AUDIO_CLOCK_H
19
20 // This file can be included for either C or C++ source.
21
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <sys/time.h>
25 #include <time.h>
26
27 // These are declared as macros for compatbility with existing uses.
28 // TODO Spell out the words in full.
29 #define MICROS_PER_SECOND 1000000LL
30 #define MILLIS_PER_SECOND 1000LL
31 #define NANOS_PER_MICROSECOND 1000LL
32 #define NANOS_PER_MILLISECOND 1000000LL
33 #define NANOS_PER_SECOND 1000000000LL
34
35 #define SECONDS_PER_MINUTE 60LL
36 #define MINUTES_PER_HOUR 60LL
37
38 #define MICROS_PER_MINUTE (MICROS_PER_SECOND * SECONDS_PER_MINUTE)
39 #define MILLIS_PER_MINUTE (MILLIS_PER_SECOND * SECONDS_PER_MINUTE)
40 #define NANOS_PER_MINUTE (NANOS_PER_SECOND * SECONDS_PER_MINUTE)
41
42 #define MICROS_PER_HOUR (MICROS_PER_MINUTE * MINUTES_PER_HOUR)
43 #define MILLIS_PER_HOUR (MILLIS_PER_MINUTE * MINUTES_PER_HOUR)
44 #define NANOS_PER_HOUR (NANOS_PER_MINUTE * MINUTES_PER_HOUR)
45
46 /**
47 * \brief Converts time in ns to a time string, with format similar to logcat.
48 * \param ns input time in nanoseconds to convert.
49 * \param buffer caller allocated string buffer, buffer_length must be >= 19 chars
50 * in order to fully fit in time. The string is always returned
51 * null terminated if buffer_size is greater than zero.
52 * \param buffer_size size of buffer.
53 */
audio_utils_ns_to_string(int64_t ns,char * buffer,size_t buffer_size)54 static inline void audio_utils_ns_to_string(int64_t ns, char *buffer, size_t buffer_size)
55 {
56 if (buffer_size == 0) return;
57
58 const int one_second = 1000000000;
59 const time_t sec = ns / one_second;
60 struct tm tm;
61
62 // Supported on bionic, glibc, and macOS, but not mingw.
63 if (localtime_r(&sec, &tm) == NULL) {
64 buffer[0] = '\0';
65 return;
66 }
67
68 if (snprintf(buffer, buffer_size, "%02d-%02d %02d:%02d:%02d.%03d",
69 tm.tm_mon + 1, // localtime_r uses months in 0 - 11 range
70 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
71 (int)(ns % one_second / 1000000)) < 0) {
72 buffer[0] = '\0'; // null terminate on format error, which should not happen
73 }
74 }
75
76 /**
77 * An object that contains the formatted time string.
78 *
79 * The time string is 19 characters (including null termination).
80 * Example: "03-27 16:47:06.187"
81 * MM DD HH MM SS MS
82 */
83 typedef struct audio_utils_time_string {
84 char time[19]; /* minimum size buffer */
85 } audio_utils_time_string_t;
86
87 /**
88 * \brief Converts time in ns to a time string object, with format similar to logcat.
89 * \param ns input time in nanoseconds to convert.
90 */
audio_utils_time_string_from_ns(int64_t ns)91 static inline audio_utils_time_string_t audio_utils_time_string_from_ns(int64_t ns)
92 {
93 audio_utils_time_string_t ts;
94
95 audio_utils_ns_to_string(ns, ts.time, sizeof(ts.time));
96 return ts;
97 }
98
99 /**
100 * \brief Converts a timespec to nanoseconds.
101 * \param ts input timespec to convert.
102 * \return timespec converted to nanoseconds.
103 */
audio_utils_ns_from_timespec(const struct timespec * ts)104 static inline int64_t audio_utils_ns_from_timespec(const struct timespec *ts)
105 {
106 return ts->tv_sec * 1000000000LL + ts->tv_nsec;
107 }
108
109 /**
110 * \brief Gets the real time clock in nanoseconds.
111 * \return the real time clock in nanoseconds, or 0 on error.
112 */
audio_utils_get_real_time_ns()113 static inline int64_t audio_utils_get_real_time_ns() {
114
115 #if defined(__linux__)
116
117 struct timespec now_ts;
118 if (clock_gettime(CLOCK_REALTIME, &now_ts) == 0) {
119 return audio_utils_ns_from_timespec(&now_ts);
120 }
121 return 0; // should not happen.
122
123 #else
124
125 // Mac OS X compatible
126 struct timeval now_tv;
127 if (gettimeofday(&now_tv, NULL /* struct timezone * */) == 0) {
128 return now_tv.tv_sec * 1000000000LL + now_tv.tv_usec * 1000LL;
129 }
130 return 0; // should not happen.
131
132 #endif
133
134 }
135
136 #endif // !ANDROID_AUDIO_CLOCK_H
137