blob: 498de8e071268e0d709fdef801839b918f354f4a [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
Di Folco, Neil10b3d7e2016-06-02 20:24:54 +020037struct alignas(8) /* bug 29096183, bug 29108507 */ ExtendedTimestamp {
Andy Hung3f0c9022016-01-15 17:49:46 -080038 enum Location {
Andy Hungb01faa32016-04-27 12:51:32 -070039 LOCATION_INVALID = -1,
Andy Hung6d7b1192016-05-07 22:59:48 -070040 // 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.
Andy Hung3f0c9022016-01-15 17:49:46 -080043 LOCATION_KERNEL, // timestamp of newest frame in the kernel (alsa) buffer.
Andy Hung6d7b1192016-05-07 22:59:48 -070044
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.
Andy Hung3f0c9022016-01-15 17:49:46 -080050 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
Andy Hungea2b9c02016-02-12 17:06:53 -080080 // 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
Andy Hung3f0c9022016-01-15 17:49:46 -080090 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));
Andy Hungea2b9c02016-02-12 17:06:53 -080096 mFlushed = 0;
Andy Hung3f0c9022016-01-15 17:49:46 -080097 }
98
99 // Returns the best timestamp as judged from the closest-to-hw stage in the
Andy Hungb01faa32016-04-27 12:51:32 -0700100 // 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 {
Andy Hung3f0c9022016-01-15 17:49:46 -0800104 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.
Andy Hung6d7b1192016-05-07 22:59:48 -0700111 for (int i = LOCATION_KERNEL; i >= LOCATION_SERVER; --i) {
Andy Hung3f0c9022016-01-15 17:49:46 -0800112 if (mTimeNs[i] > 0) {
113 *position = mPosition[i];
114 *time = mTimeNs[i] + mTimebaseOffset[timebase];
Andy Hungb01faa32016-04-27 12:51:32 -0700115 if (location != nullptr) {
116 *location = (Location)i;
117 }
Andy Hung3f0c9022016-01-15 17:49:46 -0800118 return OK;
119 }
120 }
121 return INVALID_OPERATION;
122 }
123
Andy Hungb01faa32016-04-27 12:51:32 -0700124 status_t getBestTimestamp(AudioTimestamp *timestamp, Location *location = nullptr) const {
Andy Hung6ae58432016-02-16 18:32:24 -0800125 if (timestamp == nullptr) {
126 return BAD_VALUE;
127 }
128 int64_t position, time;
Andy Hungb01faa32016-04-27 12:51:32 -0700129 if (getBestTimestamp(&position, &time, TIMEBASE_MONOTONIC, location) == OK) {
Andy Hung6ae58432016-02-16 18:32:24 -0800130 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
Andy Hung3f0c9022016-01-15 17:49:46 -0800138 // 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
Glenn Kasten71de2f22013-09-23 14:30:36 -0700154} // namespace
155
Glenn Kastence703742013-07-19 16:33:58 -0700156#endif // ANDROID_AUDIO_TIMESTAMP_H