• 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 extern "C" {
23 #include "../private/bionic_futex.h"
24 }
25 
26 namespace android {
27 
audio_track_cblk_t()28 audio_track_cblk_t::audio_track_cblk_t()
29     : mServer(0), frameCount_(0), mFutex(0), mMinimum(0),
30     mVolumeLR(0x10001000), mSampleRate(0), mSendLevel(0), mFlags(0)
31 {
32     memset(&u, 0, sizeof(u));
33 }
34 
35 // ---------------------------------------------------------------------------
36 
Proxy(audio_track_cblk_t * cblk,void * buffers,size_t frameCount,size_t frameSize,bool isOut,bool clientInServer)37 Proxy::Proxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize,
38         bool isOut, bool clientInServer)
39     : mCblk(cblk), mBuffers(buffers), mFrameCount(frameCount), mFrameSize(frameSize),
40       mFrameCountP2(roundup(frameCount)), mIsOut(isOut), mClientInServer(clientInServer),
41       mIsShutdown(false), mUnreleased(0)
42 {
43 }
44 
45 // ---------------------------------------------------------------------------
46 
ClientProxy(audio_track_cblk_t * cblk,void * buffers,size_t frameCount,size_t frameSize,bool isOut,bool clientInServer)47 ClientProxy::ClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
48         size_t frameSize, bool isOut, bool clientInServer)
49     : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer), mEpoch(0)
50 {
51 }
52 
53 const struct timespec ClientProxy::kForever = {INT_MAX /*tv_sec*/, 0 /*tv_nsec*/};
54 const struct timespec ClientProxy::kNonBlocking = {0 /*tv_sec*/, 0 /*tv_nsec*/};
55 
56 #define MEASURE_NS 10000000 // attempt to provide accurate timeouts if requested >= MEASURE_NS
57 
58 // To facilitate quicker recovery from server failure, this value limits the timeout per each futex
59 // wait.  However it does not protect infinite timeouts.  If defined to be zero, there is no limit.
60 // FIXME May not be compatible with audio tunneling requirements where timeout should be in the
61 // order of minutes.
62 #define MAX_SEC    5
63 
obtainBuffer(Buffer * buffer,const struct timespec * requested,struct timespec * elapsed)64 status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *requested,
65         struct timespec *elapsed)
66 {
67     LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0);
68     struct timespec total;          // total elapsed time spent waiting
69     total.tv_sec = 0;
70     total.tv_nsec = 0;
71     bool measure = elapsed != NULL; // whether to measure total elapsed time spent waiting
72 
73     status_t status;
74     enum {
75         TIMEOUT_ZERO,       // requested == NULL || *requested == 0
76         TIMEOUT_INFINITE,   // *requested == infinity
77         TIMEOUT_FINITE,     // 0 < *requested < infinity
78         TIMEOUT_CONTINUE,   // additional chances after TIMEOUT_FINITE
79     } timeout;
80     if (requested == NULL) {
81         timeout = TIMEOUT_ZERO;
82     } else if (requested->tv_sec == 0 && requested->tv_nsec == 0) {
83         timeout = TIMEOUT_ZERO;
84     } else if (requested->tv_sec == INT_MAX) {
85         timeout = TIMEOUT_INFINITE;
86     } else {
87         timeout = TIMEOUT_FINITE;
88         if (requested->tv_sec > 0 || requested->tv_nsec >= MEASURE_NS) {
89             measure = true;
90         }
91     }
92     struct timespec before;
93     bool beforeIsValid = false;
94     audio_track_cblk_t* cblk = mCblk;
95     bool ignoreInitialPendingInterrupt = true;
96     // check for shared memory corruption
97     if (mIsShutdown) {
98         status = NO_INIT;
99         goto end;
100     }
101     for (;;) {
102         int32_t flags = android_atomic_and(~CBLK_INTERRUPT, &cblk->mFlags);
103         // check for track invalidation by server, or server death detection
104         if (flags & CBLK_INVALID) {
105             ALOGV("Track invalidated");
106             status = DEAD_OBJECT;
107             goto end;
108         }
109         // check for obtainBuffer interrupted by client
110         if (!ignoreInitialPendingInterrupt && (flags & CBLK_INTERRUPT)) {
111             ALOGV("obtainBuffer() interrupted by client");
112             status = -EINTR;
113             goto end;
114         }
115         ignoreInitialPendingInterrupt = false;
116         // compute number of frames available to write (AudioTrack) or read (AudioRecord)
117         int32_t front;
118         int32_t rear;
119         if (mIsOut) {
120             // The barrier following the read of mFront is probably redundant.
121             // We're about to perform a conditional branch based on 'filled',
122             // which will force the processor to observe the read of mFront
123             // prior to allowing data writes starting at mRaw.
124             // However, the processor may support speculative execution,
125             // and be unable to undo speculative writes into shared memory.
126             // The barrier will prevent such speculative execution.
127             front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
128             rear = cblk->u.mStreaming.mRear;
129         } else {
130             // On the other hand, this barrier is required.
131             rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
132             front = cblk->u.mStreaming.mFront;
133         }
134         ssize_t filled = rear - front;
135         // pipe should not be overfull
136         if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
137             ALOGE("Shared memory control block is corrupt (filled=%d); shutting down", filled);
138             mIsShutdown = true;
139             status = NO_INIT;
140             goto end;
141         }
142         // don't allow filling pipe beyond the nominal size
143         size_t avail = mIsOut ? mFrameCount - filled : filled;
144         if (avail > 0) {
145             // 'avail' may be non-contiguous, so return only the first contiguous chunk
146             size_t part1;
147             if (mIsOut) {
148                 rear &= mFrameCountP2 - 1;
149                 part1 = mFrameCountP2 - rear;
150             } else {
151                 front &= mFrameCountP2 - 1;
152                 part1 = mFrameCountP2 - front;
153             }
154             if (part1 > avail) {
155                 part1 = avail;
156             }
157             if (part1 > buffer->mFrameCount) {
158                 part1 = buffer->mFrameCount;
159             }
160             buffer->mFrameCount = part1;
161             buffer->mRaw = part1 > 0 ?
162                     &((char *) mBuffers)[(mIsOut ? rear : front) * mFrameSize] : NULL;
163             buffer->mNonContig = avail - part1;
164             mUnreleased = part1;
165             status = NO_ERROR;
166             break;
167         }
168         struct timespec remaining;
169         const struct timespec *ts;
170         switch (timeout) {
171         case TIMEOUT_ZERO:
172             status = WOULD_BLOCK;
173             goto end;
174         case TIMEOUT_INFINITE:
175             ts = NULL;
176             break;
177         case TIMEOUT_FINITE:
178             timeout = TIMEOUT_CONTINUE;
179             if (MAX_SEC == 0) {
180                 ts = requested;
181                 break;
182             }
183             // fall through
184         case TIMEOUT_CONTINUE:
185             // FIXME we do not retry if requested < 10ms? needs documentation on this state machine
186             if (!measure || requested->tv_sec < total.tv_sec ||
187                     (requested->tv_sec == total.tv_sec && requested->tv_nsec <= total.tv_nsec)) {
188                 status = TIMED_OUT;
189                 goto end;
190             }
191             remaining.tv_sec = requested->tv_sec - total.tv_sec;
192             if ((remaining.tv_nsec = requested->tv_nsec - total.tv_nsec) < 0) {
193                 remaining.tv_nsec += 1000000000;
194                 remaining.tv_sec++;
195             }
196             if (0 < MAX_SEC && MAX_SEC < remaining.tv_sec) {
197                 remaining.tv_sec = MAX_SEC;
198                 remaining.tv_nsec = 0;
199             }
200             ts = &remaining;
201             break;
202         default:
203             LOG_FATAL("obtainBuffer() timeout=%d", timeout);
204             ts = NULL;
205             break;
206         }
207         int32_t old = android_atomic_and(~CBLK_FUTEX_WAKE, &cblk->mFutex);
208         if (!(old & CBLK_FUTEX_WAKE)) {
209             int rc;
210             if (measure && !beforeIsValid) {
211                 clock_gettime(CLOCK_MONOTONIC, &before);
212                 beforeIsValid = true;
213             }
214             int ret = __futex_syscall4(&cblk->mFutex,
215                     mClientInServer ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT, old & ~CBLK_FUTEX_WAKE, ts);
216             // update total elapsed time spent waiting
217             if (measure) {
218                 struct timespec after;
219                 clock_gettime(CLOCK_MONOTONIC, &after);
220                 total.tv_sec += after.tv_sec - before.tv_sec;
221                 long deltaNs = after.tv_nsec - before.tv_nsec;
222                 if (deltaNs < 0) {
223                     deltaNs += 1000000000;
224                     total.tv_sec--;
225                 }
226                 if ((total.tv_nsec += deltaNs) >= 1000000000) {
227                     total.tv_nsec -= 1000000000;
228                     total.tv_sec++;
229                 }
230                 before = after;
231                 beforeIsValid = true;
232             }
233             switch (ret) {
234             case 0:             // normal wakeup by server, or by binderDied()
235             case -EWOULDBLOCK:  // benign race condition with server
236             case -EINTR:        // wait was interrupted by signal or other spurious wakeup
237             case -ETIMEDOUT:    // time-out expired
238                 // FIXME these error/non-0 status are being dropped
239                 break;
240             default:
241                 ALOGE("%s unexpected error %d", __func__, ret);
242                 status = -ret;
243                 goto end;
244             }
245         }
246     }
247 
248 end:
249     if (status != NO_ERROR) {
250         buffer->mFrameCount = 0;
251         buffer->mRaw = NULL;
252         buffer->mNonContig = 0;
253         mUnreleased = 0;
254     }
255     if (elapsed != NULL) {
256         *elapsed = total;
257     }
258     if (requested == NULL) {
259         requested = &kNonBlocking;
260     }
261     if (measure) {
262         ALOGV("requested %ld.%03ld elapsed %ld.%03ld",
263               requested->tv_sec, requested->tv_nsec / 1000000,
264               total.tv_sec, total.tv_nsec / 1000000);
265     }
266     return status;
267 }
268 
releaseBuffer(Buffer * buffer)269 void ClientProxy::releaseBuffer(Buffer* buffer)
270 {
271     LOG_ALWAYS_FATAL_IF(buffer == NULL);
272     size_t stepCount = buffer->mFrameCount;
273     if (stepCount == 0 || mIsShutdown) {
274         // prevent accidental re-use of buffer
275         buffer->mFrameCount = 0;
276         buffer->mRaw = NULL;
277         buffer->mNonContig = 0;
278         return;
279     }
280     LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased && mUnreleased <= mFrameCount));
281     mUnreleased -= stepCount;
282     audio_track_cblk_t* cblk = mCblk;
283     // Both of these barriers are required
284     if (mIsOut) {
285         int32_t rear = cblk->u.mStreaming.mRear;
286         android_atomic_release_store(stepCount + rear, &cblk->u.mStreaming.mRear);
287     } else {
288         int32_t front = cblk->u.mStreaming.mFront;
289         android_atomic_release_store(stepCount + front, &cblk->u.mStreaming.mFront);
290     }
291 }
292 
binderDied()293 void ClientProxy::binderDied()
294 {
295     audio_track_cblk_t* cblk = mCblk;
296     if (!(android_atomic_or(CBLK_INVALID, &cblk->mFlags) & CBLK_INVALID)) {
297         // it seems that a FUTEX_WAKE_PRIVATE will not wake a FUTEX_WAIT, even within same process
298         (void) __futex_syscall3(&cblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
299                 1);
300     }
301 }
302 
interrupt()303 void ClientProxy::interrupt()
304 {
305     audio_track_cblk_t* cblk = mCblk;
306     if (!(android_atomic_or(CBLK_INTERRUPT, &cblk->mFlags) & CBLK_INTERRUPT)) {
307         (void) __futex_syscall3(&cblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
308                 1);
309     }
310 }
311 
getMisalignment()312 size_t ClientProxy::getMisalignment()
313 {
314     audio_track_cblk_t* cblk = mCblk;
315     return (mFrameCountP2 - (mIsOut ? cblk->u.mStreaming.mRear : cblk->u.mStreaming.mFront)) &
316             (mFrameCountP2 - 1);
317 }
318 
getFramesFilled()319 size_t ClientProxy::getFramesFilled() {
320     audio_track_cblk_t* cblk = mCblk;
321     int32_t front;
322     int32_t rear;
323 
324     if (mIsOut) {
325         front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
326         rear = cblk->u.mStreaming.mRear;
327     } else {
328         rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
329         front = cblk->u.mStreaming.mFront;
330     }
331     ssize_t filled = rear - front;
332     // pipe should not be overfull
333     if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
334         ALOGE("Shared memory control block is corrupt (filled=%d); shutting down", filled);
335         return 0;
336     }
337     return (size_t)filled;
338 }
339 
340 // ---------------------------------------------------------------------------
341 
flush()342 void AudioTrackClientProxy::flush()
343 {
344     mCblk->u.mStreaming.mFlush++;
345 }
346 
clearStreamEndDone()347 bool AudioTrackClientProxy::clearStreamEndDone() {
348     return (android_atomic_and(~CBLK_STREAM_END_DONE, &mCblk->mFlags) & CBLK_STREAM_END_DONE) != 0;
349 }
350 
getStreamEndDone() const351 bool AudioTrackClientProxy::getStreamEndDone() const {
352     return (mCblk->mFlags & CBLK_STREAM_END_DONE) != 0;
353 }
354 
waitStreamEndDone(const struct timespec * requested)355 status_t AudioTrackClientProxy::waitStreamEndDone(const struct timespec *requested)
356 {
357     struct timespec total;          // total elapsed time spent waiting
358     total.tv_sec = 0;
359     total.tv_nsec = 0;
360     audio_track_cblk_t* cblk = mCblk;
361     status_t status;
362     enum {
363         TIMEOUT_ZERO,       // requested == NULL || *requested == 0
364         TIMEOUT_INFINITE,   // *requested == infinity
365         TIMEOUT_FINITE,     // 0 < *requested < infinity
366         TIMEOUT_CONTINUE,   // additional chances after TIMEOUT_FINITE
367     } timeout;
368     if (requested == NULL) {
369         timeout = TIMEOUT_ZERO;
370     } else if (requested->tv_sec == 0 && requested->tv_nsec == 0) {
371         timeout = TIMEOUT_ZERO;
372     } else if (requested->tv_sec == INT_MAX) {
373         timeout = TIMEOUT_INFINITE;
374     } else {
375         timeout = TIMEOUT_FINITE;
376     }
377     for (;;) {
378         int32_t flags = android_atomic_and(~(CBLK_INTERRUPT|CBLK_STREAM_END_DONE), &cblk->mFlags);
379         // check for track invalidation by server, or server death detection
380         if (flags & CBLK_INVALID) {
381             ALOGV("Track invalidated");
382             status = DEAD_OBJECT;
383             goto end;
384         }
385         if (flags & CBLK_STREAM_END_DONE) {
386             ALOGV("stream end received");
387             status = NO_ERROR;
388             goto end;
389         }
390         // check for obtainBuffer interrupted by client
391         // check for obtainBuffer interrupted by client
392         if (flags & CBLK_INTERRUPT) {
393             ALOGV("waitStreamEndDone() interrupted by client");
394             status = -EINTR;
395             goto end;
396         }
397         struct timespec remaining;
398         const struct timespec *ts;
399         switch (timeout) {
400         case TIMEOUT_ZERO:
401             status = WOULD_BLOCK;
402             goto end;
403         case TIMEOUT_INFINITE:
404             ts = NULL;
405             break;
406         case TIMEOUT_FINITE:
407             timeout = TIMEOUT_CONTINUE;
408             if (MAX_SEC == 0) {
409                 ts = requested;
410                 break;
411             }
412             // fall through
413         case TIMEOUT_CONTINUE:
414             // FIXME we do not retry if requested < 10ms? needs documentation on this state machine
415             if (requested->tv_sec < total.tv_sec ||
416                     (requested->tv_sec == total.tv_sec && requested->tv_nsec <= total.tv_nsec)) {
417                 status = TIMED_OUT;
418                 goto end;
419             }
420             remaining.tv_sec = requested->tv_sec - total.tv_sec;
421             if ((remaining.tv_nsec = requested->tv_nsec - total.tv_nsec) < 0) {
422                 remaining.tv_nsec += 1000000000;
423                 remaining.tv_sec++;
424             }
425             if (0 < MAX_SEC && MAX_SEC < remaining.tv_sec) {
426                 remaining.tv_sec = MAX_SEC;
427                 remaining.tv_nsec = 0;
428             }
429             ts = &remaining;
430             break;
431         default:
432             LOG_FATAL("waitStreamEndDone() timeout=%d", timeout);
433             ts = NULL;
434             break;
435         }
436         int32_t old = android_atomic_and(~CBLK_FUTEX_WAKE, &cblk->mFutex);
437         if (!(old & CBLK_FUTEX_WAKE)) {
438             int rc;
439             int ret = __futex_syscall4(&cblk->mFutex,
440                     mClientInServer ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT, old & ~CBLK_FUTEX_WAKE, ts);
441             switch (ret) {
442             case 0:             // normal wakeup by server, or by binderDied()
443             case -EWOULDBLOCK:  // benign race condition with server
444             case -EINTR:        // wait was interrupted by signal or other spurious wakeup
445             case -ETIMEDOUT:    // time-out expired
446                 break;
447             default:
448                 ALOGE("%s unexpected error %d", __func__, ret);
449                 status = -ret;
450                 goto end;
451             }
452         }
453     }
454 
455 end:
456     if (requested == NULL) {
457         requested = &kNonBlocking;
458     }
459     return status;
460 }
461 
462 // ---------------------------------------------------------------------------
463 
StaticAudioTrackClientProxy(audio_track_cblk_t * cblk,void * buffers,size_t frameCount,size_t frameSize)464 StaticAudioTrackClientProxy::StaticAudioTrackClientProxy(audio_track_cblk_t* cblk, void *buffers,
465         size_t frameCount, size_t frameSize)
466     : AudioTrackClientProxy(cblk, buffers, frameCount, frameSize),
467       mMutator(&cblk->u.mStatic.mSingleStateQueue), mBufferPosition(0)
468 {
469 }
470 
flush()471 void StaticAudioTrackClientProxy::flush()
472 {
473     LOG_FATAL("static flush");
474 }
475 
setLoop(size_t loopStart,size_t loopEnd,int loopCount)476 void StaticAudioTrackClientProxy::setLoop(size_t loopStart, size_t loopEnd, int loopCount)
477 {
478     StaticAudioTrackState newState;
479     newState.mLoopStart = loopStart;
480     newState.mLoopEnd = loopEnd;
481     newState.mLoopCount = loopCount;
482     mBufferPosition = loopStart;
483     (void) mMutator.push(newState);
484 }
485 
getBufferPosition()486 size_t StaticAudioTrackClientProxy::getBufferPosition()
487 {
488     size_t bufferPosition;
489     if (mMutator.ack()) {
490         bufferPosition = mCblk->u.mStatic.mBufferPosition;
491         if (bufferPosition > mFrameCount) {
492             bufferPosition = mFrameCount;
493         }
494     } else {
495         bufferPosition = mBufferPosition;
496     }
497     return bufferPosition;
498 }
499 
500 // ---------------------------------------------------------------------------
501 
ServerProxy(audio_track_cblk_t * cblk,void * buffers,size_t frameCount,size_t frameSize,bool isOut,bool clientInServer)502 ServerProxy::ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
503         size_t frameSize, bool isOut, bool clientInServer)
504     : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer),
505       mAvailToClient(0), mFlush(0)
506 {
507 }
508 
obtainBuffer(Buffer * buffer,bool ackFlush)509 status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
510 {
511     LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0);
512     if (mIsShutdown) {
513         goto no_init;
514     }
515     {
516     audio_track_cblk_t* cblk = mCblk;
517     // compute number of frames available to write (AudioTrack) or read (AudioRecord),
518     // or use previous cached value from framesReady(), with added barrier if it omits.
519     int32_t front;
520     int32_t rear;
521     // See notes on barriers at ClientProxy::obtainBuffer()
522     if (mIsOut) {
523         int32_t flush = cblk->u.mStreaming.mFlush;
524         rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
525         front = cblk->u.mStreaming.mFront;
526         if (flush != mFlush) {
527             mFlush = flush;
528             // effectively obtain then release whatever is in the buffer
529             android_atomic_release_store(rear, &cblk->u.mStreaming.mFront);
530             if (front != rear) {
531                 int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
532                 if (!(old & CBLK_FUTEX_WAKE)) {
533                     (void) __futex_syscall3(&cblk->mFutex,
534                             mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
535                 }
536             }
537             front = rear;
538         }
539     } else {
540         front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
541         rear = cblk->u.mStreaming.mRear;
542     }
543     ssize_t filled = rear - front;
544     // pipe should not already be overfull
545     if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
546         ALOGE("Shared memory control block is corrupt (filled=%d); shutting down", filled);
547         mIsShutdown = true;
548     }
549     if (mIsShutdown) {
550         goto no_init;
551     }
552     // don't allow filling pipe beyond the nominal size
553     size_t availToServer;
554     if (mIsOut) {
555         availToServer = filled;
556         mAvailToClient = mFrameCount - filled;
557     } else {
558         availToServer = mFrameCount - filled;
559         mAvailToClient = filled;
560     }
561     // 'availToServer' may be non-contiguous, so return only the first contiguous chunk
562     size_t part1;
563     if (mIsOut) {
564         front &= mFrameCountP2 - 1;
565         part1 = mFrameCountP2 - front;
566     } else {
567         rear &= mFrameCountP2 - 1;
568         part1 = mFrameCountP2 - rear;
569     }
570     if (part1 > availToServer) {
571         part1 = availToServer;
572     }
573     size_t ask = buffer->mFrameCount;
574     if (part1 > ask) {
575         part1 = ask;
576     }
577     // is assignment redundant in some cases?
578     buffer->mFrameCount = part1;
579     buffer->mRaw = part1 > 0 ?
580             &((char *) mBuffers)[(mIsOut ? front : rear) * mFrameSize] : NULL;
581     buffer->mNonContig = availToServer - part1;
582     // After flush(), allow releaseBuffer() on a previously obtained buffer;
583     // see "Acknowledge any pending flush()" in audioflinger/Tracks.cpp.
584     if (!ackFlush) {
585         mUnreleased = part1;
586     }
587     return part1 > 0 ? NO_ERROR : WOULD_BLOCK;
588     }
589 no_init:
590     buffer->mFrameCount = 0;
591     buffer->mRaw = NULL;
592     buffer->mNonContig = 0;
593     mUnreleased = 0;
594     return NO_INIT;
595 }
596 
releaseBuffer(Buffer * buffer)597 void ServerProxy::releaseBuffer(Buffer* buffer)
598 {
599     LOG_ALWAYS_FATAL_IF(buffer == NULL);
600     size_t stepCount = buffer->mFrameCount;
601     if (stepCount == 0 || mIsShutdown) {
602         // prevent accidental re-use of buffer
603         buffer->mFrameCount = 0;
604         buffer->mRaw = NULL;
605         buffer->mNonContig = 0;
606         return;
607     }
608     LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased && mUnreleased <= mFrameCount));
609     mUnreleased -= stepCount;
610     audio_track_cblk_t* cblk = mCblk;
611     if (mIsOut) {
612         int32_t front = cblk->u.mStreaming.mFront;
613         android_atomic_release_store(stepCount + front, &cblk->u.mStreaming.mFront);
614     } else {
615         int32_t rear = cblk->u.mStreaming.mRear;
616         android_atomic_release_store(stepCount + rear, &cblk->u.mStreaming.mRear);
617     }
618 
619     mCblk->mServer += stepCount;
620 
621     size_t half = mFrameCount / 2;
622     if (half == 0) {
623         half = 1;
624     }
625     size_t minimum = cblk->mMinimum;
626     if (minimum == 0) {
627         minimum = mIsOut ? half : 1;
628     } else if (minimum > half) {
629         minimum = half;
630     }
631     // FIXME AudioRecord wakeup needs to be optimized; it currently wakes up client every time
632     if (!mIsOut || (mAvailToClient + stepCount >= minimum)) {
633         ALOGV("mAvailToClient=%u stepCount=%u minimum=%u", mAvailToClient, stepCount, minimum);
634         int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
635         if (!(old & CBLK_FUTEX_WAKE)) {
636             (void) __futex_syscall3(&cblk->mFutex,
637                     mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
638         }
639     }
640 
641     buffer->mFrameCount = 0;
642     buffer->mRaw = NULL;
643     buffer->mNonContig = 0;
644 }
645 
646 // ---------------------------------------------------------------------------
647 
framesReady()648 size_t AudioTrackServerProxy::framesReady()
649 {
650     LOG_ALWAYS_FATAL_IF(!mIsOut);
651 
652     if (mIsShutdown) {
653         return 0;
654     }
655     audio_track_cblk_t* cblk = mCblk;
656 
657     int32_t flush = cblk->u.mStreaming.mFlush;
658     if (flush != mFlush) {
659         return mFrameCount;
660     }
661     // the acquire might not be necessary since not doing a subsequent read
662     int32_t rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
663     ssize_t filled = rear - cblk->u.mStreaming.mFront;
664     // pipe should not already be overfull
665     if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
666         ALOGE("Shared memory control block is corrupt (filled=%d); shutting down", filled);
667         mIsShutdown = true;
668         return 0;
669     }
670     //  cache this value for later use by obtainBuffer(), with added barrier
671     //  and racy if called by normal mixer thread
672     // ignores flush(), so framesReady() may report a larger mFrameCount than obtainBuffer()
673     return filled;
674 }
675 
setStreamEndDone()676 bool  AudioTrackServerProxy::setStreamEndDone() {
677     bool old =
678             (android_atomic_or(CBLK_STREAM_END_DONE, &mCblk->mFlags) & CBLK_STREAM_END_DONE) != 0;
679     if (!old) {
680         (void) __futex_syscall3(&mCblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
681                 1);
682     }
683     return old;
684 }
685 
tallyUnderrunFrames(uint32_t frameCount)686 void AudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount)
687 {
688     mCblk->u.mStreaming.mUnderrunFrames += frameCount;
689 
690     // FIXME also wake futex so that underrun is noticed more quickly
691     (void) android_atomic_or(CBLK_UNDERRUN, &mCblk->mFlags);
692 }
693 
694 // ---------------------------------------------------------------------------
695 
StaticAudioTrackServerProxy(audio_track_cblk_t * cblk,void * buffers,size_t frameCount,size_t frameSize)696 StaticAudioTrackServerProxy::StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers,
697         size_t frameCount, size_t frameSize)
698     : AudioTrackServerProxy(cblk, buffers, frameCount, frameSize),
699       mObserver(&cblk->u.mStatic.mSingleStateQueue), mPosition(0),
700       mEnd(frameCount), mFramesReadyIsCalledByMultipleThreads(false)
701 {
702     mState.mLoopStart = 0;
703     mState.mLoopEnd = 0;
704     mState.mLoopCount = 0;
705 }
706 
framesReadyIsCalledByMultipleThreads()707 void StaticAudioTrackServerProxy::framesReadyIsCalledByMultipleThreads()
708 {
709     mFramesReadyIsCalledByMultipleThreads = true;
710 }
711 
framesReady()712 size_t StaticAudioTrackServerProxy::framesReady()
713 {
714     // FIXME
715     // This is racy if called by normal mixer thread,
716     // as we're reading 2 independent variables without a lock.
717     // Can't call mObserver.poll(), as we might be called from wrong thread.
718     // If looping is enabled, should return a higher number (since includes non-contiguous).
719     size_t position = mPosition;
720     if (!mFramesReadyIsCalledByMultipleThreads) {
721         ssize_t positionOrStatus = pollPosition();
722         if (positionOrStatus >= 0) {
723             position = (size_t) positionOrStatus;
724         }
725     }
726     size_t end = mEnd;
727     return position < end ? end - position : 0;
728 }
729 
pollPosition()730 ssize_t StaticAudioTrackServerProxy::pollPosition()
731 {
732     size_t position = mPosition;
733     StaticAudioTrackState state;
734     if (mObserver.poll(state)) {
735         bool valid = false;
736         size_t loopStart = state.mLoopStart;
737         size_t loopEnd = state.mLoopEnd;
738         if (state.mLoopCount == 0) {
739             if (loopStart > mFrameCount) {
740                 loopStart = mFrameCount;
741             }
742             // ignore loopEnd
743             mPosition = position = loopStart;
744             mEnd = mFrameCount;
745             mState.mLoopCount = 0;
746             valid = true;
747         } else {
748             if (loopStart < loopEnd && loopEnd <= mFrameCount &&
749                     loopEnd - loopStart >= MIN_LOOP) {
750                 if (!(loopStart <= position && position < loopEnd)) {
751                     mPosition = position = loopStart;
752                 }
753                 mEnd = loopEnd;
754                 mState = state;
755                 valid = true;
756             }
757         }
758         if (!valid) {
759             ALOGE("%s client pushed an invalid state, shutting down", __func__);
760             mIsShutdown = true;
761             return (ssize_t) NO_INIT;
762         }
763         mCblk->u.mStatic.mBufferPosition = position;
764     }
765     return (ssize_t) position;
766 }
767 
obtainBuffer(Buffer * buffer,bool ackFlush)768 status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
769 {
770     if (mIsShutdown) {
771         buffer->mFrameCount = 0;
772         buffer->mRaw = NULL;
773         buffer->mNonContig = 0;
774         mUnreleased = 0;
775         return NO_INIT;
776     }
777     ssize_t positionOrStatus = pollPosition();
778     if (positionOrStatus < 0) {
779         buffer->mFrameCount = 0;
780         buffer->mRaw = NULL;
781         buffer->mNonContig = 0;
782         mUnreleased = 0;
783         return (status_t) positionOrStatus;
784     }
785     size_t position = (size_t) positionOrStatus;
786     size_t avail;
787     if (position < mEnd) {
788         avail = mEnd - position;
789         size_t wanted = buffer->mFrameCount;
790         if (avail < wanted) {
791             buffer->mFrameCount = avail;
792         } else {
793             avail = wanted;
794         }
795         buffer->mRaw = &((char *) mBuffers)[position * mFrameSize];
796     } else {
797         avail = 0;
798         buffer->mFrameCount = 0;
799         buffer->mRaw = NULL;
800     }
801     buffer->mNonContig = 0;     // FIXME should be > 0 for looping
802     mUnreleased = avail;
803     return NO_ERROR;
804 }
805 
releaseBuffer(Buffer * buffer)806 void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer)
807 {
808     size_t stepCount = buffer->mFrameCount;
809     LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased));
810     if (stepCount == 0) {
811         // prevent accidental re-use of buffer
812         buffer->mRaw = NULL;
813         buffer->mNonContig = 0;
814         return;
815     }
816     mUnreleased -= stepCount;
817     audio_track_cblk_t* cblk = mCblk;
818     size_t position = mPosition;
819     size_t newPosition = position + stepCount;
820     int32_t setFlags = 0;
821     if (!(position <= newPosition && newPosition <= mFrameCount)) {
822         ALOGW("%s newPosition %u outside [%u, %u]", __func__, newPosition, position, mFrameCount);
823         newPosition = mFrameCount;
824     } else if (mState.mLoopCount != 0 && newPosition == mState.mLoopEnd) {
825         if (mState.mLoopCount == -1 || --mState.mLoopCount != 0) {
826             newPosition = mState.mLoopStart;
827             setFlags = CBLK_LOOP_CYCLE;
828         } else {
829             mEnd = mFrameCount;     // this is what allows playback to continue after the loop
830             setFlags = CBLK_LOOP_FINAL;
831         }
832     }
833     if (newPosition == mFrameCount) {
834         setFlags |= CBLK_BUFFER_END;
835     }
836     mPosition = newPosition;
837 
838     cblk->mServer += stepCount;
839     cblk->u.mStatic.mBufferPosition = newPosition;
840     if (setFlags != 0) {
841         (void) android_atomic_or(setFlags, &cblk->mFlags);
842         // this would be a good place to wake a futex
843     }
844 
845     buffer->mFrameCount = 0;
846     buffer->mRaw = NULL;
847     buffer->mNonContig = 0;
848 }
849 
tallyUnderrunFrames(uint32_t frameCount)850 void StaticAudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount)
851 {
852     // Unlike AudioTrackServerProxy::tallyUnderrunFrames() used for streaming tracks,
853     // we don't have a location to count underrun frames.  The underrun frame counter
854     // only exists in AudioTrackSharedStreaming.  Fortunately, underruns are not
855     // possible for static buffer tracks other than at end of buffer, so this is not a loss.
856 
857     // FIXME also wake futex so that underrun is noticed more quickly
858     (void) android_atomic_or(CBLK_UNDERRUN, &mCblk->mFlags);
859 }
860 
861 // ---------------------------------------------------------------------------
862 
863 }   // namespace android
864