1/*
2 * Copyright (C) 2013 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_TIMESTAMP_H
18#define ANDROID_AUDIO_TIMESTAMP_H
19
20#include <string>
21#include <sstream>
22#include <time.h>
23
24namespace android {
25
26class AudioTimestamp {
27public:
28    AudioTimestamp() : mPosition(0) {
29        mTime.tv_sec = 0;
30        mTime.tv_nsec = 0;
31    }
32    // FIXME change type to match android.media.AudioTrack
33    uint32_t        mPosition; // a frame position in AudioTrack::getPosition() units
34    struct timespec mTime;     // corresponding CLOCK_MONOTONIC when frame is expected to present
35};
36
37struct alignas(8) /* bug 29096183, bug 29108507 */ ExtendedTimestamp {
38    enum Location {
39        LOCATION_INVALID = -1,
40        // Locations in the audio playback / record pipeline.
41        LOCATION_CLIENT,   // timestamp of last read frame from client-server track buffer.
42        LOCATION_SERVER,   // timestamp of newest frame from client-server track buffer.
43        LOCATION_KERNEL,   // timestamp of newest frame in the kernel (alsa) buffer.
44
45        // Historical data: info when the kernel timestamp was OK (prior to the newest frame).
46        // This may be useful when the newest frame kernel timestamp is unavailable.
47        // Available for playback timestamps.
48        LOCATION_SERVER_LASTKERNELOK, // timestamp of server the prior time kernel timestamp OK.
49        LOCATION_KERNEL_LASTKERNELOK, // timestamp of kernel the prior time kernel timestamp OK.
50        LOCATION_MAX       // for sizing arrays only
51    };
52
53    // This needs to be kept in sync with android.media.AudioTimestamp
54    enum Timebase {
55        TIMEBASE_MONOTONIC,  // Clock monotonic offset (generally 0)
56        TIMEBASE_BOOTTIME,
57        TIMEBASE_MAX,
58    };
59
60    ExtendedTimestamp() {
61        clear();
62    }
63
64    // mPosition is expressed in frame units.
65    // It is generally nonnegative, though we keep this signed for
66    // to potentially express algorithmic latency at the start of the stream
67    // and to prevent unintentional unsigned integer underflow.
68    int64_t mPosition[LOCATION_MAX];
69
70    // mTimeNs is in nanoseconds for the default timebase, monotonic.
71    // If this value is -1, then both time and position are invalid.
72    // If this value is 0, then the time is not valid but the position is valid.
73    int64_t mTimeNs[LOCATION_MAX];
74
75    // mTimebaseOffset is the offset in ns from monotonic when the
76    // timestamp was taken.  This may vary due to suspend time
77    // or NTP adjustment.
78    int64_t mTimebaseOffset[TIMEBASE_MAX];
79
80    // Playback only:
81    // mFlushed is number of flushed frames before entering the server mix;
82    // hence not included in mPosition. This is used for adjusting server positions
83    // information for frames "dropped".
84    // FIXME: This variable should be eliminated, with the offset added on the server side
85    // before sending to client, but differences in legacy position offset handling
86    // and new extended timestamps require this to be maintained as a separate quantity.
87    int64_t mFlushed;
88
89    // Call to reset the timestamp to the original (invalid) state
90    void clear() {
91        memset(mPosition, 0, sizeof(mPosition)); // actually not necessary if time is -1
92        for (int i = 0; i < LOCATION_MAX; ++i) {
93            mTimeNs[i] = -1;
94        }
95        memset(mTimebaseOffset, 0, sizeof(mTimebaseOffset));
96        mFlushed = 0;
97    }
98
99    // Returns the best timestamp as judged from the closest-to-hw stage in the
100    // pipeline with a valid timestamp.  If the optional location parameter is non-null,
101    // it will be filled with the location where the time was obtained.
102    status_t getBestTimestamp(
103            int64_t *position, int64_t *time, int timebase, Location *location = nullptr) const {
104        if (position == nullptr || time == nullptr
105                || timebase < 0 || timebase >= TIMEBASE_MAX) {
106            return BAD_VALUE;
107        }
108        // look for the closest-to-hw stage in the pipeline with a valid timestamp.
109        // We omit LOCATION_CLIENT as we prefer at least LOCATION_SERVER based accuracy
110        // when getting the best timestamp.
111        for (int i = LOCATION_KERNEL; i >= LOCATION_SERVER; --i) {
112            if (mTimeNs[i] > 0) {
113                *position = mPosition[i];
114                *time = mTimeNs[i] + mTimebaseOffset[timebase];
115                if (location != nullptr) {
116                    *location = (Location)i;
117                }
118                return OK;
119            }
120        }
121        return INVALID_OPERATION;
122    }
123
124    status_t getBestTimestamp(AudioTimestamp *timestamp, Location *location = nullptr) const {
125        if (timestamp == nullptr) {
126            return BAD_VALUE;
127        }
128        int64_t position, time;
129        if (getBestTimestamp(&position, &time, TIMEBASE_MONOTONIC, location) == OK) {
130            timestamp->mPosition = position;
131            timestamp->mTime.tv_sec = time / 1000000000;
132            timestamp->mTime.tv_nsec = time - timestamp->mTime.tv_sec * 1000000000LL;
133            return OK;
134        }
135        return INVALID_OPERATION;
136    }
137
138    // convert fields to a printable string
139    std::string toString() {
140        std::stringstream ss;
141
142        ss << "BOOTTIME offset " << mTimebaseOffset[TIMEBASE_BOOTTIME] << "\n";
143        for (int i = 0; i < LOCATION_MAX; ++i) {
144            ss << "ExtendedTimestamp[" << i << "]  position: "
145                    << mPosition[i] << "  time: "  << mTimeNs[i] << "\n";
146        }
147        return ss.str();
148    }
149    // TODO:
150    // Consider adding buffer status:
151    // size, available, algorithmic latency
152};
153
154}   // namespace
155
156#endif  // ANDROID_AUDIO_TIMESTAMP_H
157