Loading include/private/media/AudioTrackShared.h +32 −0 Original line number Diff line number Diff line Loading @@ -60,6 +60,8 @@ struct AudioTrackSharedStreaming { volatile int32_t mRear; // written by producer (output: client, input: server) volatile int32_t mFlush; // incremented by client to indicate a request to flush; // server notices and discards all data between mFront and mRear volatile int32_t mStop; // set by client to indicate a stop frame position; server // will not read beyond this position until start is called. volatile uint32_t mUnderrunFrames; // server increments for each unavailable but desired frame volatile uint32_t mUnderrunCount; // server increments for each underrun occurrence }; Loading Loading @@ -335,6 +337,8 @@ public: mTimestamp.clear(); } virtual void stop() { }; // called by client in AudioTrack::stop() private: // This is a copy of mCblk->mBufferSizeInFrames uint32_t mBufferSizeInFrames; // effective size of the buffer Loading Loading @@ -383,8 +387,14 @@ public: mPlaybackRateMutator.push(playbackRate); } // Sends flush and stop position information from the client to the server, // used by streaming AudioTrack flush() or stop(). void sendStreamingFlushStop(bool flush); virtual void flush(); void stop() override; virtual uint32_t getUnderrunFrames() const { return mCblk->u.mStreaming.mUnderrunFrames; } Loading @@ -410,6 +420,8 @@ public: virtual void flush(); void stop() override; #define MIN_LOOP 16 // minimum length of each loop iteration in frames // setLoop(), setBufferPosition(), and setBufferPositionAndLoop() set the Loading Loading @@ -532,6 +544,10 @@ public: // client will be notified via Futex virtual void flushBufferIfNeeded(); // Returns the rear position of the AudioTrack shared ring buffer, limited by // the stop frame position level. virtual int32_t getRear() const = 0; // Total count of the number of flushed frames since creation (never reset). virtual int64_t framesFlushed() const { return mFlushed; } Loading Loading @@ -607,10 +623,18 @@ public: return mDrained.load(); } int32_t getRear() const override; // Called on server side track start(). virtual void start(); private: AudioPlaybackRate mPlaybackRate; // last observed playback rate PlaybackRateQueue::Observer mPlaybackRateObserver; // Last client stop-at position when start() was called. Used for streaming AudioTracks. std::atomic<int32_t> mStopLast{0}; // The server keeps a copy here where it is safe from the client. uint32_t mUnderrunCount; // echoed to mCblk bool mUnderrunning; // used to detect edge of underrun Loading @@ -634,6 +658,10 @@ public: virtual void tallyUnderrunFrames(uint32_t frameCount); virtual uint32_t getUnderrunFrames() const { return 0; } int32_t getRear() const override; void start() override { } // ignore for static tracks private: status_t updateStateWithLoop(StaticAudioTrackState *localState, const StaticAudioTrackState &update) const; Loading Loading @@ -661,6 +689,10 @@ public: size_t frameSize, bool clientInServer) : ServerProxy(cblk, buffers, frameCount, frameSize, false /*isOut*/, clientInServer) { } int32_t getRear() const override { return mCblk->u.mStreaming.mRear; // For completeness only; mRear written by server. } protected: virtual ~AudioRecordServerProxy() { } }; Loading media/libaudioclient/AudioTrack.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -770,6 +770,7 @@ void AudioTrack::stop() mReleased = 0; } mProxy->stop(); // notify server not to read beyond current client position until start(). mProxy->interrupt(); mAudioTrack->stop(); Loading media/libaudioclient/AudioTrackShared.cpp +92 −11 Original line number Diff line number Diff line Loading @@ -393,19 +393,50 @@ size_t ClientProxy::getMisalignment() // --------------------------------------------------------------------------- __attribute__((no_sanitize("integer"))) void AudioTrackClientProxy::flush() { sendStreamingFlushStop(true /* flush */); } void AudioTrackClientProxy::stop() { sendStreamingFlushStop(false /* flush */); } // Sets the client-written mFlush and mStop positions, which control server behavior. // // @param flush indicates whether the operation is a flush or stop. // A client stop sets mStop to the current write position; // the server will not read past this point until start() or subsequent flush(). // A client flush sets both mStop and mFlush to the current write position. // This advances the server read limit (if previously set) and on the next // server read advances the server read position to this limit. // void AudioTrackClientProxy::sendStreamingFlushStop(bool flush) { // TODO: Replace this by 64 bit counters - avoids wrap complication. // This works for mFrameCountP2 <= 2^30 size_t increment = mFrameCountP2 << 1; size_t mask = increment - 1; audio_track_cblk_t* cblk = mCblk; // mFlush is 32 bits concatenated as [ flush_counter ] [ newfront_offset ] // Should newFlush = cblk->u.mStreaming.mRear? Only problem is // if you want to flush twice to the same rear location after a 32 bit wrap. int32_t newFlush = (cblk->u.mStreaming.mRear & mask) | ((cblk->u.mStreaming.mFlush & ~mask) + increment); android_atomic_release_store(newFlush, &cblk->u.mStreaming.mFlush); const size_t increment = mFrameCountP2 << 1; const size_t mask = increment - 1; // No need for client atomic synchronization on mRear, mStop, mFlush // as AudioTrack client only read/writes to them under client lock. Server only reads. const int32_t rearMasked = mCblk->u.mStreaming.mRear & mask; // update stop before flush so that the server front // never advances beyond a (potential) previous stop's rear limit. int32_t stopBits; // the following add can overflow __builtin_add_overflow(mCblk->u.mStreaming.mStop & ~mask, increment, &stopBits); android_atomic_release_store(rearMasked | stopBits, &mCblk->u.mStreaming.mStop); if (flush) { int32_t flushBits; // the following add can overflow __builtin_add_overflow(mCblk->u.mStreaming.mFlush & ~mask, increment, &flushBits); android_atomic_release_store(rearMasked | flushBits, &mCblk->u.mStreaming.mFlush); } } bool AudioTrackClientProxy::clearStreamEndDone() { Loading Loading @@ -540,6 +571,11 @@ void StaticAudioTrackClientProxy::flush() LOG_ALWAYS_FATAL("static flush"); } void StaticAudioTrackClientProxy::stop() { ; // no special handling required for static tracks. } void StaticAudioTrackClientProxy::setLoop(size_t loopStart, size_t loopEnd, int loopCount) { // This can only happen on a 64-bit client Loading Loading @@ -638,6 +674,7 @@ void ServerProxy::flushBufferIfNeeded() if (flush != mFlush) { ALOGV("ServerProxy::flushBufferIfNeeded() mStreaming.mFlush = 0x%x, mFlush = 0x%0x", flush, mFlush); // shouldn't matter, but for range safety use mRear instead of getRear(). int32_t rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear); int32_t front = cblk->u.mStreaming.mFront; Loading Loading @@ -676,6 +713,45 @@ void ServerProxy::flushBufferIfNeeded() } } __attribute__((no_sanitize("integer"))) int32_t AudioTrackServerProxy::getRear() const { const int32_t stop = android_atomic_acquire_load(&mCblk->u.mStreaming.mStop); const int32_t rear = android_atomic_acquire_load(&mCblk->u.mStreaming.mRear); const int32_t stopLast = mStopLast.load(std::memory_order_acquire); if (stop != stopLast) { const int32_t front = mCblk->u.mStreaming.mFront; const size_t overflowBit = mFrameCountP2 << 1; const size_t mask = overflowBit - 1; int32_t newRear = (rear & ~mask) | (stop & mask); ssize_t filled = newRear - front; if (filled < 0) { // front and rear offsets span the overflow bit of the p2 mask // so rebasing newrear. ALOGV("stop wrap: filled %zx >= overflowBit %zx", filled, overflowBit); newRear += overflowBit; filled += overflowBit; } if (0 <= filled && (size_t) filled <= mFrameCount) { // we're stopped, return the stop level as newRear return newRear; } // A corrupt stop. Log error and ignore. ALOGE("mStopLast %#x -> stop %#x, front %#x, rear %#x, mask %#x, newRear %#x, " "filled %zd=%#x", stopLast, stop, front, rear, (unsigned)mask, newRear, filled, (unsigned)filled); // Don't reset mStopLast as this is const. } return rear; } void AudioTrackServerProxy::start() { mStopLast = android_atomic_acquire_load(&mCblk->u.mStreaming.mStop); } __attribute__((no_sanitize("integer"))) status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush) { Loading @@ -693,7 +769,7 @@ status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush) // See notes on barriers at ClientProxy::obtainBuffer() if (mIsOut) { flushBufferIfNeeded(); // might modify mFront rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear); rear = getRear(); front = cblk->u.mStreaming.mFront; } else { front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront); Loading Loading @@ -825,8 +901,7 @@ size_t AudioTrackServerProxy::framesReady() // FIXME should return an accurate value, but over-estimate is better than under-estimate return mFrameCount; } // the acquire might not be necessary since not doing a subsequent read int32_t rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear); const int32_t rear = getRear(); ssize_t filled = rear - cblk->u.mStreaming.mFront; // pipe should not already be overfull if (!(0 <= filled && (size_t) filled <= mFrameCount)) { Loading @@ -852,7 +927,7 @@ size_t AudioTrackServerProxy::framesReadySafe() const if (flush != mFlush) { return mFrameCount; } const int32_t rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear); const int32_t rear = getRear(); const ssize_t filled = rear - cblk->u.mStreaming.mFront; if (!(0 <= filled && (size_t) filled <= mFrameCount)) { return 0; // error condition, silently return 0. Loading Loading @@ -1149,6 +1224,12 @@ void StaticAudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount) } } int32_t StaticAudioTrackServerProxy::getRear() const { LOG_ALWAYS_FATAL("getRear() not permitted for static tracks"); return 0; } // --------------------------------------------------------------------------- } // namespace android media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +1 −8 Original line number Diff line number Diff line Loading @@ -1617,14 +1617,7 @@ void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) { // internal buffer before resuming playback. // FIXME: this is ignored after flush(). mAudioSink->stop(); if (mPaused) { // Race condition: if renderer is paused and audio sink is stopped, // we need to make sure that the audio track buffer fully drains // before delivering data. // FIXME: remove this if we can detect if stop() is complete. const int delayUs = 2 * 50 * 1000; // (2 full mixer thread cycles at 50ms) mPauseDrainAudioAllowedUs = ALooper::GetNowUs() + delayUs; } else { if (!mPaused) { mAudioSink->start(); } mNumFramesWritten = 0; Loading services/audioflinger/Tracks.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -764,6 +764,12 @@ status_t AudioFlinger::PlaybackThread::Track::start(AudioSystem::sync_event_t ev mState = state; } } if (status == NO_ERROR || status == ALREADY_EXISTS) { // for streaming tracks, remove the buffer read stop limit. mAudioTrackServerProxy->start(); } // track was already in the active list, not a problem if (status == ALREADY_EXISTS) { status = NO_ERROR; Loading Loading
include/private/media/AudioTrackShared.h +32 −0 Original line number Diff line number Diff line Loading @@ -60,6 +60,8 @@ struct AudioTrackSharedStreaming { volatile int32_t mRear; // written by producer (output: client, input: server) volatile int32_t mFlush; // incremented by client to indicate a request to flush; // server notices and discards all data between mFront and mRear volatile int32_t mStop; // set by client to indicate a stop frame position; server // will not read beyond this position until start is called. volatile uint32_t mUnderrunFrames; // server increments for each unavailable but desired frame volatile uint32_t mUnderrunCount; // server increments for each underrun occurrence }; Loading Loading @@ -335,6 +337,8 @@ public: mTimestamp.clear(); } virtual void stop() { }; // called by client in AudioTrack::stop() private: // This is a copy of mCblk->mBufferSizeInFrames uint32_t mBufferSizeInFrames; // effective size of the buffer Loading Loading @@ -383,8 +387,14 @@ public: mPlaybackRateMutator.push(playbackRate); } // Sends flush and stop position information from the client to the server, // used by streaming AudioTrack flush() or stop(). void sendStreamingFlushStop(bool flush); virtual void flush(); void stop() override; virtual uint32_t getUnderrunFrames() const { return mCblk->u.mStreaming.mUnderrunFrames; } Loading @@ -410,6 +420,8 @@ public: virtual void flush(); void stop() override; #define MIN_LOOP 16 // minimum length of each loop iteration in frames // setLoop(), setBufferPosition(), and setBufferPositionAndLoop() set the Loading Loading @@ -532,6 +544,10 @@ public: // client will be notified via Futex virtual void flushBufferIfNeeded(); // Returns the rear position of the AudioTrack shared ring buffer, limited by // the stop frame position level. virtual int32_t getRear() const = 0; // Total count of the number of flushed frames since creation (never reset). virtual int64_t framesFlushed() const { return mFlushed; } Loading Loading @@ -607,10 +623,18 @@ public: return mDrained.load(); } int32_t getRear() const override; // Called on server side track start(). virtual void start(); private: AudioPlaybackRate mPlaybackRate; // last observed playback rate PlaybackRateQueue::Observer mPlaybackRateObserver; // Last client stop-at position when start() was called. Used for streaming AudioTracks. std::atomic<int32_t> mStopLast{0}; // The server keeps a copy here where it is safe from the client. uint32_t mUnderrunCount; // echoed to mCblk bool mUnderrunning; // used to detect edge of underrun Loading @@ -634,6 +658,10 @@ public: virtual void tallyUnderrunFrames(uint32_t frameCount); virtual uint32_t getUnderrunFrames() const { return 0; } int32_t getRear() const override; void start() override { } // ignore for static tracks private: status_t updateStateWithLoop(StaticAudioTrackState *localState, const StaticAudioTrackState &update) const; Loading Loading @@ -661,6 +689,10 @@ public: size_t frameSize, bool clientInServer) : ServerProxy(cblk, buffers, frameCount, frameSize, false /*isOut*/, clientInServer) { } int32_t getRear() const override { return mCblk->u.mStreaming.mRear; // For completeness only; mRear written by server. } protected: virtual ~AudioRecordServerProxy() { } }; Loading
media/libaudioclient/AudioTrack.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -770,6 +770,7 @@ void AudioTrack::stop() mReleased = 0; } mProxy->stop(); // notify server not to read beyond current client position until start(). mProxy->interrupt(); mAudioTrack->stop(); Loading
media/libaudioclient/AudioTrackShared.cpp +92 −11 Original line number Diff line number Diff line Loading @@ -393,19 +393,50 @@ size_t ClientProxy::getMisalignment() // --------------------------------------------------------------------------- __attribute__((no_sanitize("integer"))) void AudioTrackClientProxy::flush() { sendStreamingFlushStop(true /* flush */); } void AudioTrackClientProxy::stop() { sendStreamingFlushStop(false /* flush */); } // Sets the client-written mFlush and mStop positions, which control server behavior. // // @param flush indicates whether the operation is a flush or stop. // A client stop sets mStop to the current write position; // the server will not read past this point until start() or subsequent flush(). // A client flush sets both mStop and mFlush to the current write position. // This advances the server read limit (if previously set) and on the next // server read advances the server read position to this limit. // void AudioTrackClientProxy::sendStreamingFlushStop(bool flush) { // TODO: Replace this by 64 bit counters - avoids wrap complication. // This works for mFrameCountP2 <= 2^30 size_t increment = mFrameCountP2 << 1; size_t mask = increment - 1; audio_track_cblk_t* cblk = mCblk; // mFlush is 32 bits concatenated as [ flush_counter ] [ newfront_offset ] // Should newFlush = cblk->u.mStreaming.mRear? Only problem is // if you want to flush twice to the same rear location after a 32 bit wrap. int32_t newFlush = (cblk->u.mStreaming.mRear & mask) | ((cblk->u.mStreaming.mFlush & ~mask) + increment); android_atomic_release_store(newFlush, &cblk->u.mStreaming.mFlush); const size_t increment = mFrameCountP2 << 1; const size_t mask = increment - 1; // No need for client atomic synchronization on mRear, mStop, mFlush // as AudioTrack client only read/writes to them under client lock. Server only reads. const int32_t rearMasked = mCblk->u.mStreaming.mRear & mask; // update stop before flush so that the server front // never advances beyond a (potential) previous stop's rear limit. int32_t stopBits; // the following add can overflow __builtin_add_overflow(mCblk->u.mStreaming.mStop & ~mask, increment, &stopBits); android_atomic_release_store(rearMasked | stopBits, &mCblk->u.mStreaming.mStop); if (flush) { int32_t flushBits; // the following add can overflow __builtin_add_overflow(mCblk->u.mStreaming.mFlush & ~mask, increment, &flushBits); android_atomic_release_store(rearMasked | flushBits, &mCblk->u.mStreaming.mFlush); } } bool AudioTrackClientProxy::clearStreamEndDone() { Loading Loading @@ -540,6 +571,11 @@ void StaticAudioTrackClientProxy::flush() LOG_ALWAYS_FATAL("static flush"); } void StaticAudioTrackClientProxy::stop() { ; // no special handling required for static tracks. } void StaticAudioTrackClientProxy::setLoop(size_t loopStart, size_t loopEnd, int loopCount) { // This can only happen on a 64-bit client Loading Loading @@ -638,6 +674,7 @@ void ServerProxy::flushBufferIfNeeded() if (flush != mFlush) { ALOGV("ServerProxy::flushBufferIfNeeded() mStreaming.mFlush = 0x%x, mFlush = 0x%0x", flush, mFlush); // shouldn't matter, but for range safety use mRear instead of getRear(). int32_t rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear); int32_t front = cblk->u.mStreaming.mFront; Loading Loading @@ -676,6 +713,45 @@ void ServerProxy::flushBufferIfNeeded() } } __attribute__((no_sanitize("integer"))) int32_t AudioTrackServerProxy::getRear() const { const int32_t stop = android_atomic_acquire_load(&mCblk->u.mStreaming.mStop); const int32_t rear = android_atomic_acquire_load(&mCblk->u.mStreaming.mRear); const int32_t stopLast = mStopLast.load(std::memory_order_acquire); if (stop != stopLast) { const int32_t front = mCblk->u.mStreaming.mFront; const size_t overflowBit = mFrameCountP2 << 1; const size_t mask = overflowBit - 1; int32_t newRear = (rear & ~mask) | (stop & mask); ssize_t filled = newRear - front; if (filled < 0) { // front and rear offsets span the overflow bit of the p2 mask // so rebasing newrear. ALOGV("stop wrap: filled %zx >= overflowBit %zx", filled, overflowBit); newRear += overflowBit; filled += overflowBit; } if (0 <= filled && (size_t) filled <= mFrameCount) { // we're stopped, return the stop level as newRear return newRear; } // A corrupt stop. Log error and ignore. ALOGE("mStopLast %#x -> stop %#x, front %#x, rear %#x, mask %#x, newRear %#x, " "filled %zd=%#x", stopLast, stop, front, rear, (unsigned)mask, newRear, filled, (unsigned)filled); // Don't reset mStopLast as this is const. } return rear; } void AudioTrackServerProxy::start() { mStopLast = android_atomic_acquire_load(&mCblk->u.mStreaming.mStop); } __attribute__((no_sanitize("integer"))) status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush) { Loading @@ -693,7 +769,7 @@ status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush) // See notes on barriers at ClientProxy::obtainBuffer() if (mIsOut) { flushBufferIfNeeded(); // might modify mFront rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear); rear = getRear(); front = cblk->u.mStreaming.mFront; } else { front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront); Loading Loading @@ -825,8 +901,7 @@ size_t AudioTrackServerProxy::framesReady() // FIXME should return an accurate value, but over-estimate is better than under-estimate return mFrameCount; } // the acquire might not be necessary since not doing a subsequent read int32_t rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear); const int32_t rear = getRear(); ssize_t filled = rear - cblk->u.mStreaming.mFront; // pipe should not already be overfull if (!(0 <= filled && (size_t) filled <= mFrameCount)) { Loading @@ -852,7 +927,7 @@ size_t AudioTrackServerProxy::framesReadySafe() const if (flush != mFlush) { return mFrameCount; } const int32_t rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear); const int32_t rear = getRear(); const ssize_t filled = rear - cblk->u.mStreaming.mFront; if (!(0 <= filled && (size_t) filled <= mFrameCount)) { return 0; // error condition, silently return 0. Loading Loading @@ -1149,6 +1224,12 @@ void StaticAudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount) } } int32_t StaticAudioTrackServerProxy::getRear() const { LOG_ALWAYS_FATAL("getRear() not permitted for static tracks"); return 0; } // --------------------------------------------------------------------------- } // namespace android
media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +1 −8 Original line number Diff line number Diff line Loading @@ -1617,14 +1617,7 @@ void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) { // internal buffer before resuming playback. // FIXME: this is ignored after flush(). mAudioSink->stop(); if (mPaused) { // Race condition: if renderer is paused and audio sink is stopped, // we need to make sure that the audio track buffer fully drains // before delivering data. // FIXME: remove this if we can detect if stop() is complete. const int delayUs = 2 * 50 * 1000; // (2 full mixer thread cycles at 50ms) mPauseDrainAudioAllowedUs = ALooper::GetNowUs() + delayUs; } else { if (!mPaused) { mAudioSink->start(); } mNumFramesWritten = 0; Loading
services/audioflinger/Tracks.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -764,6 +764,12 @@ status_t AudioFlinger::PlaybackThread::Track::start(AudioSystem::sync_event_t ev mState = state; } } if (status == NO_ERROR || status == ALREADY_EXISTS) { // for streaming tracks, remove the buffer read stop limit. mAudioTrackServerProxy->start(); } // track was already in the active list, not a problem if (status == ALREADY_EXISTS) { status = NO_ERROR; Loading