1 /*
2  * Copyright (C) 2016 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 UTILITY_AUDIO_CLOCK_H
18 #define UTILITY_AUDIO_CLOCK_H
19 
20 #include <errno.h>
21 #include <stdint.h>
22 #include <time.h>
23 
24 #include <aaudio/AAudio.h>
25 
26 // Time conversion constants.
27 #define AAUDIO_NANOS_PER_MICROSECOND ((int64_t)1000)
28 #define AAUDIO_NANOS_PER_MILLISECOND (AAUDIO_NANOS_PER_MICROSECOND * 1000)
29 #define AAUDIO_MILLIS_PER_SECOND     1000
30 #define AAUDIO_NANOS_PER_SECOND      (AAUDIO_NANOS_PER_MILLISECOND * AAUDIO_MILLIS_PER_SECOND)
31 
32 class AudioClock {
33 public:
34     static int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) {
35         struct timespec time;
36         int result = clock_gettime(clockId, &time);
37         if (result < 0) {
38             return -errno;
39         }
40         return (time.tv_sec * AAUDIO_NANOS_PER_SECOND) + time.tv_nsec;
41     }
42 
43     /**
44      * Sleep until the specified absolute time.
45      * Return immediately with AAUDIO_ERROR_ILLEGAL_ARGUMENT if a negative
46      * nanoTime is specified.
47      *
48      * @param nanoTime time to wake up
49      * @param clockId CLOCK_MONOTONIC is default
50      * @return 0, a negative error, or 1 if the call is interrupted by a signal handler (EINTR)
51      */
52     static int sleepUntilNanoTime(int64_t nanoTime,
53                                   clockid_t clockId = CLOCK_MONOTONIC) {
54         if (nanoTime > 0) {
55             struct timespec time;
56             time.tv_sec = nanoTime / AAUDIO_NANOS_PER_SECOND;
57             // Calculate the fractional nanoseconds. Avoids expensive % operation.
58             time.tv_nsec = nanoTime - (time.tv_sec * AAUDIO_NANOS_PER_SECOND);
59             int err = clock_nanosleep(clockId, TIMER_ABSTIME, &time, nullptr);
60             switch (err) {
61             case EINTR:
62                 return 1;
63             case 0:
64                 return 0;
65             default:
66                 // Subtract because clock_nanosleep() returns a positive error number!
67                 return 0 - err;
68             }
69         } else {
70             return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
71         }
72     }
73 
74     /**
75      * Sleep for the specified number of relative nanoseconds in real-time.
76      * Return immediately with 0 if a negative nanoseconds is specified.
77      *
78      * @param nanoseconds time to sleep
79      * @param clockId CLOCK_MONOTONIC is default
80      * @return 0, a negative error, or 1 if the call is interrupted by a signal handler (EINTR)
81      */
82     static int sleepForNanos(int64_t nanoseconds, clockid_t clockId = CLOCK_MONOTONIC) {
83         if (nanoseconds > 0) {
84             struct timespec time;
85             time.tv_sec = nanoseconds / AAUDIO_NANOS_PER_SECOND;
86             // Calculate the fractional nanoseconds. Avoids expensive % operation.
87             time.tv_nsec = nanoseconds - (time.tv_sec * AAUDIO_NANOS_PER_SECOND);
88             const int flags = 0; // documented as relative sleep
89             int err = clock_nanosleep(clockId, flags, &time, nullptr);
90             switch (err) {
91             case EINTR:
92                 return 1;
93             case 0:
94                 return 0;
95             default:
96                 // Subtract because clock_nanosleep() returns a positive error number!
97                 return 0 - err;
98             }
99         }
100         return 0;
101     }
102 };
103 
104 
105 #endif // UTILITY_AUDIO_CLOCK_H
106