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