• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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