summaryrefslogtreecommitdiffstats
path: root/include
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
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')
-rw-r--r--include/media/AudioBufferProvider.h15
-rw-r--r--include/media/AudioRecord.h251
-rw-r--r--include/media/AudioTrack.h274
-rw-r--r--include/private/media/AudioTrackShared.h391
4 files changed, 637 insertions, 294 deletions
diff --git a/include/media/AudioBufferProvider.h b/include/media/AudioBufferProvider.h
index 43e4de7..ef392f0 100644
--- a/include/media/AudioBufferProvider.h
+++ b/include/media/AudioBufferProvider.h
@@ -26,6 +26,8 @@ class AudioBufferProvider
{
public:
+ // FIXME merge with AudioTrackShared::Buffer, AudioTrack::Buffer, and AudioRecord::Buffer
+ // and rename getNextBuffer() to obtainBuffer()
struct Buffer {
Buffer() : raw(NULL), frameCount(0) { }
union {
@@ -44,6 +46,19 @@ public:
// pts is the local time when the next sample yielded by getNextBuffer
// will be rendered.
// Pass kInvalidPTS if the PTS is unknown or not applicable.
+ // On entry:
+ // buffer != NULL
+ // buffer->raw unused
+ // buffer->frameCount maximum number of desired frames
+ // On successful return:
+ // status NO_ERROR
+ // buffer->raw non-NULL pointer to buffer->frameCount contiguous available frames
+ // buffer->frameCount number of contiguous available frames at buffer->raw,
+ // 0 < buffer->frameCount <= entry value
+ // On error return:
+ // status != NO_ERROR
+ // buffer->raw NULL
+ // buffer->frameCount 0
virtual status_t getNextBuffer(Buffer* buffer, int64_t pts = kInvalidPTS) = 0;
virtual void releaseBuffer(Buffer* buffer) = 0;
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 38c6548..81be803 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -14,26 +14,24 @@
* limitations under the License.
*/
-#ifndef AUDIORECORD_H_
-#define AUDIORECORD_H_
+#ifndef ANDROID_AUDIORECORD_H
+#define ANDROID_AUDIORECORD_H
-#include <binder/IMemory.h>
#include <cutils/sched_policy.h>
#include <media/AudioSystem.h>
#include <media/IAudioRecord.h>
-#include <system/audio.h>
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
#include <utils/threads.h>
namespace android {
+// ----------------------------------------------------------------------------
+
class audio_track_cblk_t;
class AudioRecordClientProxy;
// ----------------------------------------------------------------------------
-class AudioRecord : virtual public RefBase
+class AudioRecord : public RefBase
{
public:
@@ -49,6 +47,8 @@ public:
// (See setMarkerPosition()).
EVENT_NEW_POS = 3, // Record head is at a new position
// (See setPositionUpdatePeriod()).
+ EVENT_NEW_IAUDIORECORD = 4, // IAudioRecord 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()
@@ -58,11 +58,16 @@ public:
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 available,
// on output is the number of frames actually drained
- size_t size; // total size in bytes == frameCount * frameSize
+ 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
@@ -84,6 +89,7 @@ public:
* - EVENT_OVERRUN: unused.
* - 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_NEW_IAUDIORECORD: unused.
*/
typedef void (*callback_t)(int event, void* user, void *info);
@@ -101,20 +107,28 @@ public:
audio_format_t format,
audio_channel_mask_t channelMask);
+ /* How data is transferred from AudioRecord
+ */
+ enum transfer_type {
+ TRANSFER_DEFAULT, // not specified explicitly; determine from other parameters
+ TRANSFER_CALLBACK, // callback EVENT_MORE_DATA
+ TRANSFER_OBTAIN, // FIXME deprecated: call obtainBuffer() and releaseBuffer()
+ TRANSFER_SYNC, // synchronous read()
+ };
+
/* Constructs an uninitialized AudioRecord. No connection with
- * AudioFlinger takes place.
+ * AudioFlinger takes place. Use set() after this.
*/
AudioRecord();
/* Creates an AudioRecord object and registers it with AudioFlinger.
* Once created, the track needs to be started before it can be used.
- * Unspecified values are set to the audio hardware's current
- * values.
+ * Unspecified values are set to appropriate default values.
*
* Parameters:
*
- * inputSource: Select the audio input to record to (e.g. AUDIO_SOURCE_DEFAULT).
- * sampleRate: Track sampling rate in Hz.
+ * inputSource: Select the audio input to record from (e.g. AUDIO_SOURCE_DEFAULT).
+ * sampleRate: Data sink sampling rate in Hz.
* format: Audio format (e.g AUDIO_FORMAT_PCM_16_BIT for signed
* 16 bits per sample).
* channelMask: Channel mask.
@@ -124,11 +138,13 @@ public:
* be larger if the requested size is not compatible with current audio HAL
* latency. Zero means to use a default value.
* cbf: Callback function. If not null, this function is called periodically
- * to consume new PCM data.
+ * to consume new PCM data and inform of marker, position updates, etc.
* user: Context for use by the callback receiver.
* notificationFrames: The callback function is called each time notificationFrames PCM
* frames are ready in record track output buffer.
* sessionId: Not yet supported.
+ * transferType: How data is transferred from AudioRecord.
+ * threadCanCallJava: Not present in parameter list, and so is fixed at false.
*/
AudioRecord(audio_source_t inputSource,
@@ -139,22 +155,26 @@ public:
callback_t cbf = NULL,
void* user = NULL,
int notificationFrames = 0,
- int sessionId = 0);
-
+ int sessionId = 0,
+ transfer_type transferType = TRANSFER_DEFAULT);
/* Terminates the AudioRecord and unregisters it from AudioFlinger.
* Also destroys all resources associated with the AudioRecord.
*/
~AudioRecord();
-
- /* Initialize an uninitialized AudioRecord.
+ /* Initialize an AudioRecord that was created using the AudioRecord() constructor.
+ * Don't call set() more than once, or after an AudioRecord() constructor that takes parameters.
* Returned status (from utils/Errors.h) can be:
* - NO_ERROR: successful intialization
- * - INVALID_OPERATION: AudioRecord is already intitialized or record device is already in use
+ * - INVALID_OPERATION: AudioRecord is already initialized or record device is already in use
* - BAD_VALUE: invalid parameter (channels, format, sampleRate...)
* - NO_INIT: audio server or audio hardware not initialized
* - PERMISSION_DENIED: recording is not allowed for the requesting process
+ *
+ * Parameters not listed in the AudioRecord constructors above:
+ *
+ * threadCanCallJava: Whether callbacks are made from an attached thread and thus can call JNI.
*/
status_t set(audio_source_t inputSource = AUDIO_SOURCE_DEFAULT,
uint32_t sampleRate = 0,
@@ -165,30 +185,29 @@ public:
void* user = NULL,
int notificationFrames = 0,
bool threadCanCallJava = false,
- int sessionId = 0);
-
+ int sessionId = 0,
+ transfer_type transferType = TRANSFER_DEFAULT);
/* Result of constructing the AudioRecord. This must be checked
* before using any AudioRecord API (except for set()), because using
* an uninitialized AudioRecord produces undefined results.
* See set() method above for possible return codes.
*/
- status_t initCheck() const;
+ status_t initCheck() const { return mStatus; }
/* Returns this track's estimated latency in milliseconds.
* This includes the latency due to AudioRecord buffer size,
* and audio hardware driver.
*/
- uint32_t latency() const;
+ uint32_t latency() const { return mLatency; }
/* getters, see constructor and set() */
- audio_format_t format() const;
- uint32_t channelCount() const;
- size_t frameCount() const;
- size_t frameSize() const { return mFrameSize; }
- audio_source_t inputSource() const;
-
+ audio_format_t format() const { return mFormat; }
+ uint32_t channelCount() const { return mChannelCount; }
+ size_t frameCount() const { return mFrameCount; }
+ size_t frameSize() const { return mFrameSize; }
+ audio_source_t inputSource() const { return mInputSource; }
/* After it's created the track is not active. Call start() to
* make it active. If set, the callback will start being called.
@@ -198,26 +217,29 @@ public:
status_t start(AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
int triggerSession = 0);
- /* Stop a track. If set, the callback will cease being called and
- * obtainBuffer returns STOPPED. Note that obtainBuffer() still works
- * and will drain buffers until the pool is exhausted.
+ /* Stop a track. If set, the callback will cease being called. Note that obtainBuffer() still
+ * works and will drain buffers until the pool is exhausted, and then will return WOULD_BLOCK.
*/
void stop();
bool stopped() const;
- /* Get sample rate for this record track in Hz.
+ /* Return the sink sample rate for this record track in Hz.
+ * Unlike AudioTrack, the sample rate is const after initialization, so doesn't need a lock.
*/
- uint32_t getSampleRate() const;
+ uint32_t getSampleRate() const { return mSampleRate; }
/* Sets marker position. When record 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 ~0 or 1.
* If the AudioRecord has been opened with no callback function associated,
* the operation will fail.
*
* Parameters:
*
- * marker: marker position expressed in frames.
+ * marker: marker position expressed in wrapping (overflow) frame units,
+ * like the return value of getPosition().
*
* Returned status (from utils/Errors.h) can be:
* - NO_ERROR: successful operation
@@ -226,13 +248,13 @@ public:
status_t setMarkerPosition(uint32_t marker);
status_t getMarkerPosition(uint32_t *marker) const;
-
/* Sets position update period. Every time the number of frames specified has been recorded,
* a callback with event type EVENT_NEW_POS is called.
* Calling setPositionUpdatePeriod with updatePeriod == 0 cancels new position notification
* callback.
* If the AudioRecord has been opened with no callback function associated,
* the operation will fail.
+ * Extremely small values may be rounded up to a value the implementation can support.
*
* Parameters:
*
@@ -245,13 +267,13 @@ public:
status_t setPositionUpdatePeriod(uint32_t updatePeriod);
status_t getPositionUpdatePeriod(uint32_t *updatePeriod) const;
-
- /* Gets record head position. The position is the total number of frames
- * recorded since record start.
+ /* Return the total number of frames recorded since recording started.
+ * The counter will wrap (overflow) periodically, e.g. every ~27 hours at 44.1 kHz.
+ * It is reset to zero by stop().
*
* Parameters:
*
- * position: Address where to return record head position within AudioRecord buffer.
+ * position: Address where to return record head position.
*
* Returned status (from utils/Errors.h) can be:
* - NO_ERROR: successful operation
@@ -276,38 +298,70 @@ public:
*
* Returned value:
* AudioRecord session ID.
+ *
+ * No lock needed because session ID doesn't change after first set().
*/
- int getSessionId() const;
-
- /* Obtains a buffer of "frameCount" frames. The buffer must be
- * drained 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.
+ int getSessionId() const { return mSessionId; }
+
+ /* Obtains a buffer of up to "audioBuffer->frameCount" full frames.
+ * After draining these frames of data, the caller should release them with releaseBuffer().
+ * If the track buffer is not empty, obtainBuffer() returns as many contiguous
+ * full frames as are available immediately.
+ * If the track buffer is empty and track is stopped, obtainBuffer() returns WOULD_BLOCK
+ * regardless of the value of waitCount.
+ * If the track buffer is empty 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.
*
+ * obtainBuffer() and releaseBuffer() are deprecated for direct use by applications,
+ * which should use read() or callback EVENT_MORE_DATA instead.
+ *
* Interpretation of waitCount:
* +n limits wait time to n * WAIT_PERIOD_MS,
* -1 causes an (almost) infinite wait time,
* 0 non-blocking.
+ *
+ * Buffer fields
+ * On entry:
+ * frameCount number of frames requested
+ * After error return:
+ * frameCount 0
+ * size 0
+ * raw undefined
+ * After successful return:
+ * frameCount actual number of frames available, <= number requested
+ * size actual number of bytes available
+ * 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 an emptied buffer of "frameCount" frames for AudioFlinger to re-fill. */
+ /* Release an emptied buffer of "audioBuffer->frameCount" frames for AudioFlinger to re-fill. */
+ // FIXME make private when obtainBuffer() for TRANSFER_OBTAIN is removed
void releaseBuffer(Buffer* audioBuffer);
-
/* As a convenience we provide a read() interface to the audio buffer.
- * This is implemented on top of obtainBuffer/releaseBuffer.
+ * 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 read >= 0,
+ * or a negative status code.
*/
ssize_t read(void* buffer, size_t size);
@@ -336,68 +390,113 @@ private:
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 AudioRecord;
virtual bool threadLoop();
- AudioRecord& mReceiver;
+ AudioRecord& mReceiver;
virtual ~AudioRecordThread();
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 AudioRecordThread::threadLoop()
- bool processAudioBuffer(const sp<AudioRecordThread>& 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<AudioRecordThread>& thread);
+
+ // caller must hold lock on mLock for all _l methods
status_t openRecord_l(uint32_t sampleRate,
audio_format_t format,
size_t frameCount,
- audio_io_handle_t input);
+ audio_io_handle_t input,
+ size_t epoch);
+
audio_io_handle_t getInput_l();
- status_t restoreRecord_l(audio_track_cblk_t*& cblk);
+
+ // FIXME enum is faster than strcmp() for parameter 'from'
+ status_t restoreRecord_l(const char *from);
sp<AudioRecordThread> mAudioRecordThread;
mutable Mutex mLock;
- bool mActive; // protected by mLock
+ // Current client state: false = stopped, true = active. Protected by mLock. If more states
+ // are added, consider changing this to enum State { ... } mState as in AudioTrack.
+ bool mActive;
// for client callback handler
callback_t mCbf; // callback handler for events, or NULL
- void* mUserData;
+ void* mUserData; // for client callback handler
// for notification APIs
- uint32_t mNotificationFrames;
- uint32_t mRemainingFrames;
- uint32_t mMarkerPosition; // in frames
+ uint32_t mNotificationFrames; // frames between each notification callback
+ 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
+
+ uint32_t mMarkerPosition; // in wrapping (overflow) frame units
bool mMarkerReached;
uint32_t mNewPosition; // in frames
- uint32_t mUpdatePeriod; // in ms
+ uint32_t mUpdatePeriod; // in frames, zero means no EVENT_NEW_POS
+
+ status_t mStatus;
// constant after constructor or set()
uint32_t mSampleRate;
size_t mFrameCount;
audio_format_t mFormat;
- uint8_t mChannelCount;
+ uint32_t mChannelCount;
size_t mFrameSize; // app-level frame size == AudioFlinger frame size
audio_source_t mInputSource;
- status_t mStatus;
- uint32_t mLatency;
+ uint32_t mLatency; // in ms
audio_channel_mask_t mChannelMask;
- audio_io_handle_t mInput; // returned by AudioSystem::getInput()
int mSessionId;
+ transfer_type mTransfer;
+
+ audio_io_handle_t mInput; // returned by AudioSystem::getInput()
// may be changed if IAudioRecord object is re-created
sp<IAudioRecord> mAudioRecord;
sp<IMemory> mCblkMemory;
- audio_track_cblk_t* mCblk;
- void* mBuffers; // starting address of buffers in shared memory
+ audio_track_cblk_t* mCblk; // re-load after mLock.unlock()
- int mPreviousPriority; // before start()
+ int mPreviousPriority; // before start()
SchedPolicy mPreviousSchedulingGroup;
- AudioRecordClientProxy* mProxy;
+
+ // The proxy should only be referenced while a lock is held because the proxy isn't
+ // multi-thread safe.
+ // 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
+ sp<AudioRecordClientProxy> mProxy;
+
+ bool mInOverrun; // whether recorder is currently in overrun state
+
+private:
+ class DeathNotifier : public IBinder::DeathRecipient {
+ public:
+ DeathNotifier(AudioRecord* audioRecord) : mAudioRecord(audioRecord) { }
+ protected:
+ virtual void binderDied(const wp<IBinder>& who);
+ private:
+ const wp<AudioRecord> mAudioRecord;
+ };
+
+ sp<DeathNotifier> mDeathNotifier;
+ uint32_t mSequence; // incremented for each new IAudioRecord attempt
};
}; // namespace android
-#endif /*AUDIORECORD_H_*/
+#endif // ANDROID_AUDIORECORD_H
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 @@ namespace android {
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 @@ public:
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 @@ public:
// (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 @@ public:
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 @@ public:
* 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 @@ public:
* - 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 @@ public:
* 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 @@ public:
* 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 @@ public:
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 @@ public:
* 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 @@ public:
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 @@ protected:
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 @@ public:
* - 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 @@ public:
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,14 +253,15 @@ public:
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; }
+ size_t frameSize() const { return mFrameSize; }
+ uint32_t channelCount() const { return mChannelCount; }
uint32_t frameCount() const { return mFrameCount; }
- size_t frameSize() const { return mFrameSize; }
/* Return the static buffer specified in constructor or set(), or 0 for streaming mode */
sp<IMemory> sharedBuffer() const { return mSharedBuffer; }
@@ -255,10 +274,9 @@ public:
/* 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 @@ public:
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 @@ public:
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 @@ public:
* 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 @@ public:
/* 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 @@ public:
/* 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 @@ public:
*/
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 @@ public:
* 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 @@ public:
/*
* 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 @@ protected:
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 @@ protected:
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 @@ protected:
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
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() { }
};
// ----------------------------------------------------------------------------