1 /*
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>
22
23 #include <linux/futex.h>
24 #include <sys/syscall.h>
25
26 namespace android {
27
28 // used to clamp a value to size_t. TODO: move to another file.
29 template <typename T>
clampToSize(T x)30 size_t clampToSize(T x) {
31 return x > SIZE_MAX ? SIZE_MAX : x < 0 ? 0 : (size_t) x;
32 }
33
audio_track_cblk_t()34 audio_track_cblk_t::audio_track_cblk_t()
35 : mServer(0), mFutex(0), mMinimum(0),
36 mVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY), mSampleRate(0), mSendLevel(0), mFlags(0)
37 {
38 memset(&u, 0, sizeof(u));
39 }
40
41 // ---------------------------------------------------------------------------
42
Proxy(audio_track_cblk_t * cblk,void * buffers,size_t frameCount,size_t frameSize,bool isOut,bool clientInServer)43 Proxy::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),
47 mIsShutdown(false), mUnreleased(0)
48 {
49 }
50
51 // ---------------------------------------------------------------------------
52
ClientProxy(audio_track_cblk_t * cblk,void * buffers,size_t frameCount,size_t frameSize,bool isOut,bool clientInServer)53 ClientProxy::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)
56 {
57 }
58
59 const struct timespec ClientProxy::kForever = {INT_MAX /*tv_sec*/, 0 /*tv_nsec*/};
60 const 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
obtainBuffer(Buffer * buffer,const struct timespec * requested,struct timespec * elapsed)70 status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *requested,
71 struct timespec *elapsed)
72 {
73 LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0);
74 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
78
79 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;
92 } else {
93 timeout = TIMEOUT_FINITE;
94 if (requested->tv_sec > 0 || requested->tv_nsec >= MEASURE_NS) {
95 measure = true;
96 }
97 }
98 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 (;;) {
108 int32_t flags = android_atomic_and(~CBLK_INTERRUPT, &cblk->mFlags);
109 // 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;
135 } else {
136 // 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)) {
143 if (mIsOut) {
144 ALOGE("Shared memory control block is corrupt (filled=%zd, mFrameCount=%zu); "
145 "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);
154 }
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;
166 }
167 if (part1 > avail) {
168 part1 = avail;
169 }
170 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;
177 mUnreleased = part1;
178 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:
216 LOG_ALWAYS_FATAL("obtainBuffer() timeout=%d", timeout);
217 ts = NULL;
218 break;
219 }
220 int32_t old = android_atomic_and(~CBLK_FUTEX_WAKE, &cblk->mFutex);
221 if (!(old & CBLK_FUTEX_WAKE)) {
222 if (measure && !beforeIsValid) {
223 clock_gettime(CLOCK_MONOTONIC, &before);
224 beforeIsValid = true;
225 }
226 errno = 0;
227 (void) syscall(__NR_futex, &cblk->mFutex,
228 mClientInServer ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT, old & ~CBLK_FUTEX_WAKE, ts);
229 // 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 }
246 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
251 // FIXME these error/non-0 status are being dropped
252 break;
253 default:
254 status = errno;
255 ALOGE("%s unexpected error %s", __func__, strerror(status));
256 goto end;
257 }
258 }
259 }
260
261 end:
262 if (status != NO_ERROR) {
263 buffer->mFrameCount = 0;
264 buffer->mRaw = NULL;
265 buffer->mNonContig = 0;
266 mUnreleased = 0;
267 }
268 if (elapsed != NULL) {
269 *elapsed = total;
270 }
271 if (requested == NULL) {
272 requested = &kNonBlocking;
273 }
274 if (measure) {
275 ALOGV("requested %ld.%03ld elapsed %ld.%03ld",
276 requested->tv_sec, requested->tv_nsec / 1000000,
277 total.tv_sec, total.tv_nsec / 1000000);
278 }
279 return status;
280 }
281
releaseBuffer(Buffer * buffer)282 void ClientProxy::releaseBuffer(Buffer* buffer)
283 {
284 LOG_ALWAYS_FATAL_IF(buffer == NULL);
285 size_t stepCount = buffer->mFrameCount;
286 if (stepCount == 0 || mIsShutdown) {
287 // prevent accidental re-use of buffer
288 buffer->mFrameCount = 0;
289 buffer->mRaw = NULL;
290 buffer->mNonContig = 0;
291 return;
292 }
293 LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased && mUnreleased <= mFrameCount));
294 mUnreleased -= stepCount;
295 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
binderDied()306 void ClientProxy::binderDied()
307 {
308 audio_track_cblk_t* cblk = mCblk;
309 if (!(android_atomic_or(CBLK_INVALID, &cblk->mFlags) & CBLK_INVALID)) {
310 android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
311 // it seems that a FUTEX_WAKE_PRIVATE will not wake a FUTEX_WAIT, even within same process
312 (void) syscall(__NR_futex, &cblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
313 1);
314 }
315 }
316
interrupt()317 void ClientProxy::interrupt()
318 {
319 audio_track_cblk_t* cblk = mCblk;
320 if (!(android_atomic_or(CBLK_INTERRUPT, &cblk->mFlags) & CBLK_INTERRUPT)) {
321 android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
322 (void) syscall(__NR_futex, &cblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
323 1);
324 }
325 }
326
getMisalignment()327 size_t ClientProxy::getMisalignment()
328 {
329 audio_track_cblk_t* cblk = mCblk;
330 return (mFrameCountP2 - (mIsOut ? cblk->u.mStreaming.mRear : cblk->u.mStreaming.mFront)) &
331 (mFrameCountP2 - 1);
332 }
333
getFramesFilled()334 size_t ClientProxy::getFramesFilled() {
335 audio_track_cblk_t* cblk = mCblk;
336 int32_t front;
337 int32_t rear;
338
339 if (mIsOut) {
340 front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
341 rear = cblk->u.mStreaming.mRear;
342 } else {
343 rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
344 front = cblk->u.mStreaming.mFront;
345 }
346 ssize_t filled = rear - front;
347 // pipe should not be overfull
348 if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
349 ALOGE("Shared memory control block is corrupt (filled=%zd); shutting down", filled);
350 return 0;
351 }
352 return (size_t)filled;
353 }
354
355 // ---------------------------------------------------------------------------
356
flush()357 void AudioTrackClientProxy::flush()
358 {
359 // This works for mFrameCountP2 <= 2^30
360 size_t increment = mFrameCountP2 << 1;
361 size_t mask = increment - 1;
362 audio_track_cblk_t* cblk = mCblk;
363 int32_t newFlush = (cblk->u.mStreaming.mRear & mask) |
364 ((cblk->u.mStreaming.mFlush & ~mask) + increment);
365 android_atomic_release_store(newFlush, &cblk->u.mStreaming.mFlush);
366 }
367
clearStreamEndDone()368 bool AudioTrackClientProxy::clearStreamEndDone() {
369 return (android_atomic_and(~CBLK_STREAM_END_DONE, &mCblk->mFlags) & CBLK_STREAM_END_DONE) != 0;
370 }
371
getStreamEndDone() const372 bool AudioTrackClientProxy::getStreamEndDone() const {
373 return (mCblk->mFlags & CBLK_STREAM_END_DONE) != 0;
374 }
375
waitStreamEndDone(const struct timespec * requested)376 status_t AudioTrackClientProxy::waitStreamEndDone(const struct timespec *requested)
377 {
378 struct timespec total; // total elapsed time spent waiting
379 total.tv_sec = 0;
380 total.tv_nsec = 0;
381 audio_track_cblk_t* cblk = mCblk;
382 status_t status;
383 enum {
384 TIMEOUT_ZERO, // requested == NULL || *requested == 0
385 TIMEOUT_INFINITE, // *requested == infinity
386 TIMEOUT_FINITE, // 0 < *requested < infinity
387 TIMEOUT_CONTINUE, // additional chances after TIMEOUT_FINITE
388 } timeout;
389 if (requested == NULL) {
390 timeout = TIMEOUT_ZERO;
391 } else if (requested->tv_sec == 0 && requested->tv_nsec == 0) {
392 timeout = TIMEOUT_ZERO;
393 } else if (requested->tv_sec == INT_MAX) {
394 timeout = TIMEOUT_INFINITE;
395 } else {
396 timeout = TIMEOUT_FINITE;
397 }
398 for (;;) {
399 int32_t flags = android_atomic_and(~(CBLK_INTERRUPT|CBLK_STREAM_END_DONE), &cblk->mFlags);
400 // check for track invalidation by server, or server death detection
401 if (flags & CBLK_INVALID) {
402 ALOGV("Track invalidated");
403 status = DEAD_OBJECT;
404 goto end;
405 }
406 if (flags & CBLK_STREAM_END_DONE) {
407 ALOGV("stream end received");
408 status = NO_ERROR;
409 goto end;
410 }
411 // check for obtainBuffer interrupted by client
412 // check for obtainBuffer interrupted by client
413 if (flags & CBLK_INTERRUPT) {
414 ALOGV("waitStreamEndDone() interrupted by client");
415 status = -EINTR;
416 goto end;
417 }
418 struct timespec remaining;
419 const struct timespec *ts;
420 switch (timeout) {
421 case TIMEOUT_ZERO:
422 status = WOULD_BLOCK;
423 goto end;
424 case TIMEOUT_INFINITE:
425 ts = NULL;
426 break;
427 case TIMEOUT_FINITE:
428 timeout = TIMEOUT_CONTINUE;
429 if (MAX_SEC == 0) {
430 ts = requested;
431 break;
432 }
433 // fall through
434 case TIMEOUT_CONTINUE:
435 // FIXME we do not retry if requested < 10ms? needs documentation on this state machine
436 if (requested->tv_sec < total.tv_sec ||
437 (requested->tv_sec == total.tv_sec && requested->tv_nsec <= total.tv_nsec)) {
438 status = TIMED_OUT;
439 goto end;
440 }
441 remaining.tv_sec = requested->tv_sec - total.tv_sec;
442 if ((remaining.tv_nsec = requested->tv_nsec - total.tv_nsec) < 0) {
443 remaining.tv_nsec += 1000000000;
444 remaining.tv_sec++;
445 }
446 if (0 < MAX_SEC && MAX_SEC < remaining.tv_sec) {
447 remaining.tv_sec = MAX_SEC;
448 remaining.tv_nsec = 0;
449 }
450 ts = &remaining;
451 break;
452 default:
453 LOG_ALWAYS_FATAL("waitStreamEndDone() timeout=%d", timeout);
454 ts = NULL;
455 break;
456 }
457 int32_t old = android_atomic_and(~CBLK_FUTEX_WAKE, &cblk->mFutex);
458 if (!(old & CBLK_FUTEX_WAKE)) {
459 errno = 0;
460 (void) syscall(__NR_futex, &cblk->mFutex,
461 mClientInServer ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT, old & ~CBLK_FUTEX_WAKE, ts);
462 switch (errno) {
463 case 0: // normal wakeup by server, or by binderDied()
464 case EWOULDBLOCK: // benign race condition with server
465 case EINTR: // wait was interrupted by signal or other spurious wakeup
466 case ETIMEDOUT: // time-out expired
467 break;
468 default:
469 status = errno;
470 ALOGE("%s unexpected error %s", __func__, strerror(status));
471 goto end;
472 }
473 }
474 }
475
476 end:
477 if (requested == NULL) {
478 requested = &kNonBlocking;
479 }
480 return status;
481 }
482
483 // ---------------------------------------------------------------------------
484
StaticAudioTrackClientProxy(audio_track_cblk_t * cblk,void * buffers,size_t frameCount,size_t frameSize)485 StaticAudioTrackClientProxy::StaticAudioTrackClientProxy(audio_track_cblk_t* cblk, void *buffers,
486 size_t frameCount, size_t frameSize)
487 : AudioTrackClientProxy(cblk, buffers, frameCount, frameSize),
488 mMutator(&cblk->u.mStatic.mSingleStateQueue), mBufferPosition(0)
489 {
490 }
491
flush()492 void StaticAudioTrackClientProxy::flush()
493 {
494 LOG_ALWAYS_FATAL("static flush");
495 }
496
setLoop(size_t loopStart,size_t loopEnd,int loopCount)497 void StaticAudioTrackClientProxy::setLoop(size_t loopStart, size_t loopEnd, int loopCount)
498 {
499 // This can only happen on a 64-bit client
500 if (loopStart > UINT32_MAX || loopEnd > UINT32_MAX) {
501 // FIXME Should return an error status
502 return;
503 }
504 StaticAudioTrackState newState;
505 newState.mLoopStart = (uint32_t) loopStart;
506 newState.mLoopEnd = (uint32_t) loopEnd;
507 newState.mLoopCount = loopCount;
508 size_t bufferPosition;
509 if (loopCount == 0 || (bufferPosition = getBufferPosition()) >= loopEnd) {
510 bufferPosition = loopStart;
511 }
512 mBufferPosition = bufferPosition; // snapshot buffer position until loop is acknowledged.
513 (void) mMutator.push(newState);
514 }
515
getBufferPosition()516 size_t StaticAudioTrackClientProxy::getBufferPosition()
517 {
518 size_t bufferPosition;
519 if (mMutator.ack()) {
520 bufferPosition = (size_t) mCblk->u.mStatic.mBufferPosition;
521 if (bufferPosition > mFrameCount) {
522 bufferPosition = mFrameCount;
523 }
524 } else {
525 bufferPosition = mBufferPosition;
526 }
527 return bufferPosition;
528 }
529
530 // ---------------------------------------------------------------------------
531
ServerProxy(audio_track_cblk_t * cblk,void * buffers,size_t frameCount,size_t frameSize,bool isOut,bool clientInServer)532 ServerProxy::ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
533 size_t frameSize, bool isOut, bool clientInServer)
534 : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer),
535 mAvailToClient(0), mFlush(0)
536 {
537 }
538
obtainBuffer(Buffer * buffer,bool ackFlush)539 status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
540 {
541 LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0);
542 if (mIsShutdown) {
543 goto no_init;
544 }
545 {
546 audio_track_cblk_t* cblk = mCblk;
547 // compute number of frames available to write (AudioTrack) or read (AudioRecord),
548 // or use previous cached value from framesReady(), with added barrier if it omits.
549 int32_t front;
550 int32_t rear;
551 // See notes on barriers at ClientProxy::obtainBuffer()
552 if (mIsOut) {
553 int32_t flush = cblk->u.mStreaming.mFlush;
554 rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
555 front = cblk->u.mStreaming.mFront;
556 if (flush != mFlush) {
557 // effectively obtain then release whatever is in the buffer
558 size_t mask = (mFrameCountP2 << 1) - 1;
559 int32_t newFront = (front & ~mask) | (flush & mask);
560 ssize_t filled = rear - newFront;
561 // Rather than shutting down on a corrupt flush, just treat it as a full flush
562 if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
563 ALOGE("mFlush %#x -> %#x, front %#x, rear %#x, mask %#x, newFront %#x, filled %d=%#x",
564 mFlush, flush, front, rear, mask, newFront, filled, filled);
565 newFront = rear;
566 }
567 mFlush = flush;
568 android_atomic_release_store(newFront, &cblk->u.mStreaming.mFront);
569 // There is no danger from a false positive, so err on the side of caution
570 if (true /*front != newFront*/) {
571 int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
572 if (!(old & CBLK_FUTEX_WAKE)) {
573 (void) syscall(__NR_futex, &cblk->mFutex,
574 mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
575 }
576 }
577 front = newFront;
578 }
579 } else {
580 front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
581 rear = cblk->u.mStreaming.mRear;
582 }
583 ssize_t filled = rear - front;
584 // pipe should not already be overfull
585 if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
586 ALOGE("Shared memory control block is corrupt (filled=%zd); shutting down", filled);
587 mIsShutdown = true;
588 }
589 if (mIsShutdown) {
590 goto no_init;
591 }
592 // don't allow filling pipe beyond the nominal size
593 size_t availToServer;
594 if (mIsOut) {
595 availToServer = filled;
596 mAvailToClient = mFrameCount - filled;
597 } else {
598 availToServer = mFrameCount - filled;
599 mAvailToClient = filled;
600 }
601 // 'availToServer' may be non-contiguous, so return only the first contiguous chunk
602 size_t part1;
603 if (mIsOut) {
604 front &= mFrameCountP2 - 1;
605 part1 = mFrameCountP2 - front;
606 } else {
607 rear &= mFrameCountP2 - 1;
608 part1 = mFrameCountP2 - rear;
609 }
610 if (part1 > availToServer) {
611 part1 = availToServer;
612 }
613 size_t ask = buffer->mFrameCount;
614 if (part1 > ask) {
615 part1 = ask;
616 }
617 // is assignment redundant in some cases?
618 buffer->mFrameCount = part1;
619 buffer->mRaw = part1 > 0 ?
620 &((char *) mBuffers)[(mIsOut ? front : rear) * mFrameSize] : NULL;
621 buffer->mNonContig = availToServer - part1;
622 // After flush(), allow releaseBuffer() on a previously obtained buffer;
623 // see "Acknowledge any pending flush()" in audioflinger/Tracks.cpp.
624 if (!ackFlush) {
625 mUnreleased = part1;
626 }
627 return part1 > 0 ? NO_ERROR : WOULD_BLOCK;
628 }
629 no_init:
630 buffer->mFrameCount = 0;
631 buffer->mRaw = NULL;
632 buffer->mNonContig = 0;
633 mUnreleased = 0;
634 return NO_INIT;
635 }
636
releaseBuffer(Buffer * buffer)637 void ServerProxy::releaseBuffer(Buffer* buffer)
638 {
639 LOG_ALWAYS_FATAL_IF(buffer == NULL);
640 size_t stepCount = buffer->mFrameCount;
641 if (stepCount == 0 || mIsShutdown) {
642 // prevent accidental re-use of buffer
643 buffer->mFrameCount = 0;
644 buffer->mRaw = NULL;
645 buffer->mNonContig = 0;
646 return;
647 }
648 LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased && mUnreleased <= mFrameCount));
649 mUnreleased -= stepCount;
650 audio_track_cblk_t* cblk = mCblk;
651 if (mIsOut) {
652 int32_t front = cblk->u.mStreaming.mFront;
653 android_atomic_release_store(stepCount + front, &cblk->u.mStreaming.mFront);
654 } else {
655 int32_t rear = cblk->u.mStreaming.mRear;
656 android_atomic_release_store(stepCount + rear, &cblk->u.mStreaming.mRear);
657 }
658
659 cblk->mServer += stepCount;
660
661 size_t half = mFrameCount / 2;
662 if (half == 0) {
663 half = 1;
664 }
665 size_t minimum = (size_t) cblk->mMinimum;
666 if (minimum == 0) {
667 minimum = mIsOut ? half : 1;
668 } else if (minimum > half) {
669 minimum = half;
670 }
671 // FIXME AudioRecord wakeup needs to be optimized; it currently wakes up client every time
672 if (!mIsOut || (mAvailToClient + stepCount >= minimum)) {
673 ALOGV("mAvailToClient=%zu stepCount=%zu minimum=%zu", mAvailToClient, stepCount, minimum);
674 int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
675 if (!(old & CBLK_FUTEX_WAKE)) {
676 (void) syscall(__NR_futex, &cblk->mFutex,
677 mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
678 }
679 }
680
681 buffer->mFrameCount = 0;
682 buffer->mRaw = NULL;
683 buffer->mNonContig = 0;
684 }
685
686 // ---------------------------------------------------------------------------
687
framesReady()688 size_t AudioTrackServerProxy::framesReady()
689 {
690 LOG_ALWAYS_FATAL_IF(!mIsOut);
691
692 if (mIsShutdown) {
693 return 0;
694 }
695 audio_track_cblk_t* cblk = mCblk;
696
697 int32_t flush = cblk->u.mStreaming.mFlush;
698 if (flush != mFlush) {
699 // FIXME should return an accurate value, but over-estimate is better than under-estimate
700 return mFrameCount;
701 }
702 // the acquire might not be necessary since not doing a subsequent read
703 int32_t rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
704 ssize_t filled = rear - cblk->u.mStreaming.mFront;
705 // pipe should not already be overfull
706 if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
707 ALOGE("Shared memory control block is corrupt (filled=%zd); shutting down", filled);
708 mIsShutdown = true;
709 return 0;
710 }
711 // cache this value for later use by obtainBuffer(), with added barrier
712 // and racy if called by normal mixer thread
713 // ignores flush(), so framesReady() may report a larger mFrameCount than obtainBuffer()
714 return filled;
715 }
716
setStreamEndDone()717 bool AudioTrackServerProxy::setStreamEndDone() {
718 audio_track_cblk_t* cblk = mCblk;
719 bool old =
720 (android_atomic_or(CBLK_STREAM_END_DONE, &cblk->mFlags) & CBLK_STREAM_END_DONE) != 0;
721 if (!old) {
722 (void) syscall(__NR_futex, &cblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
723 1);
724 }
725 return old;
726 }
727
tallyUnderrunFrames(uint32_t frameCount)728 void AudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount)
729 {
730 audio_track_cblk_t* cblk = mCblk;
731 cblk->u.mStreaming.mUnderrunFrames += frameCount;
732
733 // FIXME also wake futex so that underrun is noticed more quickly
734 (void) android_atomic_or(CBLK_UNDERRUN, &cblk->mFlags);
735 }
736
737 // ---------------------------------------------------------------------------
738
StaticAudioTrackServerProxy(audio_track_cblk_t * cblk,void * buffers,size_t frameCount,size_t frameSize)739 StaticAudioTrackServerProxy::StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers,
740 size_t frameCount, size_t frameSize)
741 : AudioTrackServerProxy(cblk, buffers, frameCount, frameSize),
742 mObserver(&cblk->u.mStatic.mSingleStateQueue), mPosition(0),
743 mFramesReadySafe(frameCount), mFramesReady(frameCount),
744 mFramesReadyIsCalledByMultipleThreads(false)
745 {
746 mState.mLoopStart = 0;
747 mState.mLoopEnd = 0;
748 mState.mLoopCount = 0;
749 }
750
framesReadyIsCalledByMultipleThreads()751 void StaticAudioTrackServerProxy::framesReadyIsCalledByMultipleThreads()
752 {
753 mFramesReadyIsCalledByMultipleThreads = true;
754 }
755
framesReady()756 size_t StaticAudioTrackServerProxy::framesReady()
757 {
758 // Can't call pollPosition() from multiple threads.
759 if (!mFramesReadyIsCalledByMultipleThreads) {
760 (void) pollPosition();
761 }
762 return mFramesReadySafe;
763 }
764
pollPosition()765 ssize_t StaticAudioTrackServerProxy::pollPosition()
766 {
767 size_t position = mPosition;
768 StaticAudioTrackState state;
769 if (mObserver.poll(state)) {
770 bool valid = false;
771 size_t loopStart = state.mLoopStart;
772 size_t loopEnd = state.mLoopEnd;
773 if (state.mLoopCount == 0) {
774 if (loopStart > mFrameCount) {
775 loopStart = mFrameCount;
776 }
777 // ignore loopEnd
778 mPosition = position = loopStart;
779 mFramesReady = mFrameCount - mPosition;
780 mState.mLoopCount = 0;
781 valid = true;
782 } else if (state.mLoopCount >= -1) {
783 if (loopStart < loopEnd && loopEnd <= mFrameCount &&
784 loopEnd - loopStart >= MIN_LOOP) {
785 // If the current position is greater than the end of the loop
786 // we "wrap" to the loop start. This might cause an audible pop.
787 if (position >= loopEnd) {
788 mPosition = position = loopStart;
789 }
790 if (state.mLoopCount == -1) {
791 mFramesReady = INT64_MAX;
792 } else {
793 // mFramesReady is 64 bits to handle the effective number of frames
794 // that the static audio track contains, including loops.
795 // TODO: Later consider fixing overflow, but does not seem needed now
796 // as will not overflow if loopStart and loopEnd are Java "ints".
797 mFramesReady = int64_t(state.mLoopCount) * (loopEnd - loopStart)
798 + mFrameCount - mPosition;
799 }
800 mState = state;
801 valid = true;
802 }
803 }
804 if (!valid || mPosition > mFrameCount) {
805 ALOGE("%s client pushed an invalid state, shutting down", __func__);
806 mIsShutdown = true;
807 return (ssize_t) NO_INIT;
808 }
809 mFramesReadySafe = clampToSize(mFramesReady);
810 // This may overflow, but client is not supposed to rely on it
811 mCblk->u.mStatic.mBufferPosition = (uint32_t) position;
812 }
813 return (ssize_t) position;
814 }
815
obtainBuffer(Buffer * buffer,bool ackFlush __unused)816 status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush __unused)
817 {
818 if (mIsShutdown) {
819 buffer->mFrameCount = 0;
820 buffer->mRaw = NULL;
821 buffer->mNonContig = 0;
822 mUnreleased = 0;
823 return NO_INIT;
824 }
825 ssize_t positionOrStatus = pollPosition();
826 if (positionOrStatus < 0) {
827 buffer->mFrameCount = 0;
828 buffer->mRaw = NULL;
829 buffer->mNonContig = 0;
830 mUnreleased = 0;
831 return (status_t) positionOrStatus;
832 }
833 size_t position = (size_t) positionOrStatus;
834 size_t end = mState.mLoopCount != 0 ? mState.mLoopEnd : mFrameCount;
835 size_t avail;
836 if (position < end) {
837 avail = end - position;
838 size_t wanted = buffer->mFrameCount;
839 if (avail < wanted) {
840 buffer->mFrameCount = avail;
841 } else {
842 avail = wanted;
843 }
844 buffer->mRaw = &((char *) mBuffers)[position * mFrameSize];
845 } else {
846 avail = 0;
847 buffer->mFrameCount = 0;
848 buffer->mRaw = NULL;
849 }
850 // As mFramesReady is the total remaining frames in the static audio track,
851 // it is always larger or equal to avail.
852 LOG_ALWAYS_FATAL_IF(mFramesReady < avail);
853 buffer->mNonContig = mFramesReady == INT64_MAX ? SIZE_MAX : clampToSize(mFramesReady - avail);
854 mUnreleased = avail;
855 return NO_ERROR;
856 }
857
releaseBuffer(Buffer * buffer)858 void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer)
859 {
860 size_t stepCount = buffer->mFrameCount;
861 LOG_ALWAYS_FATAL_IF(!(stepCount <= mFramesReady));
862 LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased));
863 if (stepCount == 0) {
864 // prevent accidental re-use of buffer
865 buffer->mRaw = NULL;
866 buffer->mNonContig = 0;
867 return;
868 }
869 mUnreleased -= stepCount;
870 audio_track_cblk_t* cblk = mCblk;
871 size_t position = mPosition;
872 size_t newPosition = position + stepCount;
873 int32_t setFlags = 0;
874 if (!(position <= newPosition && newPosition <= mFrameCount)) {
875 ALOGW("%s newPosition %zu outside [%zu, %zu]", __func__, newPosition, position, mFrameCount);
876 newPosition = mFrameCount;
877 } else if (mState.mLoopCount != 0 && newPosition == mState.mLoopEnd) {
878 newPosition = mState.mLoopStart;
879 if (mState.mLoopCount == -1 || --mState.mLoopCount != 0) {
880 setFlags = CBLK_LOOP_CYCLE;
881 } else {
882 setFlags = CBLK_LOOP_FINAL;
883 }
884 }
885 if (newPosition == mFrameCount) {
886 setFlags |= CBLK_BUFFER_END;
887 }
888 mPosition = newPosition;
889 if (mFramesReady != INT64_MAX) {
890 mFramesReady -= stepCount;
891 }
892 mFramesReadySafe = clampToSize(mFramesReady);
893
894 cblk->mServer += stepCount;
895 // This may overflow, but client is not supposed to rely on it
896 cblk->u.mStatic.mBufferPosition = (uint32_t) newPosition;
897 if (setFlags != 0) {
898 (void) android_atomic_or(setFlags, &cblk->mFlags);
899 // this would be a good place to wake a futex
900 }
901
902 buffer->mFrameCount = 0;
903 buffer->mRaw = NULL;
904 buffer->mNonContig = 0;
905 }
906
tallyUnderrunFrames(uint32_t frameCount __unused)907 void StaticAudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount __unused)
908 {
909 // Unlike AudioTrackServerProxy::tallyUnderrunFrames() used for streaming tracks,
910 // we don't have a location to count underrun frames. The underrun frame counter
911 // only exists in AudioTrackSharedStreaming. Fortunately, underruns are not
912 // possible for static buffer tracks other than at end of buffer, so this is not a loss.
913
914 // FIXME also wake futex so that underrun is noticed more quickly
915 (void) android_atomic_or(CBLK_UNDERRUN, &mCblk->mFlags);
916 }
917
918 // ---------------------------------------------------------------------------
919
920 } // namespace android
921