blob: 7c7c03abe8f138f83694e98e0ff0eab6b24df960 [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) {
31 return x > SIZE_MAX ? SIZE_MAX : x < 0 ? 0 : (size_t) x;
32}
33
Glenn Kastena8190fc2012-12-03 17:06:56 -080034audio_track_cblk_t::audio_track_cblk_t()
Glenn Kasten74935e42013-12-19 08:56:45 -080035 : mServer(0), mFutex(0), mMinimum(0),
Glenn Kastenc56f3422014-03-21 17:53:17 -070036 mVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY), mSampleRate(0), mSendLevel(0), mFlags(0)
Glenn Kasten9f80dd22012-12-18 15:57:32 -080037{
38 memset(&u, 0, sizeof(u));
39}
40
41// ---------------------------------------------------------------------------
42
43Proxy::Proxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize,
44 bool isOut, bool clientInServer)
45 : mCblk(cblk), mBuffers(buffers), mFrameCount(frameCount), mFrameSize(frameSize),
46 mFrameCountP2(roundup(frameCount)), mIsOut(isOut), mClientInServer(clientInServer),
Glenn Kasten7db7df02013-06-25 16:13:23 -070047 mIsShutdown(false), mUnreleased(0)
Glenn Kastena8190fc2012-12-03 17:06:56 -080048{
49}
50
Glenn Kasten9f80dd22012-12-18 15:57:32 -080051// ---------------------------------------------------------------------------
52
53ClientProxy::ClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
54 size_t frameSize, bool isOut, bool clientInServer)
55 : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer), mEpoch(0)
Glenn Kastena8190fc2012-12-03 17:06:56 -080056{
Glenn Kastena8190fc2012-12-03 17:06:56 -080057}
58
Glenn Kasten9f80dd22012-12-18 15:57:32 -080059const struct timespec ClientProxy::kForever = {INT_MAX /*tv_sec*/, 0 /*tv_nsec*/};
60const struct timespec ClientProxy::kNonBlocking = {0 /*tv_sec*/, 0 /*tv_nsec*/};
61
62#define MEASURE_NS 10000000 // attempt to provide accurate timeouts if requested >= MEASURE_NS
63
64// To facilitate quicker recovery from server failure, this value limits the timeout per each futex
65// wait. However it does not protect infinite timeouts. If defined to be zero, there is no limit.
66// FIXME May not be compatible with audio tunneling requirements where timeout should be in the
67// order of minutes.
68#define MAX_SEC 5
69
70status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *requested,
71 struct timespec *elapsed)
Glenn Kastena8190fc2012-12-03 17:06:56 -080072{
Glenn Kasten7db7df02013-06-25 16:13:23 -070073 LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0);
Glenn Kasten9f80dd22012-12-18 15:57:32 -080074 struct timespec total; // total elapsed time spent waiting
75 total.tv_sec = 0;
76 total.tv_nsec = 0;
77 bool measure = elapsed != NULL; // whether to measure total elapsed time spent waiting
Glenn Kastena8190fc2012-12-03 17:06:56 -080078
Glenn Kasten9f80dd22012-12-18 15:57:32 -080079 status_t status;
80 enum {
81 TIMEOUT_ZERO, // requested == NULL || *requested == 0
82 TIMEOUT_INFINITE, // *requested == infinity
83 TIMEOUT_FINITE, // 0 < *requested < infinity
84 TIMEOUT_CONTINUE, // additional chances after TIMEOUT_FINITE
85 } timeout;
86 if (requested == NULL) {
87 timeout = TIMEOUT_ZERO;
88 } else if (requested->tv_sec == 0 && requested->tv_nsec == 0) {
89 timeout = TIMEOUT_ZERO;
90 } else if (requested->tv_sec == INT_MAX) {
91 timeout = TIMEOUT_INFINITE;
Glenn Kastena8190fc2012-12-03 17:06:56 -080092 } else {
Glenn Kasten9f80dd22012-12-18 15:57:32 -080093 timeout = TIMEOUT_FINITE;
94 if (requested->tv_sec > 0 || requested->tv_nsec >= MEASURE_NS) {
95 measure = true;
96 }
Glenn Kastena8190fc2012-12-03 17:06:56 -080097 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -080098 struct timespec before;
99 bool beforeIsValid = false;
100 audio_track_cblk_t* cblk = mCblk;
101 bool ignoreInitialPendingInterrupt = true;
102 // check for shared memory corruption
103 if (mIsShutdown) {
104 status = NO_INIT;
105 goto end;
106 }
107 for (;;) {
Glenn Kasten96f60d82013-07-12 10:21:18 -0700108 int32_t flags = android_atomic_and(~CBLK_INTERRUPT, &cblk->mFlags);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800109 // check for track invalidation by server, or server death detection
110 if (flags & CBLK_INVALID) {
111 ALOGV("Track invalidated");
112 status = DEAD_OBJECT;
113 goto end;
114 }
115 // check for obtainBuffer interrupted by client
116 if (!ignoreInitialPendingInterrupt && (flags & CBLK_INTERRUPT)) {
117 ALOGV("obtainBuffer() interrupted by client");
118 status = -EINTR;
119 goto end;
120 }
121 ignoreInitialPendingInterrupt = false;
122 // compute number of frames available to write (AudioTrack) or read (AudioRecord)
123 int32_t front;
124 int32_t rear;
125 if (mIsOut) {
126 // The barrier following the read of mFront is probably redundant.
127 // We're about to perform a conditional branch based on 'filled',
128 // which will force the processor to observe the read of mFront
129 // prior to allowing data writes starting at mRaw.
130 // However, the processor may support speculative execution,
131 // and be unable to undo speculative writes into shared memory.
132 // The barrier will prevent such speculative execution.
133 front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
134 rear = cblk->u.mStreaming.mRear;
Glenn Kastena8190fc2012-12-03 17:06:56 -0800135 } else {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800136 // On the other hand, this barrier is required.
137 rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
138 front = cblk->u.mStreaming.mFront;
139 }
140 ssize_t filled = rear - front;
141 // pipe should not be overfull
142 if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
Glenn Kasten6dbb5e32014-05-13 10:38:42 -0700143 if (mIsOut) {
Mark Salyzyn34fb2962014-06-18 16:30:56 -0700144 ALOGE("Shared memory control block is corrupt (filled=%zd, mFrameCount=%zu); "
Glenn Kasten6dbb5e32014-05-13 10:38:42 -0700145 "shutting down", filled, mFrameCount);
146 mIsShutdown = true;
147 status = NO_INIT;
148 goto end;
149 }
150 // for input, sync up on overrun
151 filled = 0;
152 cblk->u.mStreaming.mFront = rear;
153 (void) android_atomic_or(CBLK_OVERRUN, &cblk->mFlags);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800154 }
155 // don't allow filling pipe beyond the nominal size
156 size_t avail = mIsOut ? mFrameCount - filled : filled;
157 if (avail > 0) {
158 // 'avail' may be non-contiguous, so return only the first contiguous chunk
159 size_t part1;
160 if (mIsOut) {
161 rear &= mFrameCountP2 - 1;
162 part1 = mFrameCountP2 - rear;
163 } else {
164 front &= mFrameCountP2 - 1;
165 part1 = mFrameCountP2 - front;
Glenn Kastena8190fc2012-12-03 17:06:56 -0800166 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800167 if (part1 > avail) {
168 part1 = avail;
Glenn Kastena8190fc2012-12-03 17:06:56 -0800169 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800170 if (part1 > buffer->mFrameCount) {
171 part1 = buffer->mFrameCount;
172 }
173 buffer->mFrameCount = part1;
174 buffer->mRaw = part1 > 0 ?
175 &((char *) mBuffers)[(mIsOut ? rear : front) * mFrameSize] : NULL;
176 buffer->mNonContig = avail - part1;
Glenn Kasten7db7df02013-06-25 16:13:23 -0700177 mUnreleased = part1;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800178 status = NO_ERROR;
179 break;
180 }
181 struct timespec remaining;
182 const struct timespec *ts;
183 switch (timeout) {
184 case TIMEOUT_ZERO:
185 status = WOULD_BLOCK;
186 goto end;
187 case TIMEOUT_INFINITE:
188 ts = NULL;
189 break;
190 case TIMEOUT_FINITE:
191 timeout = TIMEOUT_CONTINUE;
192 if (MAX_SEC == 0) {
193 ts = requested;
194 break;
195 }
196 // fall through
197 case TIMEOUT_CONTINUE:
198 // FIXME we do not retry if requested < 10ms? needs documentation on this state machine
199 if (!measure || requested->tv_sec < total.tv_sec ||
200 (requested->tv_sec == total.tv_sec && requested->tv_nsec <= total.tv_nsec)) {
201 status = TIMED_OUT;
202 goto end;
203 }
204 remaining.tv_sec = requested->tv_sec - total.tv_sec;
205 if ((remaining.tv_nsec = requested->tv_nsec - total.tv_nsec) < 0) {
206 remaining.tv_nsec += 1000000000;
207 remaining.tv_sec++;
208 }
209 if (0 < MAX_SEC && MAX_SEC < remaining.tv_sec) {
210 remaining.tv_sec = MAX_SEC;
211 remaining.tv_nsec = 0;
212 }
213 ts = &remaining;
214 break;
215 default:
Glenn Kastenadad3d72014-02-21 14:51:43 -0800216 LOG_ALWAYS_FATAL("obtainBuffer() timeout=%d", timeout);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800217 ts = NULL;
218 break;
219 }
Glenn Kasten0d09a9b2013-06-24 12:06:46 -0700220 int32_t old = android_atomic_and(~CBLK_FUTEX_WAKE, &cblk->mFutex);
221 if (!(old & CBLK_FUTEX_WAKE)) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800222 if (measure && !beforeIsValid) {
223 clock_gettime(CLOCK_MONOTONIC, &before);
224 beforeIsValid = true;
225 }
Elliott Hughesee499292014-05-21 17:55:51 -0700226 errno = 0;
227 (void) syscall(__NR_futex, &cblk->mFutex,
Glenn Kasten0d09a9b2013-06-24 12:06:46 -0700228 mClientInServer ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT, old & ~CBLK_FUTEX_WAKE, ts);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800229 // update total elapsed time spent waiting
230 if (measure) {
231 struct timespec after;
232 clock_gettime(CLOCK_MONOTONIC, &after);
233 total.tv_sec += after.tv_sec - before.tv_sec;
234 long deltaNs = after.tv_nsec - before.tv_nsec;
235 if (deltaNs < 0) {
236 deltaNs += 1000000000;
237 total.tv_sec--;
238 }
239 if ((total.tv_nsec += deltaNs) >= 1000000000) {
240 total.tv_nsec -= 1000000000;
241 total.tv_sec++;
242 }
243 before = after;
244 beforeIsValid = true;
245 }
Elliott Hughesee499292014-05-21 17:55:51 -0700246 switch (errno) {
247 case 0: // normal wakeup by server, or by binderDied()
248 case EWOULDBLOCK: // benign race condition with server
249 case EINTR: // wait was interrupted by signal or other spurious wakeup
250 case ETIMEDOUT: // time-out expired
Glenn Kasten7db7df02013-06-25 16:13:23 -0700251 // FIXME these error/non-0 status are being dropped
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800252 break;
253 default:
Elliott Hughesee499292014-05-21 17:55:51 -0700254 status = errno;
255 ALOGE("%s unexpected error %s", __func__, strerror(status));
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800256 goto end;
257 }
258 }
259 }
260
261end:
262 if (status != NO_ERROR) {
263 buffer->mFrameCount = 0;
264 buffer->mRaw = NULL;
265 buffer->mNonContig = 0;
Glenn Kasten7db7df02013-06-25 16:13:23 -0700266 mUnreleased = 0;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800267 }
268 if (elapsed != NULL) {
269 *elapsed = total;
270 }
271 if (requested == NULL) {
272 requested = &kNonBlocking;
273 }
274 if (measure) {
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100275 ALOGV("requested %ld.%03ld elapsed %ld.%03ld",
276 requested->tv_sec, requested->tv_nsec / 1000000,
277 total.tv_sec, total.tv_nsec / 1000000);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800278 }
279 return status;
280}
281
282void ClientProxy::releaseBuffer(Buffer* buffer)
283{
Glenn Kasten7db7df02013-06-25 16:13:23 -0700284 LOG_ALWAYS_FATAL_IF(buffer == NULL);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800285 size_t stepCount = buffer->mFrameCount;
Glenn Kasten7db7df02013-06-25 16:13:23 -0700286 if (stepCount == 0 || mIsShutdown) {
287 // prevent accidental re-use of buffer
288 buffer->mFrameCount = 0;
289 buffer->mRaw = NULL;
290 buffer->mNonContig = 0;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800291 return;
292 }
Glenn Kasten7db7df02013-06-25 16:13:23 -0700293 LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased && mUnreleased <= mFrameCount));
294 mUnreleased -= stepCount;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800295 audio_track_cblk_t* cblk = mCblk;
296 // Both of these barriers are required
297 if (mIsOut) {
298 int32_t rear = cblk->u.mStreaming.mRear;
299 android_atomic_release_store(stepCount + rear, &cblk->u.mStreaming.mRear);
300 } else {
301 int32_t front = cblk->u.mStreaming.mFront;
302 android_atomic_release_store(stepCount + front, &cblk->u.mStreaming.mFront);
303 }
304}
305
306void ClientProxy::binderDied()
307{
308 audio_track_cblk_t* cblk = mCblk;
Glenn Kasten96f60d82013-07-12 10:21:18 -0700309 if (!(android_atomic_or(CBLK_INVALID, &cblk->mFlags) & CBLK_INVALID)) {
zunkyu.lee82a69ea2014-11-07 15:47:32 +0900310 android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800311 // it seems that a FUTEX_WAKE_PRIVATE will not wake a FUTEX_WAIT, even within same process
Elliott Hughesee499292014-05-21 17:55:51 -0700312 (void) syscall(__NR_futex, &cblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
313 1);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800314 }
315}
316
317void ClientProxy::interrupt()
318{
319 audio_track_cblk_t* cblk = mCblk;
Glenn Kasten96f60d82013-07-12 10:21:18 -0700320 if (!(android_atomic_or(CBLK_INTERRUPT, &cblk->mFlags) & CBLK_INTERRUPT)) {
zunkyu.lee82a69ea2014-11-07 15:47:32 +0900321 android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
Elliott Hughesee499292014-05-21 17:55:51 -0700322 (void) syscall(__NR_futex, &cblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
323 1);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800324 }
325}
326
Chad Brubaker65dda4f2015-09-22 16:13:30 -0700327__attribute__((no_sanitize("integer")))
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800328size_t ClientProxy::getMisalignment()
329{
330 audio_track_cblk_t* cblk = mCblk;
331 return (mFrameCountP2 - (mIsOut ? cblk->u.mStreaming.mRear : cblk->u.mStreaming.mFront)) &
332 (mFrameCountP2 - 1);
333}
334
Eric Laurentcc21e4f2013-10-16 15:12:32 -0700335size_t ClientProxy::getFramesFilled() {
336 audio_track_cblk_t* cblk = mCblk;
337 int32_t front;
338 int32_t rear;
339
340 if (mIsOut) {
341 front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
342 rear = cblk->u.mStreaming.mRear;
343 } else {
344 rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
345 front = cblk->u.mStreaming.mFront;
346 }
347 ssize_t filled = rear - front;
348 // pipe should not be overfull
349 if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
Mark Salyzyn34fb2962014-06-18 16:30:56 -0700350 ALOGE("Shared memory control block is corrupt (filled=%zd); shutting down", filled);
Eric Laurentcc21e4f2013-10-16 15:12:32 -0700351 return 0;
352 }
353 return (size_t)filled;
354}
355
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800356// ---------------------------------------------------------------------------
357
358void AudioTrackClientProxy::flush()
359{
Glenn Kasten20f51b12014-10-30 10:43:19 -0700360 // This works for mFrameCountP2 <= 2^30
361 size_t increment = mFrameCountP2 << 1;
362 size_t mask = increment - 1;
363 audio_track_cblk_t* cblk = mCblk;
364 int32_t newFlush = (cblk->u.mStreaming.mRear & mask) |
365 ((cblk->u.mStreaming.mFlush & ~mask) + increment);
366 android_atomic_release_store(newFlush, &cblk->u.mStreaming.mFlush);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800367}
368
Eric Laurentbfb1b832013-01-07 09:53:42 -0800369bool AudioTrackClientProxy::clearStreamEndDone() {
Glenn Kasten96f60d82013-07-12 10:21:18 -0700370 return (android_atomic_and(~CBLK_STREAM_END_DONE, &mCblk->mFlags) & CBLK_STREAM_END_DONE) != 0;
Eric Laurentbfb1b832013-01-07 09:53:42 -0800371}
372
373bool AudioTrackClientProxy::getStreamEndDone() const {
Glenn Kasten96f60d82013-07-12 10:21:18 -0700374 return (mCblk->mFlags & CBLK_STREAM_END_DONE) != 0;
Eric Laurentbfb1b832013-01-07 09:53:42 -0800375}
376
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100377status_t AudioTrackClientProxy::waitStreamEndDone(const struct timespec *requested)
378{
379 struct timespec total; // total elapsed time spent waiting
380 total.tv_sec = 0;
381 total.tv_nsec = 0;
382 audio_track_cblk_t* cblk = mCblk;
383 status_t status;
384 enum {
385 TIMEOUT_ZERO, // requested == NULL || *requested == 0
386 TIMEOUT_INFINITE, // *requested == infinity
387 TIMEOUT_FINITE, // 0 < *requested < infinity
388 TIMEOUT_CONTINUE, // additional chances after TIMEOUT_FINITE
389 } timeout;
390 if (requested == NULL) {
391 timeout = TIMEOUT_ZERO;
392 } else if (requested->tv_sec == 0 && requested->tv_nsec == 0) {
393 timeout = TIMEOUT_ZERO;
394 } else if (requested->tv_sec == INT_MAX) {
395 timeout = TIMEOUT_INFINITE;
396 } else {
397 timeout = TIMEOUT_FINITE;
398 }
399 for (;;) {
Glenn Kasten96f60d82013-07-12 10:21:18 -0700400 int32_t flags = android_atomic_and(~(CBLK_INTERRUPT|CBLK_STREAM_END_DONE), &cblk->mFlags);
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100401 // check for track invalidation by server, or server death detection
402 if (flags & CBLK_INVALID) {
403 ALOGV("Track invalidated");
404 status = DEAD_OBJECT;
405 goto end;
406 }
407 if (flags & CBLK_STREAM_END_DONE) {
408 ALOGV("stream end received");
409 status = NO_ERROR;
410 goto end;
411 }
412 // check for obtainBuffer interrupted by client
413 // check for obtainBuffer interrupted by client
414 if (flags & CBLK_INTERRUPT) {
415 ALOGV("waitStreamEndDone() interrupted by client");
416 status = -EINTR;
417 goto end;
418 }
419 struct timespec remaining;
420 const struct timespec *ts;
421 switch (timeout) {
422 case TIMEOUT_ZERO:
423 status = WOULD_BLOCK;
424 goto end;
425 case TIMEOUT_INFINITE:
426 ts = NULL;
427 break;
428 case TIMEOUT_FINITE:
429 timeout = TIMEOUT_CONTINUE;
430 if (MAX_SEC == 0) {
431 ts = requested;
432 break;
433 }
434 // fall through
435 case TIMEOUT_CONTINUE:
436 // FIXME we do not retry if requested < 10ms? needs documentation on this state machine
437 if (requested->tv_sec < total.tv_sec ||
438 (requested->tv_sec == total.tv_sec && requested->tv_nsec <= total.tv_nsec)) {
439 status = TIMED_OUT;
440 goto end;
441 }
442 remaining.tv_sec = requested->tv_sec - total.tv_sec;
443 if ((remaining.tv_nsec = requested->tv_nsec - total.tv_nsec) < 0) {
444 remaining.tv_nsec += 1000000000;
445 remaining.tv_sec++;
446 }
447 if (0 < MAX_SEC && MAX_SEC < remaining.tv_sec) {
448 remaining.tv_sec = MAX_SEC;
449 remaining.tv_nsec = 0;
450 }
451 ts = &remaining;
452 break;
453 default:
Glenn Kastenadad3d72014-02-21 14:51:43 -0800454 LOG_ALWAYS_FATAL("waitStreamEndDone() timeout=%d", timeout);
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100455 ts = NULL;
456 break;
457 }
458 int32_t old = android_atomic_and(~CBLK_FUTEX_WAKE, &cblk->mFutex);
459 if (!(old & CBLK_FUTEX_WAKE)) {
Elliott Hughesee499292014-05-21 17:55:51 -0700460 errno = 0;
461 (void) syscall(__NR_futex, &cblk->mFutex,
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100462 mClientInServer ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT, old & ~CBLK_FUTEX_WAKE, ts);
Elliott Hughesee499292014-05-21 17:55:51 -0700463 switch (errno) {
464 case 0: // normal wakeup by server, or by binderDied()
465 case EWOULDBLOCK: // benign race condition with server
466 case EINTR: // wait was interrupted by signal or other spurious wakeup
467 case ETIMEDOUT: // time-out expired
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100468 break;
469 default:
Elliott Hughesee499292014-05-21 17:55:51 -0700470 status = errno;
471 ALOGE("%s unexpected error %s", __func__, strerror(status));
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100472 goto end;
473 }
474 }
475 }
476
477end:
478 if (requested == NULL) {
479 requested = &kNonBlocking;
480 }
481 return status;
482}
483
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800484// ---------------------------------------------------------------------------
485
486StaticAudioTrackClientProxy::StaticAudioTrackClientProxy(audio_track_cblk_t* cblk, void *buffers,
487 size_t frameCount, size_t frameSize)
488 : AudioTrackClientProxy(cblk, buffers, frameCount, frameSize),
489 mMutator(&cblk->u.mStatic.mSingleStateQueue), mBufferPosition(0)
490{
491}
492
493void StaticAudioTrackClientProxy::flush()
494{
Glenn Kastenadad3d72014-02-21 14:51:43 -0800495 LOG_ALWAYS_FATAL("static flush");
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800496}
497
498void StaticAudioTrackClientProxy::setLoop(size_t loopStart, size_t loopEnd, int loopCount)
499{
Glenn Kastenfdac7c02014-01-28 11:03:28 -0800500 // This can only happen on a 64-bit client
501 if (loopStart > UINT32_MAX || loopEnd > UINT32_MAX) {
502 // FIXME Should return an error status
503 return;
504 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800505 StaticAudioTrackState newState;
Glenn Kastenfdac7c02014-01-28 11:03:28 -0800506 newState.mLoopStart = (uint32_t) loopStart;
507 newState.mLoopEnd = (uint32_t) loopEnd;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800508 newState.mLoopCount = loopCount;
Andy Hung680b7952014-11-12 13:18:52 -0800509 size_t bufferPosition;
510 if (loopCount == 0 || (bufferPosition = getBufferPosition()) >= loopEnd) {
511 bufferPosition = loopStart;
512 }
513 mBufferPosition = bufferPosition; // snapshot buffer position until loop is acknowledged.
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800514 (void) mMutator.push(newState);
515}
516
517size_t StaticAudioTrackClientProxy::getBufferPosition()
518{
519 size_t bufferPosition;
520 if (mMutator.ack()) {
Glenn Kastenfdac7c02014-01-28 11:03:28 -0800521 bufferPosition = (size_t) mCblk->u.mStatic.mBufferPosition;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800522 if (bufferPosition > mFrameCount) {
523 bufferPosition = mFrameCount;
Glenn Kastena8190fc2012-12-03 17:06:56 -0800524 }
525 } else {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800526 bufferPosition = mBufferPosition;
Glenn Kastena8190fc2012-12-03 17:06:56 -0800527 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800528 return bufferPosition;
Glenn Kastena8190fc2012-12-03 17:06:56 -0800529}
530
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800531// ---------------------------------------------------------------------------
532
533ServerProxy::ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
534 size_t frameSize, bool isOut, bool clientInServer)
Glenn Kasten7db7df02013-06-25 16:13:23 -0700535 : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer),
Glenn Kastence8828a2013-09-16 18:07:38 -0700536 mAvailToClient(0), mFlush(0)
Glenn Kastena8190fc2012-12-03 17:06:56 -0800537{
Glenn Kastena8190fc2012-12-03 17:06:56 -0800538}
539
Glenn Kasten2e422c42013-10-18 13:00:29 -0700540status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800541{
Glenn Kasten7db7df02013-06-25 16:13:23 -0700542 LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800543 if (mIsShutdown) {
Glenn Kasten7db7df02013-06-25 16:13:23 -0700544 goto no_init;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800545 }
Glenn Kasten7db7df02013-06-25 16:13:23 -0700546 {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800547 audio_track_cblk_t* cblk = mCblk;
548 // compute number of frames available to write (AudioTrack) or read (AudioRecord),
549 // or use previous cached value from framesReady(), with added barrier if it omits.
550 int32_t front;
551 int32_t rear;
552 // See notes on barriers at ClientProxy::obtainBuffer()
553 if (mIsOut) {
554 int32_t flush = cblk->u.mStreaming.mFlush;
555 rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100556 front = cblk->u.mStreaming.mFront;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800557 if (flush != mFlush) {
Glenn Kasten050501d2013-07-11 10:35:38 -0700558 // effectively obtain then release whatever is in the buffer
Glenn Kasten20f51b12014-10-30 10:43:19 -0700559 size_t mask = (mFrameCountP2 << 1) - 1;
560 int32_t newFront = (front & ~mask) | (flush & mask);
561 ssize_t filled = rear - newFront;
562 // Rather than shutting down on a corrupt flush, just treat it as a full flush
563 if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
564 ALOGE("mFlush %#x -> %#x, front %#x, rear %#x, mask %#x, newFront %#x, filled %d=%#x",
565 mFlush, flush, front, rear, mask, newFront, filled, filled);
566 newFront = rear;
567 }
568 mFlush = flush;
569 android_atomic_release_store(newFront, &cblk->u.mStreaming.mFront);
570 // There is no danger from a false positive, so err on the side of caution
571 if (true /*front != newFront*/) {
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100572 int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
573 if (!(old & CBLK_FUTEX_WAKE)) {
Elliott Hughesee499292014-05-21 17:55:51 -0700574 (void) syscall(__NR_futex, &cblk->mFutex,
575 mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100576 }
577 }
Glenn Kasten20f51b12014-10-30 10:43:19 -0700578 front = newFront;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800579 }
580 } else {
581 front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
582 rear = cblk->u.mStreaming.mRear;
583 }
584 ssize_t filled = rear - front;
585 // pipe should not already be overfull
586 if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
Mark Salyzyn34fb2962014-06-18 16:30:56 -0700587 ALOGE("Shared memory control block is corrupt (filled=%zd); shutting down", filled);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800588 mIsShutdown = true;
589 }
590 if (mIsShutdown) {
Glenn Kasten7db7df02013-06-25 16:13:23 -0700591 goto no_init;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800592 }
593 // don't allow filling pipe beyond the nominal size
594 size_t availToServer;
595 if (mIsOut) {
596 availToServer = filled;
597 mAvailToClient = mFrameCount - filled;
598 } else {
599 availToServer = mFrameCount - filled;
600 mAvailToClient = filled;
601 }
602 // 'availToServer' may be non-contiguous, so return only the first contiguous chunk
603 size_t part1;
604 if (mIsOut) {
605 front &= mFrameCountP2 - 1;
606 part1 = mFrameCountP2 - front;
607 } else {
608 rear &= mFrameCountP2 - 1;
609 part1 = mFrameCountP2 - rear;
610 }
611 if (part1 > availToServer) {
612 part1 = availToServer;
613 }
614 size_t ask = buffer->mFrameCount;
615 if (part1 > ask) {
616 part1 = ask;
617 }
618 // is assignment redundant in some cases?
619 buffer->mFrameCount = part1;
620 buffer->mRaw = part1 > 0 ?
621 &((char *) mBuffers)[(mIsOut ? front : rear) * mFrameSize] : NULL;
622 buffer->mNonContig = availToServer - part1;
Glenn Kasten2e422c42013-10-18 13:00:29 -0700623 // After flush(), allow releaseBuffer() on a previously obtained buffer;
624 // see "Acknowledge any pending flush()" in audioflinger/Tracks.cpp.
625 if (!ackFlush) {
626 mUnreleased = part1;
627 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800628 return part1 > 0 ? NO_ERROR : WOULD_BLOCK;
Glenn Kasten7db7df02013-06-25 16:13:23 -0700629 }
630no_init:
631 buffer->mFrameCount = 0;
632 buffer->mRaw = NULL;
633 buffer->mNonContig = 0;
634 mUnreleased = 0;
635 return NO_INIT;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800636}
637
638void ServerProxy::releaseBuffer(Buffer* buffer)
639{
Glenn Kasten7db7df02013-06-25 16:13:23 -0700640 LOG_ALWAYS_FATAL_IF(buffer == NULL);
641 size_t stepCount = buffer->mFrameCount;
642 if (stepCount == 0 || mIsShutdown) {
643 // prevent accidental re-use of buffer
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800644 buffer->mFrameCount = 0;
645 buffer->mRaw = NULL;
646 buffer->mNonContig = 0;
647 return;
648 }
Glenn Kasten7db7df02013-06-25 16:13:23 -0700649 LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased && mUnreleased <= mFrameCount));
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800650 mUnreleased -= stepCount;
651 audio_track_cblk_t* cblk = mCblk;
652 if (mIsOut) {
653 int32_t front = cblk->u.mStreaming.mFront;
654 android_atomic_release_store(stepCount + front, &cblk->u.mStreaming.mFront);
655 } else {
656 int32_t rear = cblk->u.mStreaming.mRear;
657 android_atomic_release_store(stepCount + rear, &cblk->u.mStreaming.mRear);
658 }
659
Glenn Kasten844f88c2014-05-09 13:38:09 -0700660 cblk->mServer += stepCount;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800661
662 size_t half = mFrameCount / 2;
663 if (half == 0) {
664 half = 1;
665 }
Glenn Kastenfdac7c02014-01-28 11:03:28 -0800666 size_t minimum = (size_t) cblk->mMinimum;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800667 if (minimum == 0) {
668 minimum = mIsOut ? half : 1;
669 } else if (minimum > half) {
670 minimum = half;
671 }
Glenn Kasten93bb77d2013-06-24 12:10:45 -0700672 // FIXME AudioRecord wakeup needs to be optimized; it currently wakes up client every time
Glenn Kastence8828a2013-09-16 18:07:38 -0700673 if (!mIsOut || (mAvailToClient + stepCount >= minimum)) {
Mark Salyzyn34fb2962014-06-18 16:30:56 -0700674 ALOGV("mAvailToClient=%zu stepCount=%zu minimum=%zu", mAvailToClient, stepCount, minimum);
Glenn Kasten0d09a9b2013-06-24 12:06:46 -0700675 int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
676 if (!(old & CBLK_FUTEX_WAKE)) {
Elliott Hughesee499292014-05-21 17:55:51 -0700677 (void) syscall(__NR_futex, &cblk->mFutex,
678 mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800679 }
680 }
681
682 buffer->mFrameCount = 0;
683 buffer->mRaw = NULL;
684 buffer->mNonContig = 0;
685}
686
687// ---------------------------------------------------------------------------
688
689size_t AudioTrackServerProxy::framesReady()
690{
691 LOG_ALWAYS_FATAL_IF(!mIsOut);
692
693 if (mIsShutdown) {
694 return 0;
695 }
696 audio_track_cblk_t* cblk = mCblk;
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100697
698 int32_t flush = cblk->u.mStreaming.mFlush;
699 if (flush != mFlush) {
Glenn Kasten20f51b12014-10-30 10:43:19 -0700700 // FIXME should return an accurate value, but over-estimate is better than under-estimate
Richard Fitzgeraldb1a270d2013-05-14 12:12:21 +0100701 return mFrameCount;
702 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800703 // the acquire might not be necessary since not doing a subsequent read
704 int32_t rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
705 ssize_t filled = rear - cblk->u.mStreaming.mFront;
706 // pipe should not already be overfull
707 if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
Mark Salyzyn34fb2962014-06-18 16:30:56 -0700708 ALOGE("Shared memory control block is corrupt (filled=%zd); shutting down", filled);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800709 mIsShutdown = true;
710 return 0;
711 }
712 // cache this value for later use by obtainBuffer(), with added barrier
713 // and racy if called by normal mixer thread
714 // ignores flush(), so framesReady() may report a larger mFrameCount than obtainBuffer()
715 return filled;
716}
717
Eric Laurentbfb1b832013-01-07 09:53:42 -0800718bool AudioTrackServerProxy::setStreamEndDone() {
Glenn Kasten844f88c2014-05-09 13:38:09 -0700719 audio_track_cblk_t* cblk = mCblk;
Eric Laurentbfb1b832013-01-07 09:53:42 -0800720 bool old =
Glenn Kasten844f88c2014-05-09 13:38:09 -0700721 (android_atomic_or(CBLK_STREAM_END_DONE, &cblk->mFlags) & CBLK_STREAM_END_DONE) != 0;
Eric Laurentbfb1b832013-01-07 09:53:42 -0800722 if (!old) {
Elliott Hughese348c5b2014-05-21 18:47:50 -0700723 (void) syscall(__NR_futex, &cblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
Elliott Hughesee499292014-05-21 17:55:51 -0700724 1);
Eric Laurentbfb1b832013-01-07 09:53:42 -0800725 }
726 return old;
727}
728
Glenn Kasten82aaf942013-07-17 16:05:07 -0700729void AudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount)
730{
Glenn Kasten844f88c2014-05-09 13:38:09 -0700731 audio_track_cblk_t* cblk = mCblk;
732 cblk->u.mStreaming.mUnderrunFrames += frameCount;
Glenn Kasten82aaf942013-07-17 16:05:07 -0700733
734 // FIXME also wake futex so that underrun is noticed more quickly
Glenn Kasten844f88c2014-05-09 13:38:09 -0700735 (void) android_atomic_or(CBLK_UNDERRUN, &cblk->mFlags);
Glenn Kasten82aaf942013-07-17 16:05:07 -0700736}
737
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800738// ---------------------------------------------------------------------------
739
740StaticAudioTrackServerProxy::StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers,
741 size_t frameCount, size_t frameSize)
742 : AudioTrackServerProxy(cblk, buffers, frameCount, frameSize),
743 mObserver(&cblk->u.mStatic.mSingleStateQueue), mPosition(0),
Andy Hungcb2129b2014-11-11 12:17:22 -0800744 mFramesReadySafe(frameCount), mFramesReady(frameCount),
745 mFramesReadyIsCalledByMultipleThreads(false)
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800746{
747 mState.mLoopStart = 0;
748 mState.mLoopEnd = 0;
749 mState.mLoopCount = 0;
750}
751
752void StaticAudioTrackServerProxy::framesReadyIsCalledByMultipleThreads()
753{
754 mFramesReadyIsCalledByMultipleThreads = true;
755}
756
757size_t StaticAudioTrackServerProxy::framesReady()
758{
Andy Hungcb2129b2014-11-11 12:17:22 -0800759 // Can't call pollPosition() from multiple threads.
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800760 if (!mFramesReadyIsCalledByMultipleThreads) {
Andy Hungcb2129b2014-11-11 12:17:22 -0800761 (void) pollPosition();
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800762 }
Andy Hungcb2129b2014-11-11 12:17:22 -0800763 return mFramesReadySafe;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800764}
765
766ssize_t StaticAudioTrackServerProxy::pollPosition()
767{
768 size_t position = mPosition;
769 StaticAudioTrackState state;
770 if (mObserver.poll(state)) {
771 bool valid = false;
772 size_t loopStart = state.mLoopStart;
773 size_t loopEnd = state.mLoopEnd;
774 if (state.mLoopCount == 0) {
775 if (loopStart > mFrameCount) {
776 loopStart = mFrameCount;
777 }
778 // ignore loopEnd
779 mPosition = position = loopStart;
Andy Hungcb2129b2014-11-11 12:17:22 -0800780 mFramesReady = mFrameCount - mPosition;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800781 mState.mLoopCount = 0;
782 valid = true;
Andy Hungcb2129b2014-11-11 12:17:22 -0800783 } else if (state.mLoopCount >= -1) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800784 if (loopStart < loopEnd && loopEnd <= mFrameCount &&
785 loopEnd - loopStart >= MIN_LOOP) {
Andy Hung680b7952014-11-12 13:18:52 -0800786 // If the current position is greater than the end of the loop
787 // we "wrap" to the loop start. This might cause an audible pop.
788 if (position >= loopEnd) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800789 mPosition = position = loopStart;
790 }
Andy Hungcb2129b2014-11-11 12:17:22 -0800791 if (state.mLoopCount == -1) {
792 mFramesReady = INT64_MAX;
793 } else {
794 // mFramesReady is 64 bits to handle the effective number of frames
795 // that the static audio track contains, including loops.
796 // TODO: Later consider fixing overflow, but does not seem needed now
797 // as will not overflow if loopStart and loopEnd are Java "ints".
798 mFramesReady = int64_t(state.mLoopCount) * (loopEnd - loopStart)
799 + mFrameCount - mPosition;
800 }
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800801 mState = state;
802 valid = true;
803 }
804 }
Andy Hungcb2129b2014-11-11 12:17:22 -0800805 if (!valid || mPosition > mFrameCount) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800806 ALOGE("%s client pushed an invalid state, shutting down", __func__);
807 mIsShutdown = true;
808 return (ssize_t) NO_INIT;
809 }
Andy Hungcb2129b2014-11-11 12:17:22 -0800810 mFramesReadySafe = clampToSize(mFramesReady);
Glenn Kastenfdac7c02014-01-28 11:03:28 -0800811 // This may overflow, but client is not supposed to rely on it
812 mCblk->u.mStatic.mBufferPosition = (uint32_t) position;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800813 }
814 return (ssize_t) position;
815}
816
Glenn Kasten7c7be1e2013-12-19 16:34:04 -0800817status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush __unused)
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800818{
819 if (mIsShutdown) {
820 buffer->mFrameCount = 0;
821 buffer->mRaw = NULL;
822 buffer->mNonContig = 0;
823 mUnreleased = 0;
824 return NO_INIT;
825 }
826 ssize_t positionOrStatus = pollPosition();
827 if (positionOrStatus < 0) {
828 buffer->mFrameCount = 0;
829 buffer->mRaw = NULL;
830 buffer->mNonContig = 0;
831 mUnreleased = 0;
832 return (status_t) positionOrStatus;
833 }
834 size_t position = (size_t) positionOrStatus;
Andy Hungcb2129b2014-11-11 12:17:22 -0800835 size_t end = mState.mLoopCount != 0 ? mState.mLoopEnd : mFrameCount;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800836 size_t avail;
Andy Hungcb2129b2014-11-11 12:17:22 -0800837 if (position < end) {
838 avail = end - position;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800839 size_t wanted = buffer->mFrameCount;
840 if (avail < wanted) {
841 buffer->mFrameCount = avail;
842 } else {
843 avail = wanted;
844 }
845 buffer->mRaw = &((char *) mBuffers)[position * mFrameSize];
846 } else {
847 avail = 0;
848 buffer->mFrameCount = 0;
849 buffer->mRaw = NULL;
850 }
Andy Hungcb2129b2014-11-11 12:17:22 -0800851 // As mFramesReady is the total remaining frames in the static audio track,
852 // it is always larger or equal to avail.
853 LOG_ALWAYS_FATAL_IF(mFramesReady < avail);
854 buffer->mNonContig = mFramesReady == INT64_MAX ? SIZE_MAX : clampToSize(mFramesReady - avail);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800855 mUnreleased = avail;
856 return NO_ERROR;
857}
858
859void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer)
860{
861 size_t stepCount = buffer->mFrameCount;
Andy Hungcb2129b2014-11-11 12:17:22 -0800862 LOG_ALWAYS_FATAL_IF(!(stepCount <= mFramesReady));
Glenn Kasten7db7df02013-06-25 16:13:23 -0700863 LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased));
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800864 if (stepCount == 0) {
Glenn Kasten7db7df02013-06-25 16:13:23 -0700865 // prevent accidental re-use of buffer
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800866 buffer->mRaw = NULL;
867 buffer->mNonContig = 0;
868 return;
869 }
870 mUnreleased -= stepCount;
871 audio_track_cblk_t* cblk = mCblk;
872 size_t position = mPosition;
873 size_t newPosition = position + stepCount;
874 int32_t setFlags = 0;
875 if (!(position <= newPosition && newPosition <= mFrameCount)) {
Mark Salyzyn34fb2962014-06-18 16:30:56 -0700876 ALOGW("%s newPosition %zu outside [%zu, %zu]", __func__, newPosition, position, mFrameCount);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800877 newPosition = mFrameCount;
878 } else if (mState.mLoopCount != 0 && newPosition == mState.mLoopEnd) {
Andy Hungcb2129b2014-11-11 12:17:22 -0800879 newPosition = mState.mLoopStart;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800880 if (mState.mLoopCount == -1 || --mState.mLoopCount != 0) {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800881 setFlags = CBLK_LOOP_CYCLE;
882 } else {
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800883 setFlags = CBLK_LOOP_FINAL;
884 }
885 }
886 if (newPosition == mFrameCount) {
887 setFlags |= CBLK_BUFFER_END;
888 }
889 mPosition = newPosition;
Andy Hungcb2129b2014-11-11 12:17:22 -0800890 if (mFramesReady != INT64_MAX) {
891 mFramesReady -= stepCount;
892 }
893 mFramesReadySafe = clampToSize(mFramesReady);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800894
Glenn Kastenf20e1d82013-07-12 09:45:18 -0700895 cblk->mServer += stepCount;
Glenn Kastenfdac7c02014-01-28 11:03:28 -0800896 // This may overflow, but client is not supposed to rely on it
897 cblk->u.mStatic.mBufferPosition = (uint32_t) newPosition;
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800898 if (setFlags != 0) {
Glenn Kasten96f60d82013-07-12 10:21:18 -0700899 (void) android_atomic_or(setFlags, &cblk->mFlags);
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800900 // this would be a good place to wake a futex
901 }
902
903 buffer->mFrameCount = 0;
904 buffer->mRaw = NULL;
905 buffer->mNonContig = 0;
906}
907
Glenn Kasten7c7be1e2013-12-19 16:34:04 -0800908void StaticAudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount __unused)
Glenn Kasten82aaf942013-07-17 16:05:07 -0700909{
910 // Unlike AudioTrackServerProxy::tallyUnderrunFrames() used for streaming tracks,
911 // we don't have a location to count underrun frames. The underrun frame counter
912 // only exists in AudioTrackSharedStreaming. Fortunately, underruns are not
913 // possible for static buffer tracks other than at end of buffer, so this is not a loss.
914
915 // FIXME also wake futex so that underrun is noticed more quickly
916 (void) android_atomic_or(CBLK_UNDERRUN, &mCblk->mFlags);
917}
918
Glenn Kasten9f80dd22012-12-18 15:57:32 -0800919// ---------------------------------------------------------------------------
920
Glenn Kastena8190fc2012-12-03 17:06:56 -0800921} // namespace android