blob: 969003c17e1598f93bed9137cedd513df8fcdfc1 [file] [log] [blame]
Glenn Kastence703742013-07-19 16:33:58 -07001/*
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
Andy Hung3f0c9022016-01-15 17:49:46 -080020#include <string>
21#include <sstream>
Glenn Kastence703742013-07-19 16:33:58 -070022#include <time.h>
23
Glenn Kasten71de2f22013-09-23 14:30:36 -070024namespace android {
25
Glenn Kastence703742013-07-19 16:33:58 -070026class 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
Andy Hung3f0c9022016-01-15 17:49:46 -080037struct ExtendedTimestamp {
38 enum Location {
39 LOCATION_CLIENT, // timestamp of last read frame from client-server track buffer
40 LOCATION_SERVER, // timestamp of newest frame from client-server track buffer
41 LOCATION_KERNEL, // timestamp of newest frame in the kernel (alsa) buffer.
42 LOCATION_MAX // for sizing arrays only
43 };
44
45 // This needs to be kept in sync with android.media.AudioTimestamp
46 enum Timebase {
47 TIMEBASE_MONOTONIC, // Clock monotonic offset (generally 0)
48 TIMEBASE_BOOTTIME,
49 TIMEBASE_MAX,
50 };
51
52 ExtendedTimestamp() {
53 clear();
54 }
55
56 // mPosition is expressed in frame units.
57 // It is generally nonnegative, though we keep this signed for
58 // to potentially express algorithmic latency at the start of the stream
59 // and to prevent unintentional unsigned integer underflow.
60 int64_t mPosition[LOCATION_MAX];
61
62 // mTimeNs is in nanoseconds for the default timebase, monotonic.
63 // If this value is -1, then both time and position are invalid.
64 // If this value is 0, then the time is not valid but the position is valid.
65 int64_t mTimeNs[LOCATION_MAX];
66
67 // mTimebaseOffset is the offset in ns from monotonic when the
68 // timestamp was taken. This may vary due to suspend time
69 // or NTP adjustment.
70 int64_t mTimebaseOffset[TIMEBASE_MAX];
71
Andy Hungea2b9c02016-02-12 17:06:53 -080072 // Playback only:
73 // mFlushed is number of flushed frames before entering the server mix;
74 // hence not included in mPosition. This is used for adjusting server positions
75 // information for frames "dropped".
76 // FIXME: This variable should be eliminated, with the offset added on the server side
77 // before sending to client, but differences in legacy position offset handling
78 // and new extended timestamps require this to be maintained as a separate quantity.
79 int64_t mFlushed;
80
81 // Call to reset the timestamp to the original (invalid) state
Andy Hung3f0c9022016-01-15 17:49:46 -080082 void clear() {
83 memset(mPosition, 0, sizeof(mPosition)); // actually not necessary if time is -1
84 for (int i = 0; i < LOCATION_MAX; ++i) {
85 mTimeNs[i] = -1;
86 }
87 memset(mTimebaseOffset, 0, sizeof(mTimebaseOffset));
Andy Hungea2b9c02016-02-12 17:06:53 -080088 mFlushed = 0;
Andy Hung3f0c9022016-01-15 17:49:46 -080089 }
90
91 // Returns the best timestamp as judged from the closest-to-hw stage in the
92 // pipeline with a valid timestamp.
Andy Hung6ae58432016-02-16 18:32:24 -080093 status_t getBestTimestamp(int64_t *position, int64_t *time, int timebase) const {
Andy Hung3f0c9022016-01-15 17:49:46 -080094 if (position == nullptr || time == nullptr
95 || timebase < 0 || timebase >= TIMEBASE_MAX) {
96 return BAD_VALUE;
97 }
98 // look for the closest-to-hw stage in the pipeline with a valid timestamp.
99 // We omit LOCATION_CLIENT as we prefer at least LOCATION_SERVER based accuracy
100 // when getting the best timestamp.
101 for (int i = LOCATION_MAX - 1; i >= LOCATION_SERVER; --i) {
102 if (mTimeNs[i] > 0) {
103 *position = mPosition[i];
104 *time = mTimeNs[i] + mTimebaseOffset[timebase];
105 return OK;
106 }
107 }
108 return INVALID_OPERATION;
109 }
110
Andy Hung6ae58432016-02-16 18:32:24 -0800111 status_t getBestTimestamp(AudioTimestamp *timestamp) const {
112 if (timestamp == nullptr) {
113 return BAD_VALUE;
114 }
115 int64_t position, time;
116 if (getBestTimestamp(&position, &time, TIMEBASE_MONOTONIC) == OK) {
117 timestamp->mPosition = position;
118 timestamp->mTime.tv_sec = time / 1000000000;
119 timestamp->mTime.tv_nsec = time - timestamp->mTime.tv_sec * 1000000000LL;
120 return OK;
121 }
122 return INVALID_OPERATION;
123 }
124
Andy Hung3f0c9022016-01-15 17:49:46 -0800125 // convert fields to a printable string
126 std::string toString() {
127 std::stringstream ss;
128
129 ss << "BOOTTIME offset " << mTimebaseOffset[TIMEBASE_BOOTTIME] << "\n";
130 for (int i = 0; i < LOCATION_MAX; ++i) {
131 ss << "ExtendedTimestamp[" << i << "] position: "
132 << mPosition[i] << " time: " << mTimeNs[i] << "\n";
133 }
134 return ss.str();
135 }
136 // TODO:
137 // Consider adding buffer status:
138 // size, available, algorithmic latency
139};
140
Glenn Kasten71de2f22013-09-23 14:30:36 -0700141} // namespace
142
Glenn Kastence703742013-07-19 16:33:58 -0700143#endif // ANDROID_AUDIO_TIMESTAMP_H