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
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 8dbc9ee..e9bb76a 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -17,18 +17,9 @@
#ifndef ANDROID_AUDIOTRACK_H
#define ANDROID_AUDIOTRACK_H
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <media/IAudioFlinger.h>
-#include <media/IAudioTrack.h>
-#include <media/AudioSystem.h>
-
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
-#include <binder/IInterface.h>
-#include <binder/IMemory.h>
#include <cutils/sched_policy.h>
+#include <media/AudioSystem.h>
+#include <media/IAudioTrack.h>
#include <utils/threads.h>
namespace android {
@@ -37,10 +28,11 @@
class audio_track_cblk_t;
class AudioTrackClientProxy;
+class StaticAudioTrackClientProxy;
// ----------------------------------------------------------------------------
-class AudioTrack : virtual public RefBase
+class AudioTrack : public RefBase
{
public:
enum channel_index {
@@ -49,7 +41,7 @@
RIGHT = 1
};
- /* Events used by AudioTrack callback function (audio_track_cblk_t).
+ /* Events used by AudioTrack callback function (callback_t).
* Keep in sync with frameworks/base/media/java/android/media/AudioTrack.java NATIVE_EVENT_*.
*/
enum event_type {
@@ -64,7 +56,10 @@
// (See setMarkerPosition()).
EVENT_NEW_POS = 4, // Playback head is at a new position
// (See setPositionUpdatePeriod()).
- EVENT_BUFFER_END = 5 // Playback head is at the end of the buffer.
+ EVENT_BUFFER_END = 5, // Playback head is at the end of the buffer.
+ // Not currently used by android.media.AudioTrack.
+ EVENT_NEW_IAUDIOTRACK = 6, // IAudioTrack was re-created, either due to re-routing and
+ // voluntary invalidation by mediaserver, or mediaserver crash.
};
/* Client should declare Buffer on the stack and pass address to obtainBuffer()
@@ -74,19 +69,23 @@
class Buffer
{
public:
+ // FIXME use m prefix
size_t frameCount; // number of sample frames corresponding to size;
// on input it is the number of frames desired,
// on output is the number of frames actually filled
- size_t size; // input/output in byte units
+ size_t size; // input/output in bytes == frameCount * frameSize
+ // FIXME this is redundant with respect to frameCount,
+ // and TRANSFER_OBTAIN mode is broken for 8-bit data
+ // since we don't define the frame format
+
union {
void* raw;
- short* i16; // signed 16-bit
- int8_t* i8; // unsigned 8-bit, offset by 0x80
+ short* i16; // signed 16-bit
+ int8_t* i8; // unsigned 8-bit, offset by 0x80
};
};
-
/* As a convenience, if a callback is supplied, a handler thread
* is automatically created with the appropriate priority. This thread
* invokes the callback when a new buffer becomes available or various conditions occur.
@@ -100,9 +99,10 @@
* written.
* - EVENT_UNDERRUN: unused.
* - EVENT_LOOP_END: pointer to an int indicating the number of loops remaining.
- * - EVENT_MARKER: pointer to an uint32_t containing the marker position in frames.
- * - EVENT_NEW_POS: pointer to an uint32_t containing the new position in frames.
+ * - EVENT_MARKER: pointer to const uint32_t containing the marker position in frames.
+ * - EVENT_NEW_POS: pointer to const uint32_t containing the new position in frames.
* - EVENT_BUFFER_END: unused.
+ * - EVENT_NEW_IAUDIOTRACK: unused.
*/
typedef void (*callback_t)(int event, void* user, void *info);
@@ -114,9 +114,19 @@
* - NO_INIT: audio server or audio hardware not initialized
*/
- static status_t getMinFrameCount(size_t* frameCount,
- audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT,
- uint32_t sampleRate = 0);
+ static status_t getMinFrameCount(size_t* frameCount,
+ audio_stream_type_t streamType,
+ uint32_t sampleRate);
+
+ /* How data is transferred to AudioTrack
+ */
+ enum transfer_type {
+ TRANSFER_DEFAULT, // not specified explicitly; determine from the other parameters
+ TRANSFER_CALLBACK, // callback EVENT_MORE_DATA
+ TRANSFER_OBTAIN, // FIXME deprecated: call obtainBuffer() and releaseBuffer()
+ TRANSFER_SYNC, // synchronous write()
+ TRANSFER_SHARED, // shared memory
+ };
/* Constructs an uninitialized AudioTrack. No connection with
* AudioFlinger takes place. Use set() after this.
@@ -128,13 +138,13 @@
* Unspecified values are set to appropriate default values.
* With this constructor, the track is configured for streaming mode.
* Data to be rendered is supplied by write() or by the callback EVENT_MORE_DATA.
- * Intermixing a combination of write() and non-ignored EVENT_MORE_DATA is deprecated.
+ * Intermixing a combination of write() and non-ignored EVENT_MORE_DATA is not allowed.
*
* Parameters:
*
* streamType: Select the type of audio stream this track is attached to
* (e.g. AUDIO_STREAM_MUSIC).
- * sampleRate: Track sampling rate in Hz.
+ * sampleRate: Data source sampling rate in Hz.
* format: Audio format (e.g AUDIO_FORMAT_PCM_16_BIT for signed
* 16 bits per sample).
* channelMask: Channel mask.
@@ -149,9 +159,10 @@
* user: Context for use by the callback receiver.
* notificationFrames: The callback function is called each time notificationFrames PCM
* frames have been consumed from track input buffer.
+ * This is expressed in units of frames at the initial source sample rate.
* sessionId: Specific session ID, or zero to use default.
- * threadCanCallJava: Whether callbacks are made from an attached thread and thus can call JNI.
- * If not present in parameter list, then fixed at false.
+ * transferType: How data is transferred to AudioTrack.
+ * threadCanCallJava: Not present in parameter list, and so is fixed at false.
*/
AudioTrack( audio_stream_type_t streamType,
@@ -163,7 +174,8 @@
callback_t cbf = NULL,
void* user = NULL,
int notificationFrames = 0,
- int sessionId = 0);
+ int sessionId = 0,
+ transfer_type transferType = TRANSFER_DEFAULT);
/* Creates an audio track and registers it with AudioFlinger.
* With this constructor, the track is configured for static buffer mode.
@@ -174,7 +186,6 @@
* The write() method is not supported in this case.
* It is recommended to pass a callback function to be notified of playback end by an
* EVENT_UNDERRUN event.
- * FIXME EVENT_MORE_DATA still occurs; it must be ignored.
*/
AudioTrack( audio_stream_type_t streamType,
@@ -186,7 +197,8 @@
callback_t cbf = NULL,
void* user = NULL,
int notificationFrames = 0,
- int sessionId = 0);
+ int sessionId = 0,
+ transfer_type transferType = TRANSFER_DEFAULT);
/* Terminates the AudioTrack and unregisters it from AudioFlinger.
* Also destroys all resources associated with the AudioTrack.
@@ -195,7 +207,8 @@
virtual ~AudioTrack();
public:
- /* Initialize an uninitialized AudioTrack.
+ /* Initialize an AudioTrack that was created using the AudioTrack() constructor.
+ * Don't call set() more than once, or after the AudioTrack() constructors that take parameters.
* Returned status (from utils/Errors.h) can be:
* - NO_ERROR: successful initialization
* - INVALID_OPERATION: AudioTrack is already initialized
@@ -203,6 +216,10 @@
* - NO_INIT: audio server or audio hardware not initialized
* If sharedBuffer is non-0, the frameCount parameter is ignored and
* replaced by the shared buffer's total allocated size in frame units.
+ *
+ * Parameters not listed in the AudioTrack constructors above:
+ *
+ * threadCanCallJava: Whether callbacks are made from an attached thread and thus can call JNI.
*/
status_t set(audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT,
uint32_t sampleRate = 0,
@@ -215,7 +232,8 @@
int notificationFrames = 0,
const sp<IMemory>& sharedBuffer = 0,
bool threadCanCallJava = false,
- int sessionId = 0);
+ int sessionId = 0,
+ transfer_type transferType = TRANSFER_DEFAULT);
/* Result of constructing the AudioTrack. This must be checked
* before using any AudioTrack API (except for set()), because using
@@ -235,15 +253,16 @@
audio_stream_type_t streamType() const { return mStreamType; }
audio_format_t format() const { return mFormat; }
- /* Return frame size in bytes, which for linear PCM is channelCount * (bit depth per channel / 8).
+ /* Return frame size in bytes, which for linear PCM is
+ * channelCount * (bit depth per channel / 8).
* channelCount is determined from channelMask, and bit depth comes from format.
* For non-linear formats, the frame size is typically 1 byte.
*/
- uint32_t channelCount() const { return mChannelCount; }
-
- uint32_t frameCount() const { return mFrameCount; }
size_t frameSize() const { return mFrameSize; }
+ uint32_t channelCount() const { return mChannelCount; }
+ uint32_t frameCount() const { return mFrameCount; }
+
/* Return the static buffer specified in constructor or set(), or 0 for streaming mode */
sp<IMemory> sharedBuffer() const { return mSharedBuffer; }
@@ -255,10 +274,9 @@
/* Stop a track.
* In static buffer mode, the track is stopped immediately.
- * In streaming mode, the callback will cease being called and
- * obtainBuffer returns STOPPED. Note that obtainBuffer() still works
- * and will fill up buffers until the pool is exhausted.
- * The stop does not occur immediately: any data remaining in the buffer
+ * In streaming mode, the callback will cease being called. Note that obtainBuffer() still
+ * works and will fill up buffers until the pool is exhausted, and then will return WOULD_BLOCK.
+ * In streaming mode the stop does not occur immediately: any data remaining in the buffer
* is first drained, mixed, and output, and only then is the track marked as stopped.
*/
void stop();
@@ -272,7 +290,7 @@
void flush();
/* Pause a track. After pause, the callback will cease being called and
- * obtainBuffer returns STOPPED. Note that obtainBuffer() still works
+ * obtainBuffer returns WOULD_BLOCK. Note that obtainBuffer() still works
* and will fill up buffers until the pool is exhausted.
* Volume is ramped down over the next mix buffer following the pause request,
* and then the track is marked as paused. It can be resumed with ramp up by start().
@@ -296,11 +314,11 @@
status_t setAuxEffectSendLevel(float level);
void getAuxEffectSendLevel(float* level) const;
- /* Set sample rate for this track in Hz, mostly used for games' sound effects
+ /* Set source sample rate for this track in Hz, mostly used for games' sound effects
*/
status_t setSampleRate(uint32_t sampleRate);
- /* Return current sample rate in Hz, or 0 if unknown */
+ /* Return current source sample rate in Hz, or 0 if unknown */
uint32_t getSampleRate() const;
/* Enables looping and sets the start and end points of looping.
@@ -322,7 +340,7 @@
* loopCount != 0 implies 0 <= loopStart < loopEnd <= frameCount().
*
* If the loop period (loopEnd - loopStart) is too small for the implementation to support,
- * setLoop() will return BAD_VALUE.
+ * setLoop() will return BAD_VALUE. loopCount must be >= -1.
*
*/
status_t setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount);
@@ -330,7 +348,7 @@
/* Sets marker position. When playback reaches the number of frames specified, a callback with
* event type EVENT_MARKER is called. Calling setMarkerPosition with marker == 0 cancels marker
* notification callback. To set a marker at a position which would compute as 0,
- * a workaround is to the set the marker at a nearby position such as -1 or 1.
+ * a workaround is to the set the marker at a nearby position such as ~0 or 1.
* If the AudioTrack has been opened with no callback function associated, the operation will
* fail.
*
@@ -390,16 +408,22 @@
/* Return the total number of frames played since playback start.
* The counter will wrap (overflow) periodically, e.g. every ~27 hours at 44.1 kHz.
* It is reset to zero by flush(), reload(), and stop().
+ *
+ * Parameters:
+ *
+ * position: Address where to return play head position.
+ *
+ * Returned status (from utils/Errors.h) can be:
+ * - NO_ERROR: successful operation
+ * - BAD_VALUE: position is NULL
*/
- status_t getPosition(uint32_t *position);
+ status_t getPosition(uint32_t *position) const;
-#if 0
/* For static buffer mode only, this returns the current playback position in frames
* relative to start of buffer. It is analogous to the new API for
* setLoop() and setPosition(). After underrun, the position will be at end of buffer.
*/
status_t getBufferPosition(uint32_t *position);
-#endif
/* Forces AudioTrack buffer full condition. When playing a static buffer, this method avoids
* rewriting the buffer before restarting playback after a stop.
@@ -446,15 +470,19 @@
*/
status_t attachAuxEffect(int effectId);
- /* Obtains a buffer of "frameCount" frames. The buffer must be
- * filled entirely, and then released with releaseBuffer().
- * If the track is stopped, obtainBuffer() returns
- * STOPPED instead of NO_ERROR as long as there are buffers available,
- * at which point NO_MORE_BUFFERS is returned.
+ /* Obtains a buffer of up to "audioBuffer->frameCount" empty slots for frames.
+ * After filling these slots with data, the caller should release them with releaseBuffer().
+ * If the track buffer is not full, obtainBuffer() returns as many contiguous
+ * [empty slots for] frames as are available immediately.
+ * If the track buffer is full and track is stopped, obtainBuffer() returns WOULD_BLOCK
+ * regardless of the value of waitCount.
+ * If the track buffer is full and track is not stopped, obtainBuffer() blocks with a
+ * maximum timeout based on waitCount; see chart below.
* Buffers will be returned until the pool
* is exhausted, at which point obtainBuffer() will either block
- * or return WOULD_BLOCK depending on the value of the "blocking"
+ * or return WOULD_BLOCK depending on the value of the "waitCount"
* parameter.
+ * Each sample is 16-bit signed PCM.
*
* obtainBuffer() and releaseBuffer() are deprecated for direct use by applications,
* which should use write() or callback EVENT_MORE_DATA instead.
@@ -477,24 +505,35 @@
* raw pointer to the buffer
*/
- enum {
- NO_MORE_BUFFERS = 0x80000001, // same name in AudioFlinger.h, ok to be different value
- STOPPED = 1
- };
+ /* FIXME Deprecated public API for TRANSFER_OBTAIN mode */
+ status_t obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
+ __attribute__((__deprecated__));
- status_t obtainBuffer(Buffer* audioBuffer, int32_t waitCount);
+private:
+ /* New internal API
+ * If nonContig is non-NULL, it is an output parameter that will be set to the number of
+ * additional non-contiguous frames that are available immediately.
+ * FIXME We could pass an array of Buffers instead of only one Buffer to obtainBuffer(),
+ * in case the requested amount of frames is in two or more non-contiguous regions.
+ * FIXME requested and elapsed are both relative times. Consider changing to absolute time.
+ */
+ status_t obtainBuffer(Buffer* audioBuffer, const struct timespec *requested,
+ struct timespec *elapsed = NULL, size_t *nonContig = NULL);
+public:
- /* Release a filled buffer of "frameCount" frames for AudioFlinger to process. */
+ /* Release a filled buffer of "audioBuffer->frameCount" frames for AudioFlinger to process. */
+ // FIXME make private when obtainBuffer() for TRANSFER_OBTAIN is removed
void releaseBuffer(Buffer* audioBuffer);
/* As a convenience we provide a write() interface to the audio buffer.
+ * Input parameter 'size' is in byte units.
* This is implemented on top of obtainBuffer/releaseBuffer. For best
* performance use callbacks. Returns actual number of bytes written >= 0,
* or one of the following negative status codes:
* INVALID_OPERATION AudioTrack is configured for shared buffer mode
* BAD_VALUE size is invalid
- * STOPPED AudioTrack was stopped during the write
- * NO_MORE_BUFFERS when obtainBuffer() returns same
+ * WOULD_BLOCK when obtainBuffer() returns same, or
+ * AudioTrack was stopped during the write
* or any other error code returned by IAudioTrack::start() or restoreTrack_l().
* Not supported for static buffer mode.
*/
@@ -503,7 +542,13 @@
/*
* Dumps the state of an audio track.
*/
- status_t dump(int fd, const Vector<String16>& args) const;
+ status_t dump(int fd, const Vector<String16>& args) const;
+
+ /*
+ * Return the total number of frames which AudioFlinger desired but were unavailable,
+ * and thus which resulted in an underrun. Reset to zero by stop().
+ */
+ uint32_t getUnderrunFrames() const;
protected:
/* copying audio tracks is not allowed */
@@ -522,19 +567,29 @@
void pause(); // suspend thread from execution at next loop boundary
void resume(); // allow thread to execute, if not requested to exit
+ void pauseConditional();
+ // like pause(), but only if prior resume() wasn't latched
private:
friend class AudioTrack;
virtual bool threadLoop();
- AudioTrack& mReceiver;
- ~AudioTrackThread();
+ AudioTrack& mReceiver;
+ virtual ~AudioTrackThread();
Mutex mMyLock; // Thread::mLock is private
Condition mMyCond; // Thread::mThreadExitedCondition is private
bool mPaused; // whether thread is currently paused
+ bool mResumeLatch; // whether next pauseConditional() will be a nop
};
// body of AudioTrackThread::threadLoop()
- bool processAudioBuffer(const sp<AudioTrackThread>& thread);
+ // returns the maximum amount of time before we would like to run again, where:
+ // 0 immediately
+ // > 0 no later than this many nanoseconds from now
+ // NS_WHENEVER still active but no particular deadline
+ // NS_INACTIVE inactive so don't run again until re-started
+ // NS_NEVER never again
+ static const nsecs_t NS_WHENEVER = -1, NS_INACTIVE = -2, NS_NEVER = -3;
+ nsecs_t processAudioBuffer(const sp<AudioTrackThread>& thread);
// caller must hold lock on mLock for all _l methods
status_t createTrack_l(audio_stream_type_t streamType,
@@ -543,20 +598,24 @@
size_t frameCount,
audio_output_flags_t flags,
const sp<IMemory>& sharedBuffer,
- audio_io_handle_t output);
+ audio_io_handle_t output,
+ size_t epoch);
- // can only be called when !mActive
+ // can only be called when mState != STATE_ACTIVE
void flush_l();
- status_t setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount);
+ void setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount);
audio_io_handle_t getOutput_l();
- status_t restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart);
- bool stopped_l() const { return !mActive; }
+ // FIXME enum is faster than strcmp() for parameter 'from'
+ status_t restoreTrack_l(const char *from);
+
+ // may be changed if IAudioTrack is re-created
sp<IAudioTrack> mAudioTrack;
sp<IMemory> mCblkMemory;
- sp<AudioTrackThread> mAudioTrackThread;
+ audio_track_cblk_t* mCblk; // re-load after mLock.unlock()
+ sp<AudioTrackThread> mAudioTrackThread;
float mVolume[2];
float mSendLevel;
uint32_t mSampleRate;
@@ -564,62 +623,89 @@
size_t mReqFrameCount; // frame count to request the next time a new
// IAudioTrack is needed
- audio_track_cblk_t* mCblk; // re-load after mLock.unlock()
- // Starting address of buffers in shared memory. If there is a shared buffer, mBuffers
- // is the value of pointer() for the shared buffer, otherwise mBuffers points
- // immediately after the control block. This address is for the mapping within client
- // address space. AudioFlinger::TrackBase::mBuffer is for the server address space.
- void* mBuffers;
-
+ // constant after constructor or set()
audio_format_t mFormat; // as requested by client, not forced to 16-bit
audio_stream_type_t mStreamType;
uint32_t mChannelCount;
audio_channel_mask_t mChannelMask;
+ transfer_type mTransfer;
- // mFrameSize is equal to mFrameSizeAF for non-PCM or 16-bit PCM data.
- // For 8-bit PCM data, mFrameSizeAF is
- // twice as large because data is expanded to 16-bit before being stored in buffer.
+ // mFrameSize is equal to mFrameSizeAF for non-PCM or 16-bit PCM data. For 8-bit PCM data, it's
+ // twice as large as mFrameSize because data is expanded to 16-bit before it's stored in buffer.
size_t mFrameSize; // app-level frame size
size_t mFrameSizeAF; // AudioFlinger frame size
status_t mStatus;
- uint32_t mLatency;
- bool mActive; // protected by mLock
+ // can change dynamically when IAudioTrack invalidated
+ uint32_t mLatency; // in ms
+
+ // Indicates the current track state. Protected by mLock.
+ enum State {
+ STATE_ACTIVE,
+ STATE_STOPPED,
+ STATE_PAUSED,
+ STATE_FLUSHED,
+ } mState;
callback_t mCbf; // callback handler for events, or NULL
void* mUserData; // for client callback handler
// for notification APIs
uint32_t mNotificationFramesReq; // requested number of frames between each
- // notification callback
+ // notification callback,
+ // at initial source sample rate
uint32_t mNotificationFramesAct; // actual number of frames between each
- // notification callback
+ // notification callback,
+ // at initial source sample rate
+ bool mRefreshRemaining; // processAudioBuffer() should refresh next 2
+
+ // These are private to processAudioBuffer(), and are not protected by a lock
+ uint32_t mRemainingFrames; // number of frames to request in obtainBuffer()
+ bool mRetryOnPartialBuffer; // sleep and retry after partial obtainBuffer()
+ int mObservedSequence; // last observed value of mSequence
+
sp<IMemory> mSharedBuffer;
- int mLoopCount;
- uint32_t mRemainingFrames;
+ uint32_t mLoopPeriod; // in frames, zero means looping is disabled
uint32_t mMarkerPosition; // in wrapping (overflow) frame units
bool mMarkerReached;
uint32_t mNewPosition; // in frames
- uint32_t mUpdatePeriod; // in frames
+ uint32_t mUpdatePeriod; // in frames, zero means no EVENT_NEW_POS
- bool mFlushed; // FIXME will be made obsolete by making flush() synchronous
audio_output_flags_t mFlags;
int mSessionId;
int mAuxEffectId;
- // When locking both mLock and mCblk->lock, must lock in this order to avoid deadlock:
- // 1. mLock
- // 2. mCblk->lock
- // It is OK to lock only mCblk->lock.
mutable Mutex mLock;
bool mIsTimed;
int mPreviousPriority; // before start()
SchedPolicy mPreviousSchedulingGroup;
- AudioTrackClientProxy* mProxy;
bool mAwaitBoost; // thread should wait for priority boost before running
+
+ // The proxy should only be referenced while a lock is held because the proxy isn't
+ // multi-thread safe, especially the SingleStateQueue part of the proxy.
+ // An exception is that a blocking ClientProxy::obtainBuffer() may be called without a lock,
+ // provided that the caller also holds an extra reference to the proxy and shared memory to keep
+ // them around in case they are replaced during the obtainBuffer().
+ sp<StaticAudioTrackClientProxy> mStaticProxy; // for type safety only
+ sp<AudioTrackClientProxy> mProxy; // primary owner of the memory
+
+ bool mInUnderrun; // whether track is currently in underrun state
+
+private:
+ class DeathNotifier : public IBinder::DeathRecipient {
+ public:
+ DeathNotifier(AudioTrack* audioTrack) : mAudioTrack(audioTrack) { }
+ protected:
+ virtual void binderDied(const wp<IBinder>& who);
+ private:
+ const wp<AudioTrack> mAudioTrack;
+ };
+
+ sp<DeathNotifier> mDeathNotifier;
+ uint32_t mSequence; // incremented for each new IAudioTrack attempt
};
class TimedAudioTrack : public AudioTrack