summaryrefslogtreecommitdiffstats
path: root/include/private
diff options
context:
space:
mode:
authorGlenn Kasten <gkasten@google.com>2012-12-18 15:57:32 -0800
committerGlenn Kasten <gkasten@google.com>2013-06-12 14:33:10 -0700
commit9f80dd223d83d9bb9077fb6baee056cee4eaf7e5 (patch)
tree79f19f80ebb7978e9bab16e1d9b835849c735592 /include/private
parent9fef8d453b15a91a2b748faac2bfaff713bcf1e1 (diff)
downloadframeworks_av-9f80dd223d83d9bb9077fb6baee056cee4eaf7e5.zip
frameworks_av-9f80dd223d83d9bb9077fb6baee056cee4eaf7e5.tar.gz
frameworks_av-9f80dd223d83d9bb9077fb6baee056cee4eaf7e5.tar.bz2
New control block for AudioTrack and AudioRecord
Main differences between old and new control block: - removes the mutex, which was a potential source of priority inversion - circular indices into shared buffer, which is now always a power-of-2 size Change-Id: I4e9b7fa99858b488ac98a441fa70e31dbba1b865
Diffstat (limited to 'include/private')
-rw-r--r--include/private/media/AudioTrackShared.h391
1 files changed, 267 insertions, 124 deletions
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 41e20f8..681f557 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -22,32 +22,46 @@
#include <utils/threads.h>
#include <utils/Log.h>
+#include <utils/RefBase.h>
+#include <media/nbaio/roundup.h>
+#include <media/SingleStateQueue.h>
+#include <private/media/StaticAudioTrackState.h>
namespace android {
// ----------------------------------------------------------------------------
-// Maximum cumulated timeout milliseconds before restarting audioflinger thread
-#define MAX_STARTUP_TIMEOUT_MS 3000 // Longer timeout period at startup to cope with A2DP
- // init time
-#define MAX_RUN_TIMEOUT_MS 1000
-#define WAIT_PERIOD_MS 10
-
-#define CBLK_UNDERRUN 0x01 // set: underrun (out) or overrrun (in), clear: no underrun or overrun
+#define CBLK_UNDERRUN 0x01 // set by server immediately on output underrun, cleared by client
#define CBLK_FORCEREADY 0x02 // set: track is considered ready immediately by AudioFlinger,
// clear: track is ready when buffer full
#define CBLK_INVALID 0x04 // track buffer invalidated by AudioFlinger, need to re-create
-#define CBLK_DISABLED 0x08 // track disabled by AudioFlinger due to underrun, need to re-start
+#define CBLK_DISABLED 0x08 // output track disabled by AudioFlinger due to underrun,
+ // need to re-start. Unlike CBLK_UNDERRUN, this is not set
+ // immediately, but only after a long string of underruns.
+// 0x10 unused
+#define CBLK_LOOP_CYCLE 0x20 // set by server each time a loop cycle other than final one completes
+#define CBLK_LOOP_FINAL 0x40 // set by server when the final loop cycle completes
+#define CBLK_BUFFER_END 0x80 // set by server when the position reaches end of buffer if not looping
+#define CBLK_OVERRUN 0x100 // set by server immediately on input overrun, cleared by client
+#define CBLK_INTERRUPT 0x200 // set by client on interrupt(), cleared by client in obtainBuffer()
struct AudioTrackSharedStreaming {
// similar to NBAIO MonoPipe
- volatile int32_t mFront;
- volatile int32_t mRear;
+ // in continuously incrementing frame units, take modulo buffer size, which must be a power of 2
+ volatile int32_t mFront; // read by server
+ volatile int32_t mRear; // write by client
+ volatile int32_t mFlush; // incremented by client to indicate a request to flush;
+ // server notices and discards all data between mFront and mRear
+ volatile uint32_t mUnderrunFrames; // server increments for each unavailable but desired frame
};
-// future
+typedef SingleStateQueue<StaticAudioTrackState> StaticAudioTrackSingleStateQueue;
+
struct AudioTrackSharedStatic {
- int mReserved;
+ StaticAudioTrackSingleStateQueue::Shared
+ mSingleStateQueue;
+ size_t mBufferPosition; // updated asynchronously by server,
+ // "for entertainment purposes only"
};
// ----------------------------------------------------------------------------
@@ -55,65 +69,61 @@ struct AudioTrackSharedStatic {
// Important: do not add any virtual methods, including ~
struct audio_track_cblk_t
{
+ // Since the control block is always located in shared memory, this constructor
+ // is only used for placement new(). It is never used for regular new() or stack.
+ audio_track_cblk_t();
+ /*virtual*/ ~audio_track_cblk_t() { }
+
friend class Proxy;
+ friend class ClientProxy;
friend class AudioTrackClientProxy;
friend class AudioRecordClientProxy;
friend class ServerProxy;
+ friend class AudioTrackServerProxy;
+ friend class AudioRecordServerProxy;
// The data members are grouped so that members accessed frequently and in the same context
// are in the same line of data cache.
- Mutex lock; // sizeof(int)
- Condition cv; // sizeof(int)
-
- // next 4 are offsets within "buffers"
- volatile uint32_t user;
- volatile uint32_t server;
- uint32_t userBase;
- uint32_t serverBase;
- int mPad1; // unused, but preserves cache line alignment
+ volatile uint32_t server; // updated asynchronously by server,
+ // "for entertainment purposes only"
size_t frameCount_; // used during creation to pass actual track buffer size
// from AudioFlinger to client, and not referenced again
- // FIXME remove here and replace by createTrack() in/out parameter
+ // FIXME remove here and replace by createTrack() in/out
+ // parameter
// renamed to "_" to detect incorrect use
- // Cache line boundary (32 bytes)
+ volatile int32_t mFutex; // semaphore: down (P) by client,
+ // up (V) by server or binderDied() or interrupt()
+
+private:
- uint32_t loopStart;
- uint32_t loopEnd; // read-only for server, read/write for client
- int loopCount; // read/write for client
+ size_t mMinimum; // server wakes up client if available >= mMinimum
// Channel volumes are fixed point U4.12, so 0x1000 means 1.0.
// Left channel is in [0:15], right channel is in [16:31].
// Always read and write the combined pair atomically.
// For AudioTrack only, not used by AudioRecord.
-private:
uint32_t mVolumeLR;
uint32_t mSampleRate; // AudioTrack only: client's requested sample rate in Hz
// or 0 == default. Write-only client, read-only server.
+ // client write-only, server read-only
+ uint16_t mSendLevel; // Fixed point U4.12 so 0x1000 means 1.0
+
uint8_t mPad2; // unused
public:
// read-only for client, server writes once at initialization and is then read-only
uint8_t mName; // normal tracks: track name, fast tracks: track index
- // used by client only
- uint16_t bufferTimeoutMs; // Maximum cumulated timeout before restarting
- // audioflinger
-
- uint16_t waitTimeMs; // Cumulated wait time, used by client only
-private:
- // client write-only, server read-only
- uint16_t mSendLevel; // Fixed point U4.12 so 0x1000 means 1.0
-public:
volatile int32_t flags;
// Cache line boundary (32 bytes)
-#if 0
+public:
union {
AudioTrackSharedStreaming mStreaming;
AudioTrackSharedStatic mStatic;
@@ -121,25 +131,6 @@ public:
} u;
// Cache line boundary (32 bytes)
-#endif
-
- // Since the control block is always located in shared memory, this constructor
- // is only used for placement new(). It is never used for regular new() or stack.
- audio_track_cblk_t();
-
-private:
- // if there is a shared buffer, "buffers" is the value of pointer() for the shared
- // buffer, otherwise "buffers" points immediately after the control block
- void* buffer(void *buffers, uint32_t frameSize, size_t offset) const;
-
- bool tryLock();
-
- // isOut == true means AudioTrack, isOut == false means AudioRecord
- bool stepServer(size_t stepCount, size_t frameCount, bool isOut);
- uint32_t stepUser(size_t stepCount, size_t frameCount, bool isOut);
- uint32_t framesAvailable(size_t frameCount, bool isOut);
- uint32_t framesAvailable_l(size_t frameCount, bool isOut);
- uint32_t framesReady(bool isOut);
};
// ----------------------------------------------------------------------------
@@ -147,29 +138,31 @@ private:
// Proxy for shared memory control block, to isolate callers from needing to know the details.
// There is exactly one ClientProxy and one ServerProxy per shared memory control block.
// The proxies are located in normal memory, and are not multi-thread safe within a given side.
-class Proxy {
+class Proxy : public RefBase {
protected:
- Proxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize)
- : mCblk(cblk), mBuffers(buffers), mFrameCount(frameCount), mFrameSize(frameSize) { }
+ Proxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize, bool isOut,
+ bool clientInServer);
virtual ~Proxy() { }
public:
- void* buffer(size_t offset) const {
- return mCblk->buffer(mBuffers, mFrameSize, offset);
- }
+ struct Buffer {
+ size_t mFrameCount; // number of frames available in this buffer
+ void* mRaw; // pointer to first frame
+ size_t mNonContig; // number of additional non-contiguous frames available
+ };
protected:
// These refer to shared memory, and are virtual addresses with respect to the current process.
// They may have different virtual addresses within the other process.
- audio_track_cblk_t* const mCblk; // the control block
- void* const mBuffers; // starting address of buffers
-
- const size_t mFrameCount; // not necessarily a power of 2
- const size_t mFrameSize; // in bytes
-#if 0
- const size_t mFrameCountP2; // mFrameCount rounded to power of 2, streaming mode
-#endif
-
+ audio_track_cblk_t* const mCblk; // the control block
+ void* const mBuffers; // starting address of buffers
+
+ const size_t mFrameCount; // not necessarily a power of 2
+ const size_t mFrameSize; // in bytes
+ const size_t mFrameCountP2; // mFrameCount rounded to power of 2, streaming mode
+ const bool mIsOut; // true for AudioTrack, false for AudioRecord
+ const bool mClientInServer; // true for OutputTrack, false for AudioTrack & AudioRecord
+ bool mIsShutdown; // latch set to true when shared memory corruption detected
};
// ----------------------------------------------------------------------------
@@ -177,9 +170,86 @@ protected:
// Proxy seen by AudioTrack client and AudioRecord client
class ClientProxy : public Proxy {
protected:
- ClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize)
- : Proxy(cblk, buffers, frameCount, frameSize) { }
+ ClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize,
+ bool isOut, bool clientInServer);
virtual ~ClientProxy() { }
+
+public:
+ static const struct timespec kForever;
+ static const struct timespec kNonBlocking;
+
+ // Obtain a buffer with filled frames (reading) or empty frames (writing).
+ // It is permitted to call obtainBuffer() multiple times in succession, without any intervening
+ // calls to releaseBuffer(). In that case, the final obtainBuffer() is the one that effectively
+ // sets or extends the unreleased frame count.
+ // On entry:
+ // buffer->mFrameCount should be initialized to maximum number of desired frames,
+ // which must be > 0.
+ // buffer->mNonContig is unused.
+ // buffer->mRaw is unused.
+ // requested is the requested timeout in local monotonic delta time units:
+ // NULL or &kNonBlocking means non-blocking (zero timeout).
+ // &kForever means block forever (infinite timeout).
+ // Other values mean a specific timeout in local monotonic delta time units.
+ // elapsed is a pointer to a location that will hold the total local monotonic time that
+ // elapsed while blocked, or NULL if not needed.
+ // On exit:
+ // buffer->mFrameCount has the actual number of contiguous available frames,
+ // which is always 0 when the return status != NO_ERROR.
+ // buffer->mNonContig is the number of additional non-contiguous available frames.
+ // buffer->mRaw is a pointer to the first available frame,
+ // or NULL when buffer->mFrameCount == 0.
+ // The return status is one of:
+ // NO_ERROR Success, buffer->mFrameCount > 0.
+ // WOULD_BLOCK Non-blocking mode and no frames are available.
+ // TIMED_OUT Timeout occurred before any frames became available.
+ // This can happen even for infinite timeout, due to a spurious wakeup.
+ // In this case, the caller should investigate and then re-try as appropriate.
+ // DEAD_OBJECT Server has died or invalidated, caller should destroy this proxy and re-create.
+ // -EINTR Call has been interrupted. Look around to see why, and then perhaps try again.
+ // NO_INIT Shared memory is corrupt.
+ // BAD_VALUE On entry buffer == NULL or buffer->mFrameCount == 0.
+ status_t obtainBuffer(Buffer* buffer, const struct timespec *requested = NULL,
+ struct timespec *elapsed = NULL);
+
+ // Release (some of) the frames last obtained.
+ // On entry, buffer->mFrameCount should have the number of frames to release,
+ // which must (cumulatively) be <= the number of frames last obtained but not yet released.
+ // buffer->mRaw is ignored, but is normally same pointer returned by last obtainBuffer().
+ // It is permitted to call releaseBuffer() multiple times to release the frames in chunks.
+ // On exit:
+ // buffer->mFrameCount is zero.
+ // buffer->mRaw is NULL.
+ void releaseBuffer(Buffer* buffer);
+
+ // Call after detecting server's death
+ void binderDied();
+
+ // Call to force an obtainBuffer() to return quickly with -EINTR
+ void interrupt();
+
+ size_t getPosition() {
+ return mEpoch + mCblk->server;
+ }
+
+ void setEpoch(size_t epoch) {
+ mEpoch = epoch;
+ }
+
+ void setMinimum(size_t minimum) {
+ mCblk->mMinimum = minimum;
+ }
+
+ // Return the number of frames that would need to be obtained and released
+ // in order for the client to be aligned at start of buffer
+ virtual size_t getMisalignment();
+
+ size_t getEpoch() const {
+ return mEpoch;
+ }
+
+private:
+ size_t mEpoch;
};
// ----------------------------------------------------------------------------
@@ -187,8 +257,10 @@ protected:
// Proxy used by AudioTrack client, which also includes AudioFlinger::PlaybackThread::OutputTrack
class AudioTrackClientProxy : public ClientProxy {
public:
- AudioTrackClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize)
- : ClientProxy(cblk, buffers, frameCount, frameSize) { }
+ AudioTrackClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
+ size_t frameSize, bool clientInServer = false)
+ : ClientProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/,
+ clientInServer) { }
virtual ~AudioTrackClientProxy() { }
// No barriers on the following operations, so the ordering of loads/stores
@@ -208,27 +280,36 @@ public:
mCblk->mSampleRate = sampleRate;
}
- // called by:
- // PlaybackThread::OutputTrack::write
- // AudioTrack::createTrack_l
- // AudioTrack::releaseBuffer
- // AudioTrack::reload
- // AudioTrack::restoreTrack_l (2 places)
- size_t stepUser(size_t stepCount) {
- return mCblk->stepUser(stepCount, mFrameCount, true /*isOut*/);
+ virtual void flush();
+
+ virtual uint32_t getUnderrunFrames() const {
+ return mCblk->u.mStreaming.mUnderrunFrames;
}
+};
+
+class StaticAudioTrackClientProxy : public AudioTrackClientProxy {
+public:
+ StaticAudioTrackClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
+ size_t frameSize);
+ virtual ~StaticAudioTrackClientProxy() { }
+
+ virtual void flush();
+
+#define MIN_LOOP 16 // minimum length of each loop iteration in frames
+ void setLoop(size_t loopStart, size_t loopEnd, int loopCount);
+ size_t getBufferPosition();
- // called by AudioTrack::obtainBuffer and AudioTrack::processBuffer
- size_t framesAvailable() {
- return mCblk->framesAvailable(mFrameCount, true /*isOut*/);
+ virtual size_t getMisalignment() {
+ return 0;
}
- // called by AudioTrack::obtainBuffer and PlaybackThread::OutputTrack::obtainBuffer
- // FIXME remove this API since it assumes a lock that should be invisible to caller
- size_t framesAvailable_l() {
- return mCblk->framesAvailable_l(mFrameCount, true /*isOut*/);
+ virtual uint32_t getUnderrunFrames() const {
+ return 0;
}
+private:
+ StaticAudioTrackSingleStateQueue::Mutator mMutator;
+ size_t mBufferPosition; // so that getBufferPosition() appears to be synchronous
};
// ----------------------------------------------------------------------------
@@ -236,60 +317,122 @@ public:
// Proxy used by AudioRecord client
class AudioRecordClientProxy : public ClientProxy {
public:
- AudioRecordClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize)
- : ClientProxy(cblk, buffers, frameCount, frameSize) { }
+ AudioRecordClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
+ size_t frameSize)
+ : ClientProxy(cblk, buffers, frameCount, frameSize,
+ false /*isOut*/, false /*clientInServer*/) { }
~AudioRecordClientProxy() { }
-
- // called by AudioRecord::releaseBuffer
- size_t stepUser(size_t stepCount) {
- return mCblk->stepUser(stepCount, mFrameCount, false /*isOut*/);
- }
-
- // called by AudioRecord::processBuffer
- size_t framesAvailable() {
- return mCblk->framesAvailable(mFrameCount, false /*isOut*/);
- }
-
- // called by AudioRecord::obtainBuffer
- size_t framesReady() {
- return mCblk->framesReady(false /*isOut*/);
- }
-
};
// ----------------------------------------------------------------------------
// Proxy used by AudioFlinger server
class ServerProxy : public Proxy {
+protected:
+ ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize,
+ bool isOut, bool clientInServer);
public:
- ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize, bool isOut)
- : Proxy(cblk, buffers, frameCount, frameSize), mIsOut(isOut) { }
virtual ~ServerProxy() { }
- // for AudioTrack and AudioRecord
- bool step(size_t stepCount) { return mCblk->stepServer(stepCount, mFrameCount, mIsOut); }
+ // Obtain a buffer with filled frames (writing) or empty frames (reading).
+ // It is permitted to call obtainBuffer() multiple times in succession, without any intervening
+ // calls to releaseBuffer(). In that case, the final obtainBuffer() is the one that effectively
+ // sets or extends the unreleased frame count.
+ // Always non-blocking.
+ // On entry:
+ // buffer->mFrameCount should be initialized to maximum number of desired frames,
+ // which must be > 0.
+ // buffer->mNonContig is unused.
+ // buffer->mRaw is unused.
+ // On exit:
+ // buffer->mFrameCount has the actual number of contiguous available frames,
+ // which is always 0 when the return status != NO_ERROR.
+ // buffer->mNonContig is the number of additional non-contiguous available frames.
+ // buffer->mRaw is a pointer to the first available frame,
+ // or NULL when buffer->mFrameCount == 0.
+ // The return status is one of:
+ // NO_ERROR Success, buffer->mFrameCount > 0.
+ // WOULD_BLOCK No frames are available.
+ // NO_INIT Shared memory is corrupt.
+ virtual status_t obtainBuffer(Buffer* buffer);
+
+ // Release (some of) the frames last obtained.
+ // On entry, buffer->mFrameCount should have the number of frames to release,
+ // which must (cumulatively) be <= the number of frames last obtained but not yet released.
+ // It is permitted to call releaseBuffer() multiple times to release the frames in chunks.
+ // buffer->mRaw is ignored, but is normally same pointer returned by last obtainBuffer().
+ // On exit:
+ // buffer->mFrameCount is zero.
+ // buffer->mRaw is NULL.
+ virtual void releaseBuffer(Buffer* buffer);
+protected:
+ size_t mUnreleased; // unreleased frames remaining from most recent obtainBuffer()
+ size_t mAvailToClient; // estimated frames available to client prior to releaseBuffer()
+private:
+ int32_t mFlush; // our copy of cblk->u.mStreaming.mFlush, for streaming output only
+ bool mDeferWake; // whether another releaseBuffer() is expected soon
+};
+
+// Proxy used by AudioFlinger for servicing AudioTrack
+class AudioTrackServerProxy : public ServerProxy {
+public:
+ AudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
+ size_t frameSize, bool clientInServer = false)
+ : ServerProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, clientInServer) { }
+protected:
+ virtual ~AudioTrackServerProxy() { }
+
+public:
// return value of these methods must be validated by the caller
uint32_t getSampleRate() const { return mCblk->mSampleRate; }
uint16_t getSendLevel_U4_12() const { return mCblk->mSendLevel; }
uint32_t getVolumeLR() const { return mCblk->mVolumeLR; }
- // for AudioTrack only
- size_t framesReady() {
- ALOG_ASSERT(mIsOut);
- return mCblk->framesReady(true);
- }
+ // estimated total number of filled frames available to server to read,
+ // which may include non-contiguous frames
+ virtual size_t framesReady();
+
+ // Currently AudioFlinger will call framesReady() for a fast track from two threads:
+ // FastMixer thread, and normal mixer thread. This is dangerous, as the proxy is intended
+ // to be called from at most one thread of server, and one thread of client.
+ // As a temporary workaround, this method informs the proxy implementation that it
+ // should avoid doing a state queue poll from within framesReady().
+ // FIXME Change AudioFlinger to not call framesReady() from normal mixer thread.
+ virtual void framesReadyIsCalledByMultipleThreads() { }
+};
- // for AudioRecord only, called by RecordThread::RecordTrack::getNextBuffer
- // FIXME remove this API since it assumes a lock that should be invisible to caller
- size_t framesAvailableIn_l() {
- ALOG_ASSERT(!mIsOut);
- return mCblk->framesAvailable_l(mFrameCount, false);
- }
+class StaticAudioTrackServerProxy : public AudioTrackServerProxy {
+public:
+ StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
+ size_t frameSize);
+protected:
+ virtual ~StaticAudioTrackServerProxy() { }
+
+public:
+ virtual size_t framesReady();
+ virtual void framesReadyIsCalledByMultipleThreads();
+ virtual status_t obtainBuffer(Buffer* buffer);
+ virtual void releaseBuffer(Buffer* buffer);
private:
- const bool mIsOut; // true for AudioTrack, false for AudioRecord
+ ssize_t pollPosition(); // poll for state queue update, and return current position
+ StaticAudioTrackSingleStateQueue::Observer mObserver;
+ size_t mPosition; // server's current play position in frames, relative to 0
+ size_t mEnd; // cached value computed from mState, safe for asynchronous read
+ bool mFramesReadyIsCalledByMultipleThreads;
+ StaticAudioTrackState mState;
+};
+// Proxy used by AudioFlinger for servicing AudioRecord
+class AudioRecordServerProxy : public ServerProxy {
+public:
+ AudioRecordServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
+ size_t frameSize)
+ : ServerProxy(cblk, buffers, frameCount, frameSize, false /*isOut*/,
+ false /*clientInServer*/) { }
+protected:
+ virtual ~AudioRecordServerProxy() { }
};
// ----------------------------------------------------------------------------