blob: 1d15495063dbf8ed9a7e063168f61a6ed929f676 [file] [log] [blame]
Glenn Kastena8190fc2012-12-03 17:06:56 -08001/*
2 * Copyright (C) 2007 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#define LOG_TAG "AudioTrackShared"
18//#define LOG_NDEBUG 0
19
20#include <private/media/AudioTrackShared.h>
21#include <utils/Log.h>
Elliott Hughesee499292014-05-21 17:55:51 -070022
23#include <linux/futex.h>
24#include <sys/syscall.h>
Glenn Kastena8190fc2012-12-03 17:06:56 -080025
26namespace android {
27
Andy Hungcb2129b2014-11-11 12:17:22 -080028// used to clamp a value to size_t. TODO: move to another file.
29template <typename T>
30size_t clampToSize(T x) {
Andy Hung486a7132014-12-22 16:54:21 -080031 return sizeof(T) > sizeof(size_t) && x > (T) SIZE_MAX ? SIZE_MAX : x < 0 ? 0 : (size_t) x;
Andy Hungcb2129b2014-11-11 12:17:22 -080032}
33
Andy Hung9b461582014-12-01 17:56:29 -080034// incrementSequence is used to determine the next sequence value
35// for the loop and position sequence counters. It should return
36// a value between "other" + 1 and "other" + INT32_MAX, the choice of
37// which needs to be the "least recently used" sequence value for "self".
38// In general, this means (new_self) returned is max(self, other) + 1.
39
40static uint32_t incrementSequence(uint32_t self, uint32_t other) {
Chad Brubakercb50c542015-10-07 14:20:10 -070041 int32_t diff = (int32_t) self - (int32_t) other;
Andy Hung9b461582014-12-01 17:56:29 -080042 if (diff >= 0 && diff < INT32_MAX) {
43 return self + 1; // we're already ahead of other.
44 }
45 return other + 1; // we're behind, so move just ahead of other.
46}
47
Glenn Kastena8190fc2012-12-03 17:06:56 -080048audio_track_cblk_t::audio_track_cblk_t()
Glenn Kasten74935e42013-12-19 08:56:45 -080049 : mServer(0), mFutex(0), mMinimum(0),
Glenn Kastenc56f3422014-03-21 17:53:17 -070050 mVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY), mSampleRate(0), mSendLevel(0), mFlags(0)
Glenn Kasten9f80dd22012-12-18 15:57:32 -080051{
52 memset(&u, 0, sizeof(u));
53}
54
55// ---------------------------------------------------------------------------
56
57Proxy::Proxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize,
58 bool isOut, bool clientInServer)
59 : mCblk(cblk), mBuffers(buffers), mFrameCount(frameCount), mFrameSize(frameSize),
60 mFrameCountP2(roundup(frameCount)), mIsOut(isOut), mClientInServer(clientInServer),
Glenn Kasten7db7df02013-06-25 16:13:23 -070061 mIsShutdown(false), mUnreleased(0)
Glenn Kastena8190fc2012-12-03 17:06:56 -080062{
63}
64
Glenn Kasten9f80dd22012-12-18 15:57:32 -080065// ---------------------------------------------------------------------------
66
67ClientProxy::ClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
68 size_t frameSize, bool isOut, bool clientInServer)
Phil Burkc0adecb2016-01-08 12:44:11 -080069 : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer)
70 , mBufferSizeInFrames(frameCount)
71 , mEpoch(0)
Andy Hung6ae58432016-02-16 18:32:24 -080072 , mTimestampObserver(&cblk->mExtendedTimestampQueue)
Glenn Kastena8190fc2012-12-03 17:06:56 -080073{
Glenn Kastena8190fc2012-12-03 17:06:56 -080074}
75
Glenn Kasten9f80dd22012-12-18 15:57:32 -080076const struct timespec ClientProxy::kForever = {INT_MAX /*tv_sec*/, 0 /*tv_nsec*/};
77const struct timespec ClientProxy::kNonBlocking = {0 /*tv_sec*/, 0 /*tv_nsec*/};
78
79#define MEASURE_NS 10000000 // attempt to provide accurate timeouts if requested >= MEASURE_NS
80
81// To facilitate quicker recovery from server failure, this value limits the timeout per each futex
82// wait. However it does not protect infinite timeouts. If defined to be zero, there is no limit.
83// FIXME May not be compatible with audio tunneling requirements where timeout should be in the
84// order of minutes.
85#define MAX_SEC 5
86
87status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *requested,
88 struct timespec *elapsed)
Glenn Kastena8190fc2012-12-03 17:06:56 -080089{
Glenn Kasten7db7df02013-06-25 16:13:23 -070090 LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0);
Glenn Kasten9f80dd22012-12-18 15:57:32 -080091 struct timespec total; // total elapsed time spent waiting
92 total.tv_sec = 0;
93 total.tv_nsec = 0;
94 bool measure = elapsed != NULL; // whether to measure total elapsed time spent waiting
Glenn Kastena8190fc2012-12-03 17:06:56 -080095
Glenn Kasten9f80dd22012-12-18 15:57:32 -080096 status_t status;
97 enum {
98 TIMEOUT_ZERO, // requested == NULL || *requested == 0
99 TIMEOUT_INFINITE, // *requested == infinity
100 TIMEOUT_FINITE, // 0 < *requested < infinity
101 TIMEOUT_CONTINUE, // additional chances after TIMEOUT_FINITE
102 } timeout;
103 if (requested == NULL) {
104 timeout = TIMEOUT_ZERO;
105 } else if (requested->tv_sec == 0 && requested->tv_nsec == 0) {
106 timeout = TIMEOUT_ZERO;
107 } else if (requested->tv_sec == INT_MAX) {
108 timeout = TIMEOUT_INFINITE;
Glenn Kastena8190fc2012-12-03 17:06:56 -0800109 } else {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800110 timeout = TIMEOUT_FINITE;
111 if (requested->tv_sec > 0 || requested->tv_nsec >= MEASURE_NS) {
112 measure = true;
113 }
Glenn Kastena8190fc2012-12-03 17:06:56 -0800114 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800115 struct timespec before;
116 bool beforeIsValid = false;
117 audio_track_cblk_t* cblk = mCblk;
118 bool ignoreInitialPendingInterrupt = true;
119 // check for shared memory corruption
120 if (mIsShutdown) {
121 status = NO_INIT;
122 goto end;
123 }
124 for (;;) {
Glenn Kasten96f60d82013-07-12 10:21:18 -0700125 int32_t flags = android_atomic_and(~CBLK_INTERRUPT, &cblk->mFlags);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800126 // check for track invalidation by server, or server death detection
127 if (flags & CBLK_INVALID) {
128 ALOGV("Track invalidated");
129 status = DEAD_OBJECT;
130 goto end;
131 }
132 // check for obtainBuffer interrupted by client
133 if (!ignoreInitialPendingInterrupt && (flags & CBLK_INTERRUPT)) {
134 ALOGV("obtainBuffer() interrupted by client");
135 status = -EINTR;
136 goto end;
137 }
138 ignoreInitialPendingInterrupt = false;
139 // compute number of frames available to write (AudioTrack) or read (AudioRecord)
140 int32_t front;
141 int32_t rear;
142 if (mIsOut) {
143 // The barrier following the read of mFront is probably redundant.
144 // We're about to perform a conditional branch based on 'filled',
145 // which will force the processor to observe the read of mFront
146 // prior to allowing data writes starting at mRaw.
147 // However, the processor may support speculative execution,
148 // and be unable to undo speculative writes into shared memory.
149 // The barrier will prevent such speculative execution.
150 front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
151 rear = cblk->u.mStreaming.mRear;
Glenn Kastena8190fc2012-12-03 17:06:56 -0800152 } else {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800153 // On the other hand, this barrier is required.
154 rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
155 front = cblk->u.mStreaming.mFront;
156 }
Phil Burkc0adecb2016-01-08 12:44:11 -0800157 // write to rear, read from front
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800158 ssize_t filled = rear - front;
159 // pipe should not be overfull
160 if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
Glenn Kasten6dbb5e32014-05-13 10:38:42 -0700161 if (mIsOut) {
Mark Salyzyn34fb2962014-06-18 16:30:56 -0700162 ALOGE("Shared memory control block is corrupt (filled=%zd, mFrameCount=%zu); "
Glenn Kasten6dbb5e32014-05-13 10:38:42 -0700163 "shutting down", filled, mFrameCount);
164 mIsShutdown = true;
165 status = NO_INIT;
166 goto end;
167 }
168 // for input, sync up on overrun
169 filled = 0;
170 cblk->u.mStreaming.mFront = rear;
171 (void) android_atomic_or(CBLK_OVERRUN, &cblk->mFlags);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800172 }
Phil Burkc0adecb2016-01-08 12:44:11 -0800173 // Don't allow filling pipe beyond the user settable size.
174 // The calculation for avail can go negative if the buffer size
175 // is suddenly dropped below the amount already in the buffer.
176 // So use a signed calculation to prevent a numeric overflow abort.
177 ssize_t adjustableSize = (ssize_t) mBufferSizeInFrames;
178 ssize_t avail = (mIsOut) ? adjustableSize - filled : filled;
179 if (avail < 0) {
180 avail = 0;
181 } else if (avail > 0) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800182 // 'avail' may be non-contiguous, so return only the first contiguous chunk
Eric Laurentbdd81012016-01-29 15:25:06 -0800183 size_t part1;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800184 if (mIsOut) {
185 rear &= mFrameCountP2 - 1;
186 part1 = mFrameCountP2 - rear;
187 } else {
188 front &= mFrameCountP2 - 1;
189 part1 = mFrameCountP2 - front;
Glenn Kastena8190fc2012-12-03 17:06:56 -0800190 }
Eric Laurentbdd81012016-01-29 15:25:06 -0800191 if (part1 > (size_t)avail) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800192 part1 = avail;
Glenn Kastena8190fc2012-12-03 17:06:56 -0800193 }
Eric Laurentbdd81012016-01-29 15:25:06 -0800194 if (part1 > buffer->mFrameCount) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800195 part1 = buffer->mFrameCount;
196 }
Eric Laurentbdd81012016-01-29 15:25:06 -0800197 buffer->mFrameCount = part1;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800198 buffer->mRaw = part1 > 0 ?
199 &((char *) mBuffers)[(mIsOut ? rear : front) * mFrameSize] : NULL;
200 buffer->mNonContig = avail - part1;
Glenn Kasten7db7df02013-06-25 16:13:23 -0700201 mUnreleased = part1;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800202 status = NO_ERROR;
203 break;
204 }
205 struct timespec remaining;
206 const struct timespec *ts;
207 switch (timeout) {
208 case TIMEOUT_ZERO:
209 status = WOULD_BLOCK;
210 goto end;
211 case TIMEOUT_INFINITE:
212 ts = NULL;
213 break;
214 case TIMEOUT_FINITE:
215 timeout = TIMEOUT_CONTINUE;
216 if (MAX_SEC == 0) {
217 ts = requested;
218 break;
219 }
220 // fall through
221 case TIMEOUT_CONTINUE:
222 // FIXME we do not retry if requested < 10ms? needs documentation on this state machine
223 if (!measure || requested->tv_sec < total.tv_sec ||
224 (requested->tv_sec == total.tv_sec && requested->tv_nsec <= total.tv_nsec)) {
225 status = TIMED_OUT;
226 goto end;
227 }
228 remaining.tv_sec = requested->tv_sec - total.tv_sec;
229 if ((remaining.tv_nsec = requested->tv_nsec - total.tv_nsec) < 0) {
230 remaining.tv_nsec += 1000000000;
231 remaining.tv_sec++;
232 }
233 if (0 < MAX_SEC && MAX_SEC < remaining.tv_sec) {
234 remaining.tv_sec = MAX_SEC;
235 remaining.tv_nsec = 0;
236 }
237 ts = &remaining;
238 break;
239 default:
Glenn Kastenadad3d72014-02-21 14:51:43 -0800240 LOG_ALWAYS_FATAL("obtainBuffer() timeout=%d", timeout);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800241 ts = NULL;
242 break;
243 }
Glenn Kasten0d09a9b2013-06-24 12:06:46 -0700244 int32_t old = android_atomic_and(~CBLK_FUTEX_WAKE, &cblk->mFutex);
245 if (!(old & CBLK_FUTEX_WAKE)) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800246 if (measure && !beforeIsValid) {
247 clock_gettime(CLOCK_MONOTONIC, &before);
248 beforeIsValid = true;
249 }
Elliott Hughesee499292014-05-21 17:55:51 -0700250 errno = 0;
251 (void) syscall(__NR_futex, &cblk->mFutex,
Glenn Kasten0d09a9b2013-06-24 12:06:46 -0700252 mClientInServer ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT, old & ~CBLK_FUTEX_WAKE, ts);
Leena Winterrowdb463da82015-12-14 15:58:16 -0800253 status_t error = errno; // clock_gettime can affect errno
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800254 // update total elapsed time spent waiting
255 if (measure) {
256 struct timespec after;
257 clock_gettime(CLOCK_MONOTONIC, &after);
258 total.tv_sec += after.tv_sec - before.tv_sec;
259 long deltaNs = after.tv_nsec - before.tv_nsec;
260 if (deltaNs < 0) {
261 deltaNs += 1000000000;
262 total.tv_sec--;
263 }
264 if ((total.tv_nsec += deltaNs) >= 1000000000) {
265 total.tv_nsec -= 1000000000;
266 total.tv_sec++;
267 }
268 before = after;
269 beforeIsValid = true;
270 }
Leena Winterrowdb463da82015-12-14 15:58:16 -0800271 switch (error) {
Elliott Hughesee499292014-05-21 17:55:51 -0700272 case 0: // normal wakeup by server, or by binderDied()
273 case EWOULDBLOCK: // benign race condition with server
274 case EINTR: // wait was interrupted by signal or other spurious wakeup
275 case ETIMEDOUT: // time-out expired
Glenn Kasten7db7df02013-06-25 16:13:23 -0700276 // FIXME these error/non-0 status are being dropped
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800277 break;
278 default:
Leena Winterrowdb463da82015-12-14 15:58:16 -0800279 status = error;
Elliott Hughesee499292014-05-21 17:55:51 -0700280 ALOGE("%s unexpected error %s", __func__, strerror(status));
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800281 goto end;
282 }
283 }
284 }
285
286end:
287 if (status != NO_ERROR) {
288 buffer->mFrameCount = 0;
289 buffer->mRaw = NULL;
290 buffer->mNonContig = 0;
Glenn Kasten7db7df02013-06-25 16:13:23 -0700291 mUnreleased = 0;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800292 }
293 if (elapsed != NULL) {
294 *elapsed = total;
295 }
296 if (requested == NULL) {
297 requested = &kNonBlocking;
298 }
299 if (measure) {
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100300 ALOGV("requested %ld.%03ld elapsed %ld.%03ld",
301 requested->tv_sec, requested->tv_nsec / 1000000,
302 total.tv_sec, total.tv_nsec / 1000000);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800303 }
304 return status;
305}
306
307void ClientProxy::releaseBuffer(Buffer* buffer)
308{
Glenn Kasten7db7df02013-06-25 16:13:23 -0700309 LOG_ALWAYS_FATAL_IF(buffer == NULL);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800310 size_t stepCount = buffer->mFrameCount;
Glenn Kasten7db7df02013-06-25 16:13:23 -0700311 if (stepCount == 0 || mIsShutdown) {
312 // prevent accidental re-use of buffer
313 buffer->mFrameCount = 0;
314 buffer->mRaw = NULL;
315 buffer->mNonContig = 0;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800316 return;
317 }
Glenn Kasten7db7df02013-06-25 16:13:23 -0700318 LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased && mUnreleased <= mFrameCount));
319 mUnreleased -= stepCount;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800320 audio_track_cblk_t* cblk = mCblk;
321 // Both of these barriers are required
322 if (mIsOut) {
323 int32_t rear = cblk->u.mStreaming.mRear;
324 android_atomic_release_store(stepCount + rear, &cblk->u.mStreaming.mRear);
325 } else {
326 int32_t front = cblk->u.mStreaming.mFront;
327 android_atomic_release_store(stepCount + front, &cblk->u.mStreaming.mFront);
328 }
329}
330
331void ClientProxy::binderDied()
332{
333 audio_track_cblk_t* cblk = mCblk;
Glenn Kasten96f60d82013-07-12 10:21:18 -0700334 if (!(android_atomic_or(CBLK_INVALID, &cblk->mFlags) & CBLK_INVALID)) {
zunkyu.lee82a69ea2014-11-07 15:47:32 +0900335 android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800336 // it seems that a FUTEX_WAKE_PRIVATE will not wake a FUTEX_WAIT, even within same process
Elliott Hughesee499292014-05-21 17:55:51 -0700337 (void) syscall(__NR_futex, &cblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
338 1);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800339 }
340}
341
342void ClientProxy::interrupt()
343{
344 audio_track_cblk_t* cblk = mCblk;
Glenn Kasten96f60d82013-07-12 10:21:18 -0700345 if (!(android_atomic_or(CBLK_INTERRUPT, &cblk->mFlags) & CBLK_INTERRUPT)) {
zunkyu.lee82a69ea2014-11-07 15:47:32 +0900346 android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
Elliott Hughesee499292014-05-21 17:55:51 -0700347 (void) syscall(__NR_futex, &cblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
348 1);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800349 }
350}
351
Chad Brubaker65dda4f2015-09-22 16:13:30 -0700352__attribute__((no_sanitize("integer")))
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800353size_t ClientProxy::getMisalignment()
354{
355 audio_track_cblk_t* cblk = mCblk;
356 return (mFrameCountP2 - (mIsOut ? cblk->u.mStreaming.mRear : cblk->u.mStreaming.mFront)) &
357 (mFrameCountP2 - 1);
358}
359
Phil Burkc0adecb2016-01-08 12:44:11 -0800360size_t ClientProxy::setBufferSizeInFrames(size_t size)
361{
362 // TODO set minimum to 2X the fast mixer buffer size.
363 size_t minimum = 128 * 2; // arbitrary
364 size_t maximum = frameCount();
365 if (size < minimum) {
366 size = minimum;
367 } else if (size > maximum) {
368 size = maximum;
369 }
370 mBufferSizeInFrames = size;
371 return size;
372}
373
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800374// ---------------------------------------------------------------------------
375
376void AudioTrackClientProxy::flush()
377{
Glenn Kasten20f51b12014-10-30 10:43:19 -0700378 // This works for mFrameCountP2 <= 2^30
379 size_t increment = mFrameCountP2 << 1;
380 size_t mask = increment - 1;
381 audio_track_cblk_t* cblk = mCblk;
Andy Hunga2d75cd2015-07-15 17:04:20 -0700382 // mFlush is 32 bits concatenated as [ flush_counter ] [ newfront_offset ]
383 // Should newFlush = cblk->u.mStreaming.mRear? Only problem is
384 // if you want to flush twice to the same rear location after a 32 bit wrap.
Glenn Kasten20f51b12014-10-30 10:43:19 -0700385 int32_t newFlush = (cblk->u.mStreaming.mRear & mask) |
386 ((cblk->u.mStreaming.mFlush & ~mask) + increment);
387 android_atomic_release_store(newFlush, &cblk->u.mStreaming.mFlush);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800388}
389
Eric Laurentbfb1b832013-01-07 09:53:42 -0800390bool AudioTrackClientProxy::clearStreamEndDone() {
Glenn Kasten96f60d82013-07-12 10:21:18 -0700391 return (android_atomic_and(~CBLK_STREAM_END_DONE, &mCblk->mFlags) & CBLK_STREAM_END_DONE) != 0;
Eric Laurentbfb1b832013-01-07 09:53:42 -0800392}
393
394bool AudioTrackClientProxy::getStreamEndDone() const {
Glenn Kasten96f60d82013-07-12 10:21:18 -0700395 return (mCblk->mFlags & CBLK_STREAM_END_DONE) != 0;
Eric Laurentbfb1b832013-01-07 09:53:42 -0800396}
397
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100398status_t AudioTrackClientProxy::waitStreamEndDone(const struct timespec *requested)
399{
400 struct timespec total; // total elapsed time spent waiting
401 total.tv_sec = 0;
402 total.tv_nsec = 0;
403 audio_track_cblk_t* cblk = mCblk;
404 status_t status;
405 enum {
406 TIMEOUT_ZERO, // requested == NULL || *requested == 0
407 TIMEOUT_INFINITE, // *requested == infinity
408 TIMEOUT_FINITE, // 0 < *requested < infinity
409 TIMEOUT_CONTINUE, // additional chances after TIMEOUT_FINITE
410 } timeout;
411 if (requested == NULL) {
412 timeout = TIMEOUT_ZERO;
413 } else if (requested->tv_sec == 0 && requested->tv_nsec == 0) {
414 timeout = TIMEOUT_ZERO;
415 } else if (requested->tv_sec == INT_MAX) {
416 timeout = TIMEOUT_INFINITE;
417 } else {
418 timeout = TIMEOUT_FINITE;
419 }
420 for (;;) {
Glenn Kasten96f60d82013-07-12 10:21:18 -0700421 int32_t flags = android_atomic_and(~(CBLK_INTERRUPT|CBLK_STREAM_END_DONE), &cblk->mFlags);
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100422 // check for track invalidation by server, or server death detection
423 if (flags & CBLK_INVALID) {
424 ALOGV("Track invalidated");
425 status = DEAD_OBJECT;
426 goto end;
427 }
428 if (flags & CBLK_STREAM_END_DONE) {
429 ALOGV("stream end received");
430 status = NO_ERROR;
431 goto end;
432 }
433 // check for obtainBuffer interrupted by client
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100434 if (flags & CBLK_INTERRUPT) {
435 ALOGV("waitStreamEndDone() interrupted by client");
436 status = -EINTR;
437 goto end;
438 }
439 struct timespec remaining;
440 const struct timespec *ts;
441 switch (timeout) {
442 case TIMEOUT_ZERO:
443 status = WOULD_BLOCK;
444 goto end;
445 case TIMEOUT_INFINITE:
446 ts = NULL;
447 break;
448 case TIMEOUT_FINITE:
449 timeout = TIMEOUT_CONTINUE;
450 if (MAX_SEC == 0) {
451 ts = requested;
452 break;
453 }
454 // fall through
455 case TIMEOUT_CONTINUE:
456 // FIXME we do not retry if requested < 10ms? needs documentation on this state machine
457 if (requested->tv_sec < total.tv_sec ||
458 (requested->tv_sec == total.tv_sec && requested->tv_nsec <= total.tv_nsec)) {
459 status = TIMED_OUT;
460 goto end;
461 }
462 remaining.tv_sec = requested->tv_sec - total.tv_sec;
463 if ((remaining.tv_nsec = requested->tv_nsec - total.tv_nsec) < 0) {
464 remaining.tv_nsec += 1000000000;
465 remaining.tv_sec++;
466 }
467 if (0 < MAX_SEC && MAX_SEC < remaining.tv_sec) {
468 remaining.tv_sec = MAX_SEC;
469 remaining.tv_nsec = 0;
470 }
471 ts = &remaining;
472 break;
473 default:
Glenn Kastenadad3d72014-02-21 14:51:43 -0800474 LOG_ALWAYS_FATAL("waitStreamEndDone() timeout=%d", timeout);
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100475 ts = NULL;
476 break;
477 }
478 int32_t old = android_atomic_and(~CBLK_FUTEX_WAKE, &cblk->mFutex);
479 if (!(old & CBLK_FUTEX_WAKE)) {
Elliott Hughesee499292014-05-21 17:55:51 -0700480 errno = 0;
481 (void) syscall(__NR_futex, &cblk->mFutex,
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100482 mClientInServer ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT, old & ~CBLK_FUTEX_WAKE, ts);
Elliott Hughesee499292014-05-21 17:55:51 -0700483 switch (errno) {
484 case 0: // normal wakeup by server, or by binderDied()
485 case EWOULDBLOCK: // benign race condition with server
486 case EINTR: // wait was interrupted by signal or other spurious wakeup
487 case ETIMEDOUT: // time-out expired
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100488 break;
489 default:
Elliott Hughesee499292014-05-21 17:55:51 -0700490 status = errno;
491 ALOGE("%s unexpected error %s", __func__, strerror(status));
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100492 goto end;
493 }
494 }
495 }
496
497end:
498 if (requested == NULL) {
499 requested = &kNonBlocking;
500 }
501 return status;
502}
503
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800504// ---------------------------------------------------------------------------
505
506StaticAudioTrackClientProxy::StaticAudioTrackClientProxy(audio_track_cblk_t* cblk, void *buffers,
507 size_t frameCount, size_t frameSize)
508 : AudioTrackClientProxy(cblk, buffers, frameCount, frameSize),
Andy Hung4ede21d2014-12-12 15:37:34 -0800509 mMutator(&cblk->u.mStatic.mSingleStateQueue),
510 mPosLoopObserver(&cblk->u.mStatic.mPosLoopQueue)
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800511{
Andy Hung9b461582014-12-01 17:56:29 -0800512 memset(&mState, 0, sizeof(mState));
Andy Hung4ede21d2014-12-12 15:37:34 -0800513 memset(&mPosLoop, 0, sizeof(mPosLoop));
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800514}
515
516void StaticAudioTrackClientProxy::flush()
517{
Glenn Kastenadad3d72014-02-21 14:51:43 -0800518 LOG_ALWAYS_FATAL("static flush");
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800519}
520
521void StaticAudioTrackClientProxy::setLoop(size_t loopStart, size_t loopEnd, int loopCount)
522{
Glenn Kastenfdac7c02014-01-28 11:03:28 -0800523 // This can only happen on a 64-bit client
524 if (loopStart > UINT32_MAX || loopEnd > UINT32_MAX) {
525 // FIXME Should return an error status
526 return;
527 }
Andy Hung9b461582014-12-01 17:56:29 -0800528 mState.mLoopStart = (uint32_t) loopStart;
529 mState.mLoopEnd = (uint32_t) loopEnd;
530 mState.mLoopCount = loopCount;
531 mState.mLoopSequence = incrementSequence(mState.mLoopSequence, mState.mPositionSequence);
532 // set patch-up variables until the mState is acknowledged by the ServerProxy.
533 // observed buffer position and loop count will freeze until then to give the
534 // illusion of a synchronous change.
Andy Hung4ede21d2014-12-12 15:37:34 -0800535 getBufferPositionAndLoopCount(NULL, NULL);
Andy Hung9b461582014-12-01 17:56:29 -0800536 // preserve behavior to restart at mState.mLoopStart if position exceeds mState.mLoopEnd.
Andy Hung4ede21d2014-12-12 15:37:34 -0800537 if (mState.mLoopCount != 0 && mPosLoop.mBufferPosition >= mState.mLoopEnd) {
538 mPosLoop.mBufferPosition = mState.mLoopStart;
Andy Hung680b7952014-11-12 13:18:52 -0800539 }
Andy Hung4ede21d2014-12-12 15:37:34 -0800540 mPosLoop.mLoopCount = mState.mLoopCount;
Andy Hung9b461582014-12-01 17:56:29 -0800541 (void) mMutator.push(mState);
542}
543
544void StaticAudioTrackClientProxy::setBufferPosition(size_t position)
545{
546 // This can only happen on a 64-bit client
547 if (position > UINT32_MAX) {
548 // FIXME Should return an error status
549 return;
550 }
551 mState.mPosition = (uint32_t) position;
552 mState.mPositionSequence = incrementSequence(mState.mPositionSequence, mState.mLoopSequence);
Andy Hung4ede21d2014-12-12 15:37:34 -0800553 // set patch-up variables until the mState is acknowledged by the ServerProxy.
554 // observed buffer position and loop count will freeze until then to give the
555 // illusion of a synchronous change.
556 if (mState.mLoopCount > 0) { // only check if loop count is changing
557 getBufferPositionAndLoopCount(NULL, NULL); // get last position
558 }
559 mPosLoop.mBufferPosition = position;
560 if (position >= mState.mLoopEnd) {
561 // no ongoing loop is possible if position is greater than loopEnd.
562 mPosLoop.mLoopCount = 0;
563 }
Andy Hung9b461582014-12-01 17:56:29 -0800564 (void) mMutator.push(mState);
565}
566
567void StaticAudioTrackClientProxy::setBufferPositionAndLoop(size_t position, size_t loopStart,
568 size_t loopEnd, int loopCount)
569{
570 setLoop(loopStart, loopEnd, loopCount);
571 setBufferPosition(position);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800572}
573
574size_t StaticAudioTrackClientProxy::getBufferPosition()
575{
Andy Hung4ede21d2014-12-12 15:37:34 -0800576 getBufferPositionAndLoopCount(NULL, NULL);
577 return mPosLoop.mBufferPosition;
578}
579
580void StaticAudioTrackClientProxy::getBufferPositionAndLoopCount(
581 size_t *position, int *loopCount)
582{
583 if (mMutator.ack() == StaticAudioTrackSingleStateQueue::SSQ_DONE) {
584 if (mPosLoopObserver.poll(mPosLoop)) {
585 ; // a valid mPosLoop should be available if ackDone is true.
586 }
Glenn Kastena8190fc2012-12-03 17:06:56 -0800587 }
Andy Hung4ede21d2014-12-12 15:37:34 -0800588 if (position != NULL) {
589 *position = mPosLoop.mBufferPosition;
590 }
591 if (loopCount != NULL) {
592 *loopCount = mPosLoop.mLoopCount;
593 }
Glenn Kastena8190fc2012-12-03 17:06:56 -0800594}
595
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800596// ---------------------------------------------------------------------------
597
598ServerProxy::ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
599 size_t frameSize, bool isOut, bool clientInServer)
Glenn Kasten7db7df02013-06-25 16:13:23 -0700600 : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer),
Andy Hung3f0c9022016-01-15 17:49:46 -0800601 mAvailToClient(0), mFlush(0), mReleased(0)
Andy Hung6ae58432016-02-16 18:32:24 -0800602 , mTimestampMutator(&cblk->mExtendedTimestampQueue)
Glenn Kastena8190fc2012-12-03 17:06:56 -0800603{
Glenn Kastena8190fc2012-12-03 17:06:56 -0800604}
605
Glenn Kasten2e422c42013-10-18 13:00:29 -0700606status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800607{
Glenn Kasten7db7df02013-06-25 16:13:23 -0700608 LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800609 if (mIsShutdown) {
Glenn Kasten7db7df02013-06-25 16:13:23 -0700610 goto no_init;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800611 }
Glenn Kasten7db7df02013-06-25 16:13:23 -0700612 {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800613 audio_track_cblk_t* cblk = mCblk;
614 // compute number of frames available to write (AudioTrack) or read (AudioRecord),
615 // or use previous cached value from framesReady(), with added barrier if it omits.
616 int32_t front;
617 int32_t rear;
618 // See notes on barriers at ClientProxy::obtainBuffer()
619 if (mIsOut) {
620 int32_t flush = cblk->u.mStreaming.mFlush;
621 rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100622 front = cblk->u.mStreaming.mFront;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800623 if (flush != mFlush) {
Glenn Kasten050501d2013-07-11 10:35:38 -0700624 // effectively obtain then release whatever is in the buffer
Andy Hunga2d75cd2015-07-15 17:04:20 -0700625 const size_t overflowBit = mFrameCountP2 << 1;
626 const size_t mask = overflowBit - 1;
Glenn Kasten20f51b12014-10-30 10:43:19 -0700627 int32_t newFront = (front & ~mask) | (flush & mask);
628 ssize_t filled = rear - newFront;
Andy Hunga2d75cd2015-07-15 17:04:20 -0700629 if (filled >= (ssize_t)overflowBit) {
630 // front and rear offsets span the overflow bit of the p2 mask
631 // so rebasing newFront on the front offset is off by the overflow bit.
632 // adjust newFront to match rear offset.
Glenn Kastendbd0f3c2015-07-17 11:04:04 -0700633 ALOGV("flush wrap: filled %zx >= overflowBit %zx", filled, overflowBit);
Andy Hunga2d75cd2015-07-15 17:04:20 -0700634 newFront += overflowBit;
635 filled -= overflowBit;
636 }
Glenn Kasten20f51b12014-10-30 10:43:19 -0700637 // Rather than shutting down on a corrupt flush, just treat it as a full flush
638 if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
Glenn Kastenb187de12014-12-30 08:18:15 -0800639 ALOGE("mFlush %#x -> %#x, front %#x, rear %#x, mask %#x, newFront %#x, "
Lajos Molnarf1063e22015-04-17 15:19:42 -0700640 "filled %zd=%#x",
641 mFlush, flush, front, rear,
642 (unsigned)mask, newFront, filled, (unsigned)filled);
Glenn Kasten20f51b12014-10-30 10:43:19 -0700643 newFront = rear;
644 }
645 mFlush = flush;
646 android_atomic_release_store(newFront, &cblk->u.mStreaming.mFront);
647 // There is no danger from a false positive, so err on the side of caution
648 if (true /*front != newFront*/) {
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100649 int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
650 if (!(old & CBLK_FUTEX_WAKE)) {
Elliott Hughesee499292014-05-21 17:55:51 -0700651 (void) syscall(__NR_futex, &cblk->mFutex,
652 mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100653 }
654 }
Glenn Kasten20f51b12014-10-30 10:43:19 -0700655 front = newFront;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800656 }
657 } else {
658 front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
659 rear = cblk->u.mStreaming.mRear;
660 }
661 ssize_t filled = rear - front;
662 // pipe should not already be overfull
663 if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
Mark Salyzyn34fb2962014-06-18 16:30:56 -0700664 ALOGE("Shared memory control block is corrupt (filled=%zd); shutting down", filled);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800665 mIsShutdown = true;
666 }
667 if (mIsShutdown) {
Glenn Kasten7db7df02013-06-25 16:13:23 -0700668 goto no_init;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800669 }
670 // don't allow filling pipe beyond the nominal size
671 size_t availToServer;
672 if (mIsOut) {
673 availToServer = filled;
674 mAvailToClient = mFrameCount - filled;
675 } else {
676 availToServer = mFrameCount - filled;
677 mAvailToClient = filled;
678 }
679 // 'availToServer' may be non-contiguous, so return only the first contiguous chunk
680 size_t part1;
681 if (mIsOut) {
682 front &= mFrameCountP2 - 1;
683 part1 = mFrameCountP2 - front;
684 } else {
685 rear &= mFrameCountP2 - 1;
686 part1 = mFrameCountP2 - rear;
687 }
688 if (part1 > availToServer) {
689 part1 = availToServer;
690 }
691 size_t ask = buffer->mFrameCount;
692 if (part1 > ask) {
693 part1 = ask;
694 }
695 // is assignment redundant in some cases?
696 buffer->mFrameCount = part1;
697 buffer->mRaw = part1 > 0 ?
698 &((char *) mBuffers)[(mIsOut ? front : rear) * mFrameSize] : NULL;
699 buffer->mNonContig = availToServer - part1;
Glenn Kasten2e422c42013-10-18 13:00:29 -0700700 // After flush(), allow releaseBuffer() on a previously obtained buffer;
701 // see "Acknowledge any pending flush()" in audioflinger/Tracks.cpp.
702 if (!ackFlush) {
703 mUnreleased = part1;
704 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800705 return part1 > 0 ? NO_ERROR : WOULD_BLOCK;
Glenn Kasten7db7df02013-06-25 16:13:23 -0700706 }
707no_init:
708 buffer->mFrameCount = 0;
709 buffer->mRaw = NULL;
710 buffer->mNonContig = 0;
711 mUnreleased = 0;
712 return NO_INIT;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800713}
714
715void ServerProxy::releaseBuffer(Buffer* buffer)
716{
Glenn Kasten7db7df02013-06-25 16:13:23 -0700717 LOG_ALWAYS_FATAL_IF(buffer == NULL);
718 size_t stepCount = buffer->mFrameCount;
719 if (stepCount == 0 || mIsShutdown) {
720 // prevent accidental re-use of buffer
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800721 buffer->mFrameCount = 0;
722 buffer->mRaw = NULL;
723 buffer->mNonContig = 0;
724 return;
725 }
Glenn Kasten7db7df02013-06-25 16:13:23 -0700726 LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased && mUnreleased <= mFrameCount));
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800727 mUnreleased -= stepCount;
728 audio_track_cblk_t* cblk = mCblk;
729 if (mIsOut) {
730 int32_t front = cblk->u.mStreaming.mFront;
731 android_atomic_release_store(stepCount + front, &cblk->u.mStreaming.mFront);
732 } else {
733 int32_t rear = cblk->u.mStreaming.mRear;
734 android_atomic_release_store(stepCount + rear, &cblk->u.mStreaming.mRear);
735 }
736
Glenn Kasten844f88c2014-05-09 13:38:09 -0700737 cblk->mServer += stepCount;
Andy Hung3f0c9022016-01-15 17:49:46 -0800738 mReleased += stepCount;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800739
740 size_t half = mFrameCount / 2;
741 if (half == 0) {
742 half = 1;
743 }
Glenn Kastenfdac7c02014-01-28 11:03:28 -0800744 size_t minimum = (size_t) cblk->mMinimum;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800745 if (minimum == 0) {
746 minimum = mIsOut ? half : 1;
747 } else if (minimum > half) {
748 minimum = half;
749 }
Glenn Kasten93bb77d2013-06-24 12:10:45 -0700750 // FIXME AudioRecord wakeup needs to be optimized; it currently wakes up client every time
Glenn Kastence8828a2013-09-16 18:07:38 -0700751 if (!mIsOut || (mAvailToClient + stepCount >= minimum)) {
Mark Salyzyn34fb2962014-06-18 16:30:56 -0700752 ALOGV("mAvailToClient=%zu stepCount=%zu minimum=%zu", mAvailToClient, stepCount, minimum);
Glenn Kasten0d09a9b2013-06-24 12:06:46 -0700753 int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
754 if (!(old & CBLK_FUTEX_WAKE)) {
Elliott Hughesee499292014-05-21 17:55:51 -0700755 (void) syscall(__NR_futex, &cblk->mFutex,
756 mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800757 }
758 }
759
760 buffer->mFrameCount = 0;
761 buffer->mRaw = NULL;
762 buffer->mNonContig = 0;
763}
764
765// ---------------------------------------------------------------------------
766
767size_t AudioTrackServerProxy::framesReady()
768{
769 LOG_ALWAYS_FATAL_IF(!mIsOut);
770
771 if (mIsShutdown) {
772 return 0;
773 }
774 audio_track_cblk_t* cblk = mCblk;
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100775
776 int32_t flush = cblk->u.mStreaming.mFlush;
777 if (flush != mFlush) {
Glenn Kasten20f51b12014-10-30 10:43:19 -0700778 // FIXME should return an accurate value, but over-estimate is better than under-estimate
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100779 return mFrameCount;
780 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800781 // the acquire might not be necessary since not doing a subsequent read
782 int32_t rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
783 ssize_t filled = rear - cblk->u.mStreaming.mFront;
784 // pipe should not already be overfull
785 if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
Mark Salyzyn34fb2962014-06-18 16:30:56 -0700786 ALOGE("Shared memory control block is corrupt (filled=%zd); shutting down", filled);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800787 mIsShutdown = true;
788 return 0;
789 }
790 // cache this value for later use by obtainBuffer(), with added barrier
791 // and racy if called by normal mixer thread
792 // ignores flush(), so framesReady() may report a larger mFrameCount than obtainBuffer()
793 return filled;
794}
795
Eric Laurentbfb1b832013-01-07 09:53:42 -0800796bool AudioTrackServerProxy::setStreamEndDone() {
Glenn Kasten844f88c2014-05-09 13:38:09 -0700797 audio_track_cblk_t* cblk = mCblk;
Eric Laurentbfb1b832013-01-07 09:53:42 -0800798 bool old =
Glenn Kasten844f88c2014-05-09 13:38:09 -0700799 (android_atomic_or(CBLK_STREAM_END_DONE, &cblk->mFlags) & CBLK_STREAM_END_DONE) != 0;
Eric Laurentbfb1b832013-01-07 09:53:42 -0800800 if (!old) {
Elliott Hughese348c5b2014-05-21 18:47:50 -0700801 (void) syscall(__NR_futex, &cblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
Elliott Hughesee499292014-05-21 17:55:51 -0700802 1);
Eric Laurentbfb1b832013-01-07 09:53:42 -0800803 }
804 return old;
805}
806
Glenn Kasten82aaf942013-07-17 16:05:07 -0700807void AudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount)
808{
Glenn Kasten844f88c2014-05-09 13:38:09 -0700809 audio_track_cblk_t* cblk = mCblk;
Phil Burk2812d9e2016-01-04 10:34:30 -0800810 if (frameCount > 0) {
811 cblk->u.mStreaming.mUnderrunFrames += frameCount;
Glenn Kasten82aaf942013-07-17 16:05:07 -0700812
Phil Burk2812d9e2016-01-04 10:34:30 -0800813 if (!mUnderrunning) { // start of underrun?
814 mUnderrunCount++;
815 cblk->u.mStreaming.mUnderrunCount = mUnderrunCount;
816 mUnderrunning = true;
817 ALOGV("tallyUnderrunFrames(%3u) at uf = %u, bump mUnderrunCount = %u",
818 frameCount, cblk->u.mStreaming.mUnderrunFrames, mUnderrunCount);
819 }
820
821 // FIXME also wake futex so that underrun is noticed more quickly
822 (void) android_atomic_or(CBLK_UNDERRUN, &cblk->mFlags);
823 } else {
824 ALOGV_IF(mUnderrunning,
825 "tallyUnderrunFrames(%3u) at uf = %u, underrun finished",
826 frameCount, cblk->u.mStreaming.mUnderrunFrames);
827 mUnderrunning = false; // so we can detect the next edge
828 }
Glenn Kasten82aaf942013-07-17 16:05:07 -0700829}
830
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700831AudioPlaybackRate AudioTrackServerProxy::getPlaybackRate()
Andy Hung8edb8dc2015-03-26 19:13:55 -0700832{ // do not call from multiple threads without holding lock
Ricardo Garcia5a8a95d2015-04-18 14:47:04 -0700833 mPlaybackRateObserver.poll(mPlaybackRate);
834 return mPlaybackRate;
Andy Hung8edb8dc2015-03-26 19:13:55 -0700835}
836
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800837// ---------------------------------------------------------------------------
838
839StaticAudioTrackServerProxy::StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers,
840 size_t frameCount, size_t frameSize)
841 : AudioTrackServerProxy(cblk, buffers, frameCount, frameSize),
Andy Hung4ede21d2014-12-12 15:37:34 -0800842 mObserver(&cblk->u.mStatic.mSingleStateQueue),
843 mPosLoopMutator(&cblk->u.mStatic.mPosLoopQueue),
Andy Hungcb2129b2014-11-11 12:17:22 -0800844 mFramesReadySafe(frameCount), mFramesReady(frameCount),
845 mFramesReadyIsCalledByMultipleThreads(false)
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800846{
Andy Hung9b461582014-12-01 17:56:29 -0800847 memset(&mState, 0, sizeof(mState));
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800848}
849
850void StaticAudioTrackServerProxy::framesReadyIsCalledByMultipleThreads()
851{
852 mFramesReadyIsCalledByMultipleThreads = true;
853}
854
855size_t StaticAudioTrackServerProxy::framesReady()
856{
Andy Hungcb2129b2014-11-11 12:17:22 -0800857 // Can't call pollPosition() from multiple threads.
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800858 if (!mFramesReadyIsCalledByMultipleThreads) {
Andy Hungcb2129b2014-11-11 12:17:22 -0800859 (void) pollPosition();
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800860 }
Andy Hungcb2129b2014-11-11 12:17:22 -0800861 return mFramesReadySafe;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800862}
863
Andy Hung9b461582014-12-01 17:56:29 -0800864status_t StaticAudioTrackServerProxy::updateStateWithLoop(
865 StaticAudioTrackState *localState, const StaticAudioTrackState &update) const
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800866{
Andy Hung9b461582014-12-01 17:56:29 -0800867 if (localState->mLoopSequence != update.mLoopSequence) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800868 bool valid = false;
Andy Hung9b461582014-12-01 17:56:29 -0800869 const size_t loopStart = update.mLoopStart;
870 const size_t loopEnd = update.mLoopEnd;
871 size_t position = localState->mPosition;
872 if (update.mLoopCount == 0) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800873 valid = true;
Andy Hung9b461582014-12-01 17:56:29 -0800874 } else if (update.mLoopCount >= -1) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800875 if (loopStart < loopEnd && loopEnd <= mFrameCount &&
876 loopEnd - loopStart >= MIN_LOOP) {
Andy Hung680b7952014-11-12 13:18:52 -0800877 // If the current position is greater than the end of the loop
878 // we "wrap" to the loop start. This might cause an audible pop.
879 if (position >= loopEnd) {
Andy Hung9b461582014-12-01 17:56:29 -0800880 position = loopStart;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800881 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800882 valid = true;
883 }
884 }
Andy Hung9b461582014-12-01 17:56:29 -0800885 if (!valid || position > mFrameCount) {
886 return NO_INIT;
887 }
888 localState->mPosition = position;
889 localState->mLoopCount = update.mLoopCount;
890 localState->mLoopEnd = loopEnd;
891 localState->mLoopStart = loopStart;
892 localState->mLoopSequence = update.mLoopSequence;
893 }
894 return OK;
895}
896
897status_t StaticAudioTrackServerProxy::updateStateWithPosition(
898 StaticAudioTrackState *localState, const StaticAudioTrackState &update) const
899{
900 if (localState->mPositionSequence != update.mPositionSequence) {
901 if (update.mPosition > mFrameCount) {
902 return NO_INIT;
903 } else if (localState->mLoopCount != 0 && update.mPosition >= localState->mLoopEnd) {
904 localState->mLoopCount = 0; // disable loop count if position is beyond loop end.
905 }
906 localState->mPosition = update.mPosition;
907 localState->mPositionSequence = update.mPositionSequence;
908 }
909 return OK;
910}
911
912ssize_t StaticAudioTrackServerProxy::pollPosition()
913{
914 StaticAudioTrackState state;
915 if (mObserver.poll(state)) {
916 StaticAudioTrackState trystate = mState;
917 bool result;
Chad Brubakercb50c542015-10-07 14:20:10 -0700918 const int32_t diffSeq = (int32_t) state.mLoopSequence - (int32_t) state.mPositionSequence;
Andy Hung9b461582014-12-01 17:56:29 -0800919
920 if (diffSeq < 0) {
921 result = updateStateWithLoop(&trystate, state) == OK &&
922 updateStateWithPosition(&trystate, state) == OK;
923 } else {
924 result = updateStateWithPosition(&trystate, state) == OK &&
925 updateStateWithLoop(&trystate, state) == OK;
926 }
927 if (!result) {
Andy Hung4ede21d2014-12-12 15:37:34 -0800928 mObserver.done();
Andy Hung9b461582014-12-01 17:56:29 -0800929 // caution: no update occurs so server state will be inconsistent with client state.
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800930 ALOGE("%s client pushed an invalid state, shutting down", __func__);
931 mIsShutdown = true;
932 return (ssize_t) NO_INIT;
933 }
Andy Hung9b461582014-12-01 17:56:29 -0800934 mState = trystate;
935 if (mState.mLoopCount == -1) {
936 mFramesReady = INT64_MAX;
937 } else if (mState.mLoopCount == 0) {
938 mFramesReady = mFrameCount - mState.mPosition;
939 } else if (mState.mLoopCount > 0) {
940 // TODO: Later consider fixing overflow, but does not seem needed now
941 // as will not overflow if loopStart and loopEnd are Java "ints".
942 mFramesReady = int64_t(mState.mLoopCount) * (mState.mLoopEnd - mState.mLoopStart)
943 + mFrameCount - mState.mPosition;
944 }
Andy Hungcb2129b2014-11-11 12:17:22 -0800945 mFramesReadySafe = clampToSize(mFramesReady);
Glenn Kastenfdac7c02014-01-28 11:03:28 -0800946 // This may overflow, but client is not supposed to rely on it
Andy Hung4ede21d2014-12-12 15:37:34 -0800947 StaticAudioTrackPosLoop posLoop;
948
949 posLoop.mLoopCount = (int32_t) mState.mLoopCount;
950 posLoop.mBufferPosition = (uint32_t) mState.mPosition;
951 mPosLoopMutator.push(posLoop);
952 mObserver.done(); // safe to read mStatic variables.
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800953 }
Andy Hung9b461582014-12-01 17:56:29 -0800954 return (ssize_t) mState.mPosition;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800955}
956
Andy Hung954ca452015-09-09 14:39:02 -0700957status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800958{
959 if (mIsShutdown) {
960 buffer->mFrameCount = 0;
961 buffer->mRaw = NULL;
962 buffer->mNonContig = 0;
963 mUnreleased = 0;
964 return NO_INIT;
965 }
966 ssize_t positionOrStatus = pollPosition();
967 if (positionOrStatus < 0) {
968 buffer->mFrameCount = 0;
969 buffer->mRaw = NULL;
970 buffer->mNonContig = 0;
971 mUnreleased = 0;
972 return (status_t) positionOrStatus;
973 }
974 size_t position = (size_t) positionOrStatus;
Andy Hungcb2129b2014-11-11 12:17:22 -0800975 size_t end = mState.mLoopCount != 0 ? mState.mLoopEnd : mFrameCount;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800976 size_t avail;
Andy Hungcb2129b2014-11-11 12:17:22 -0800977 if (position < end) {
978 avail = end - position;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800979 size_t wanted = buffer->mFrameCount;
980 if (avail < wanted) {
981 buffer->mFrameCount = avail;
982 } else {
983 avail = wanted;
984 }
985 buffer->mRaw = &((char *) mBuffers)[position * mFrameSize];
986 } else {
987 avail = 0;
988 buffer->mFrameCount = 0;
989 buffer->mRaw = NULL;
990 }
Andy Hungcb2129b2014-11-11 12:17:22 -0800991 // As mFramesReady is the total remaining frames in the static audio track,
992 // it is always larger or equal to avail.
Andy Hung486a7132014-12-22 16:54:21 -0800993 LOG_ALWAYS_FATAL_IF(mFramesReady < (int64_t) avail);
Andy Hungcb2129b2014-11-11 12:17:22 -0800994 buffer->mNonContig = mFramesReady == INT64_MAX ? SIZE_MAX : clampToSize(mFramesReady - avail);
Andy Hung954ca452015-09-09 14:39:02 -0700995 if (!ackFlush) {
996 mUnreleased = avail;
997 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800998 return NO_ERROR;
999}
1000
1001void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer)
1002{
1003 size_t stepCount = buffer->mFrameCount;
Andy Hung486a7132014-12-22 16:54:21 -08001004 LOG_ALWAYS_FATAL_IF(!((int64_t) stepCount <= mFramesReady));
Glenn Kasten7db7df02013-06-25 16:13:23 -07001005 LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased));
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001006 if (stepCount == 0) {
Glenn Kasten7db7df02013-06-25 16:13:23 -07001007 // prevent accidental re-use of buffer
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001008 buffer->mRaw = NULL;
1009 buffer->mNonContig = 0;
1010 return;
1011 }
1012 mUnreleased -= stepCount;
1013 audio_track_cblk_t* cblk = mCblk;
Andy Hung9b461582014-12-01 17:56:29 -08001014 size_t position = mState.mPosition;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001015 size_t newPosition = position + stepCount;
1016 int32_t setFlags = 0;
1017 if (!(position <= newPosition && newPosition <= mFrameCount)) {
Glenn Kastenb187de12014-12-30 08:18:15 -08001018 ALOGW("%s newPosition %zu outside [%zu, %zu]", __func__, newPosition, position,
1019 mFrameCount);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001020 newPosition = mFrameCount;
1021 } else if (mState.mLoopCount != 0 && newPosition == mState.mLoopEnd) {
Andy Hungcb2129b2014-11-11 12:17:22 -08001022 newPosition = mState.mLoopStart;
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001023 if (mState.mLoopCount == -1 || --mState.mLoopCount != 0) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001024 setFlags = CBLK_LOOP_CYCLE;
1025 } else {
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001026 setFlags = CBLK_LOOP_FINAL;
1027 }
1028 }
1029 if (newPosition == mFrameCount) {
1030 setFlags |= CBLK_BUFFER_END;
1031 }
Andy Hung9b461582014-12-01 17:56:29 -08001032 mState.mPosition = newPosition;
Andy Hungcb2129b2014-11-11 12:17:22 -08001033 if (mFramesReady != INT64_MAX) {
1034 mFramesReady -= stepCount;
1035 }
1036 mFramesReadySafe = clampToSize(mFramesReady);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001037
Glenn Kastenf20e1d82013-07-12 09:45:18 -07001038 cblk->mServer += stepCount;
Andy Hung3f0c9022016-01-15 17:49:46 -08001039 mReleased += stepCount;
1040
Glenn Kastenfdac7c02014-01-28 11:03:28 -08001041 // This may overflow, but client is not supposed to rely on it
Andy Hung4ede21d2014-12-12 15:37:34 -08001042 StaticAudioTrackPosLoop posLoop;
1043 posLoop.mBufferPosition = mState.mPosition;
1044 posLoop.mLoopCount = mState.mLoopCount;
1045 mPosLoopMutator.push(posLoop);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001046 if (setFlags != 0) {
Glenn Kasten96f60d82013-07-12 10:21:18 -07001047 (void) android_atomic_or(setFlags, &cblk->mFlags);
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001048 // this would be a good place to wake a futex
1049 }
1050
1051 buffer->mFrameCount = 0;
1052 buffer->mRaw = NULL;
1053 buffer->mNonContig = 0;
1054}
1055
Phil Burk2812d9e2016-01-04 10:34:30 -08001056void StaticAudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount)
Glenn Kasten82aaf942013-07-17 16:05:07 -07001057{
1058 // Unlike AudioTrackServerProxy::tallyUnderrunFrames() used for streaming tracks,
1059 // we don't have a location to count underrun frames. The underrun frame counter
1060 // only exists in AudioTrackSharedStreaming. Fortunately, underruns are not
1061 // possible for static buffer tracks other than at end of buffer, so this is not a loss.
1062
1063 // FIXME also wake futex so that underrun is noticed more quickly
Phil Burk2812d9e2016-01-04 10:34:30 -08001064 if (frameCount > 0) {
1065 (void) android_atomic_or(CBLK_UNDERRUN, &mCblk->mFlags);
1066 }
Glenn Kasten82aaf942013-07-17 16:05:07 -07001067}
1068
Glenn Kasten9f80dd22012-12-18 15:57:32 -08001069// ---------------------------------------------------------------------------
1070
Glenn Kastena8190fc2012-12-03 17:06:56 -08001071} // namespace android