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