From 9f80dd223d83d9bb9077fb6baee056cee4eaf7e5 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 18 Dec 2012 15:57:32 -0800 Subject: 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 --- include/media/AudioBufferProvider.h | 15 ++ include/media/AudioRecord.h | 251 ++++++++++++++------ include/media/AudioTrack.h | 274 ++++++++++++++-------- include/private/media/AudioTrackShared.h | 391 +++++++++++++++++++++---------- 4 files changed, 637 insertions(+), 294 deletions(-) (limited to 'include') 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 #include #include #include -#include -#include -#include #include 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& 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& 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 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 mAudioRecord; sp 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 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& who); + private: + const wp mAudioRecord; + }; + + sp 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 -#include - -#include -#include -#include - -#include -#include -#include -#include #include +#include +#include #include 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& 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 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& args) const; + status_t dump(int fd, const Vector& 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& 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& 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& 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 mAudioTrack; sp mCblkMemory; - sp mAudioTrackThread; + audio_track_cblk_t* mCblk; // re-load after mLock.unlock() + sp 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 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 mStaticProxy; // for type safety only + sp 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& who); + private: + const wp mAudioTrack; + }; + + sp 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 #include +#include +#include +#include +#include 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 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() { } }; // ---------------------------------------------------------------------------- -- cgit v1.1