Merge "audioflinger: define ANDROID_SMP, remove conditional tracing"
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index f1b77ab..6f85527 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -52,8 +52,11 @@
* Keep in sync with frameworks/base/media/java/android/media/AudioTrack.java NATIVE_EVENT_*.
*/
enum event_type {
- EVENT_MORE_DATA = 0, // Request to write more data to PCM buffer.
- EVENT_UNDERRUN = 1, // PCM buffer underrun occurred.
+ EVENT_MORE_DATA = 0, // Request to write more data to buffer.
+ // If this event is delivered but the callback handler
+ // does not want to write more data, the handler must explicitly
+ // ignore the event by setting frameCount to zero.
+ EVENT_UNDERRUN = 1, // Buffer underrun occurred.
EVENT_LOOP_END = 2, // Sample loop end was reached; playback restarted from
// loop start if loop count was not 0.
EVENT_MARKER = 3, // Playback head is at the specified marker position
@@ -115,14 +118,16 @@
uint32_t sampleRate = 0);
/* Constructs an uninitialized AudioTrack. No connection with
- * AudioFlinger takes place.
+ * AudioFlinger takes place. Use set() after this.
*/
AudioTrack();
/* Creates an AudioTrack 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.
+ * 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.
*
* Parameters:
*
@@ -136,10 +141,10 @@
* application's contribution to the
* latency of the track. The actual size selected by the AudioTrack could be
* larger if the requested size is not compatible with current audio HAL
- * latency. Zero means to use a default value.
+ * configuration. Zero means to use a default value.
* flags: See comments on audio_output_flags_t in <system/audio.h>.
* cbf: Callback function. If not null, this function is called periodically
- * to provide new PCM data.
+ * to provide new 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 have been consumed from track input buffer.
@@ -159,13 +164,16 @@
int notificationFrames = 0,
int sessionId = 0);
- /* Creates an audio track and registers it with AudioFlinger. With this constructor,
- * the PCM data to be rendered by AudioTrack is passed in a shared memory buffer
- * identified by the argument sharedBuffer. This prototype is for static buffer playback.
- * PCM data must be present in memory before the AudioTrack is started.
- * The write() and flush() methods are not supported in this case.
+ /* Creates an audio track and registers it with AudioFlinger.
+ * With this constructor, the track is configured for static buffer mode.
+ * The format must not be 8-bit linear PCM.
+ * Data to be rendered is passed in a shared memory buffer
+ * identified by the argument sharedBuffer, which must be non-0.
+ * The memory should be initialized to the desired data before calling start().
+ * 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,
@@ -184,13 +192,14 @@
*/
~AudioTrack();
-
/* Initialize an uninitialized AudioTrack.
* Returned status (from utils/Errors.h) can be:
* - NO_ERROR: successful initialization
* - INVALID_OPERATION: AudioTrack is already initialized
* - BAD_VALUE: invalid parameter (channelMask, format, sampleRate...)
* - 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.
*/
status_t set(audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT,
uint32_t sampleRate = 0,
@@ -205,64 +214,68 @@
bool threadCanCallJava = false,
int sessionId = 0);
-
/* Result of constructing the AudioTrack. This must be checked
* before using any AudioTrack API (except for set()), because using
* an uninitialized AudioTrack 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 AudioTrack buffer size, AudioMixer (if any)
* and audio hardware driver.
*/
- uint32_t latency() const;
+ uint32_t latency() const { return mLatency; }
/* getters, see constructors and set() */
- audio_stream_type_t streamType() const;
- audio_format_t format() const;
- uint32_t channelCount() const;
- uint32_t frameCount() const;
+ audio_stream_type_t streamType() const { return mStreamType; }
+ audio_format_t format() const { return mFormat; }
- /* Return 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.
*/
- size_t frameSize() const { return mFrameSize; }
+ uint32_t channelCount() const { return mChannelCount; }
- sp<IMemory>& sharedBuffer();
+ 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; }
/* After it's created the track is not active. Call start() to
* make it active. If set, the callback will start being called.
+ * If the track was previously paused, volume is ramped up over the first mix buffer.
*/
void start();
- /* Stop a track. If set, the callback will cease being called and
+ /* 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
+ * is first drained, mixed, and output, and only then is the track marked as stopped.
*/
void stop();
bool stopped() const;
- /* Flush a stopped track. All pending buffers are discarded.
- * This function has no effect if the track is not stopped.
+ /* Flush a stopped or paused track. All previously buffered data is discarded immediately.
+ * This has the effect of draining the buffers without mixing or output.
+ * Flush is intended for streaming mode, for example before switching to non-contiguous content.
+ * This function is a no-op if the track is not stopped or paused, or uses a static buffer.
*/
void flush();
- /* Pause a track. If set, the callback will cease being called and
+ /* Pause a track. After pause, 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.
+ * 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().
*/
void pause();
- /* Mute or unmute this track.
- * While muted, the callback, if set, is still called.
- */
- void mute(bool);
- bool muted() const;
-
/* Set volume for this track, mostly used for games' sound effects
* left and right volumes. Levels must be >= 0.0 and <= 1.0.
* This is the older API. New applications should use setVolume(float) when possible.
@@ -288,6 +301,7 @@
uint32_t getSampleRate() const;
/* Enables looping and sets the start and end points of looping.
+ * Only supported for static buffer mode.
*
* Parameters:
*
@@ -303,13 +317,15 @@
/* 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.
+ * 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.
* If the AudioTrack 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
@@ -318,13 +334,13 @@
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 played,
* a callback with event type EVENT_NEW_POS is called.
* Calling setPositionUpdatePeriod with updatePeriod == 0 cancels new position notification
* callback.
* If the AudioTrack 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:
*
@@ -352,20 +368,26 @@
*
* Returned status (from utils/Errors.h) can be:
* - NO_ERROR: successful operation
- * - INVALID_OPERATION: the AudioTrack is not stopped.
+ * - INVALID_OPERATION: the AudioTrack is not stopped or paused, or is streaming mode.
* - BAD_VALUE: The specified position is beyond the number of frames present in AudioTrack
* buffer
*/
status_t setPosition(uint32_t position);
+
+ /* 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().
+ */
status_t getPosition(uint32_t *position);
/* Forces AudioTrack buffer full condition. When playing a static buffer, this method avoids
* rewriting the buffer before restarting playback after a stop.
* This method must be called with the AudioTrack in paused or stopped state.
+ * Not allowed in streaming mode.
*
* Returned status (from utils/Errors.h) can be:
* - NO_ERROR: successful operation
- * - INVALID_OPERATION: the AudioTrack is not stopped.
+ * - INVALID_OPERATION: the AudioTrack is not stopped or paused, or is streaming mode.
*/
status_t reload();
@@ -387,7 +409,7 @@
* Returned value:
* AudioTrack session ID.
*/
- int getSessionId() const;
+ int getSessionId() const { return mSessionId; }
/* Attach track auxiliary output to specified effect. Use effectId = 0
* to detach track from effect.
@@ -413,6 +435,9 @@
* or return WOULD_BLOCK depending on the value of the "blocking"
* parameter.
*
+ * obtainBuffer() and releaseBuffer() are deprecated for direct use by applications,
+ * which should use write() 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,
@@ -450,6 +475,7 @@
* STOPPED AudioTrack was stopped during the write
* NO_MORE_BUFFERS when obtainBuffer() returns same
* or any other error code returned by IAudioTrack::start() or restoreTrack_l().
+ * Not supported for static buffer mode.
*/
ssize_t write(const void* buffer, size_t size);
@@ -497,7 +523,10 @@
audio_output_flags_t flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output);
+
+ // can only be called when !mActive
void flush_l();
+
status_t 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);
@@ -523,9 +552,7 @@
audio_format_t mFormat; // as requested by client, not forced to 16-bit
audio_stream_type_t mStreamType;
- uint8_t mChannelCount;
- uint8_t mMuted;
- uint8_t mReserved;
+ uint32_t mChannelCount;
audio_channel_mask_t mChannelMask;
// mFrameSize is equal to mFrameSizeAF for non-PCM or 16-bit PCM data.
@@ -550,7 +577,7 @@
sp<IMemory> mSharedBuffer;
int mLoopCount;
uint32_t mRemainingFrames;
- uint32_t mMarkerPosition; // in frames
+ uint32_t mMarkerPosition; // in wrapping (overflow) frame units
bool mMarkerReached;
uint32_t mNewPosition; // in frames
uint32_t mUpdatePeriod; // in frames
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
index 9e0e389..144be0e 100644
--- a/include/media/IAudioTrack.h
+++ b/include/media/IAudioTrack.h
@@ -54,11 +54,6 @@
*/
virtual void flush() = 0;
- /* Mute or unmute this track.
- * While muted, the callback, if set, is still called.
- */
- virtual void mute(bool) = 0;
-
/* Pause a track. If set, the callback will cease being called and
* obtainBuffer will return an error. Buffers that are already released
* will continue to be processed, unless/until flush() is called.
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index f2b6441..a35d562 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -13,6 +13,7 @@
LOCAL_SRC_FILES:= \
AudioTrack.cpp \
+ AudioTrackShared.cpp \
IAudioFlinger.cpp \
IAudioFlingerClient.cpp \
IAudioTrack.cpp \
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index e40895a..1d87ff8 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -138,6 +138,11 @@
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT)
{
+ if (sharedBuffer == 0) {
+ ALOGE("sharedBuffer must be non-0");
+ mStatus = BAD_VALUE;
+ return;
+ }
mStatus = set(streamType, sampleRate, format, channelMask,
0 /*frameCount*/, flags, cbf, user, notificationFrames,
sharedBuffer, false /*threadCanCallJava*/, sessionId);
@@ -304,7 +309,6 @@
}
mSharedBuffer = sharedBuffer;
- mMuted = false;
mActive = false;
mUserData = user;
mLoopCount = 0;
@@ -317,43 +321,6 @@
return NO_ERROR;
}
-status_t AudioTrack::initCheck() const
-{
- return mStatus;
-}
-
-// -------------------------------------------------------------------------
-
-uint32_t AudioTrack::latency() const
-{
- return mLatency;
-}
-
-audio_stream_type_t AudioTrack::streamType() const
-{
- return mStreamType;
-}
-
-audio_format_t AudioTrack::format() const
-{
- return mFormat;
-}
-
-uint32_t AudioTrack::channelCount() const
-{
- return mChannelCount;
-}
-
-size_t AudioTrack::frameCount() const
-{
- return mFrameCount;
-}
-
-sp<IMemory>& AudioTrack::sharedBuffer()
-{
- return mSharedBuffer;
-}
-
// -------------------------------------------------------------------------
void AudioTrack::start()
@@ -435,6 +402,7 @@
mMarkerReached = false;
// Force flush if a shared buffer is used otherwise audioflinger
// will not stop before end of buffer is reached.
+ // It may be needed to make sure that we stop playback, likely in case looping is on.
if (mSharedBuffer != 0) {
flush_l();
}
@@ -457,26 +425,26 @@
void AudioTrack::flush()
{
AutoMutex lock(mLock);
- flush_l();
+ if (!mActive && mSharedBuffer == 0) {
+ flush_l();
+ }
}
-// must be called with mLock held
void AudioTrack::flush_l()
{
ALOGV("flush");
+ ALOG_ASSERT(!mActive);
// clear playback marker and periodic update counter
mMarkerPosition = 0;
mMarkerReached = false;
mUpdatePeriod = 0;
- if (!mActive) {
- mFlushed = true;
- mAudioTrack->flush();
- // Release AudioTrack callback thread in case it was waiting for new buffers
- // in AudioTrack::obtainBuffer()
- mCblk->cv.signal();
- }
+ mFlushed = true;
+ mAudioTrack->flush();
+ // Release AudioTrack callback thread in case it was waiting for new buffers
+ // in AudioTrack::obtainBuffer()
+ mCblk->cv.signal();
}
void AudioTrack::pause()
@@ -490,17 +458,6 @@
}
}
-void AudioTrack::mute(bool e)
-{
- mAudioTrack->mute(e);
- mMuted = e;
-}
-
-bool AudioTrack::muted() const
-{
- return mMuted;
-}
-
status_t AudioTrack::setVolume(float left, float right)
{
if (left < 0.0f || left > 1.0f || right < 0.0f || right > 1.0f) {
@@ -583,6 +540,10 @@
// must be called with mLock held
status_t AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount)
{
+ if (mSharedBuffer == 0 || mIsTimed) {
+ return INVALID_OPERATION;
+ }
+
audio_track_cblk_t* cblk = mCblk;
Mutex::Autolock _l(cblk->lock);
@@ -595,10 +556,6 @@
return NO_ERROR;
}
- if (mIsTimed) {
- return INVALID_OPERATION;
- }
-
if (loopStart >= loopEnd ||
loopEnd - loopStart > mFrameCount ||
cblk->server > loopStart) {
@@ -672,7 +629,7 @@
status_t AudioTrack::setPosition(uint32_t position)
{
- if (mIsTimed) {
+ if (mSharedBuffer == 0 || mIsTimed) {
return INVALID_OPERATION;
}
@@ -708,6 +665,10 @@
status_t AudioTrack::reload()
{
+ if (mSharedBuffer == 0 || mIsTimed) {
+ return INVALID_OPERATION;
+ }
+
AutoMutex lock(mLock);
if (!stopped_l()) {
@@ -735,11 +696,6 @@
mCblk->sampleRate, mFormat, mChannelMask, mFlags);
}
-int AudioTrack::getSessionId() const
-{
- return mSessionId;
-}
-
status_t AudioTrack::attachAuxEffect(int effectId)
{
ALOGV("attachAuxEffect(%d)", effectId);
@@ -1089,10 +1045,7 @@
ssize_t AudioTrack::write(const void* buffer, size_t userSize)
{
- if (mSharedBuffer != 0) {
- return INVALID_OPERATION;
- }
- if (mIsTimed) {
+ if (mSharedBuffer != 0 || mIsTimed) {
return INVALID_OPERATION;
}
@@ -1471,8 +1424,8 @@
snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%d)\n", mFormat,
mChannelCount, mFrameCount);
result.append(buffer);
- snprintf(buffer, 255, " sample rate(%u), status(%d), muted(%d)\n",
- (cblk == 0) ? 0 : cblk->sampleRate, mStatus, mMuted);
+ snprintf(buffer, 255, " sample rate(%u), status(%d)\n",
+ (cblk == 0) ? 0 : cblk->sampleRate, mStatus);
result.append(buffer);
snprintf(buffer, 255, " active(%d), latency (%d)\n", mActive, mLatency);
result.append(buffer);
@@ -1529,180 +1482,4 @@
}
}
-// =========================================================================
-
-
-audio_track_cblk_t::audio_track_cblk_t()
- : lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0),
- userBase(0), serverBase(0), frameCount_(0),
- loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), mVolumeLR(0x10001000),
- mSendLevel(0), flags(0)
-{
-}
-
-uint32_t audio_track_cblk_t::stepUser(size_t stepCount, size_t frameCount, bool isOut)
-{
- ALOGV("stepuser %08x %08x %d", user, server, stepCount);
-
- uint32_t u = user;
- u += stepCount;
- // Ensure that user is never ahead of server for AudioRecord
- if (isOut) {
- // If stepServer() has been called once, switch to normal obtainBuffer() timeout period
- if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS-1) {
- bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
- }
- } else if (u > server) {
- ALOGW("stepUser occurred after track reset");
- u = server;
- }
-
- if (u >= frameCount) {
- // common case, user didn't just wrap
- if (u - frameCount >= userBase ) {
- userBase += frameCount;
- }
- } else if (u >= userBase + frameCount) {
- // user just wrapped
- userBase += frameCount;
- }
-
- user = u;
-
- // Clear flow control error condition as new data has been written/read to/from buffer.
- if (flags & CBLK_UNDERRUN) {
- android_atomic_and(~CBLK_UNDERRUN, &flags);
- }
-
- return u;
-}
-
-bool audio_track_cblk_t::stepServer(size_t stepCount, size_t frameCount, bool isOut)
-{
- ALOGV("stepserver %08x %08x %d", user, server, stepCount);
-
- if (!tryLock()) {
- ALOGW("stepServer() could not lock cblk");
- return false;
- }
-
- uint32_t s = server;
- bool flushed = (s == user);
-
- s += stepCount;
- if (isOut) {
- // Mark that we have read the first buffer so that next time stepUser() is called
- // we switch to normal obtainBuffer() timeout period
- if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS) {
- bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS - 1;
- }
- // It is possible that we receive a flush()
- // while the mixer is processing a block: in this case,
- // stepServer() is called After the flush() has reset u & s and
- // we have s > u
- if (flushed) {
- ALOGW("stepServer occurred after track reset");
- s = user;
- }
- }
-
- if (s >= loopEnd) {
- ALOGW_IF(s > loopEnd, "stepServer: s %u > loopEnd %u", s, loopEnd);
- s = loopStart;
- if (--loopCount == 0) {
- loopEnd = UINT_MAX;
- loopStart = UINT_MAX;
- }
- }
-
- if (s >= frameCount) {
- // common case, server didn't just wrap
- if (s - frameCount >= serverBase ) {
- serverBase += frameCount;
- }
- } else if (s >= serverBase + frameCount) {
- // server just wrapped
- serverBase += frameCount;
- }
-
- server = s;
-
- if (!(flags & CBLK_INVALID)) {
- cv.signal();
- }
- lock.unlock();
- return true;
-}
-
-void* audio_track_cblk_t::buffer(void *buffers, size_t frameSize, uint32_t offset) const
-{
- return (int8_t *)buffers + (offset - userBase) * frameSize;
-}
-
-uint32_t audio_track_cblk_t::framesAvailable(size_t frameCount, bool isOut)
-{
- Mutex::Autolock _l(lock);
- return framesAvailable_l(frameCount, isOut);
-}
-
-uint32_t audio_track_cblk_t::framesAvailable_l(size_t frameCount, bool isOut)
-{
- uint32_t u = user;
- uint32_t s = server;
-
- if (isOut) {
- uint32_t limit = (s < loopStart) ? s : loopStart;
- return limit + frameCount - u;
- } else {
- return frameCount + u - s;
- }
-}
-
-uint32_t audio_track_cblk_t::framesReady(bool isOut)
-{
- uint32_t u = user;
- uint32_t s = server;
-
- if (isOut) {
- if (u < loopEnd) {
- return u - s;
- } else {
- // do not block on mutex shared with client on AudioFlinger side
- if (!tryLock()) {
- ALOGW("framesReady() could not lock cblk");
- return 0;
- }
- uint32_t frames = UINT_MAX;
- if (loopCount >= 0) {
- frames = (loopEnd - loopStart)*loopCount + u - s;
- }
- lock.unlock();
- return frames;
- }
- } else {
- return s - u;
- }
-}
-
-bool audio_track_cblk_t::tryLock()
-{
- // the code below simulates lock-with-timeout
- // we MUST do this to protect the AudioFlinger server
- // as this lock is shared with the client.
- status_t err;
-
- err = lock.tryLock();
- if (err == -EBUSY) { // just wait a bit
- usleep(1000);
- err = lock.tryLock();
- }
- if (err != NO_ERROR) {
- // probably, the client just died.
- return false;
- }
- return true;
-}
-
-// -------------------------------------------------------------------------
-
}; // namespace android
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
new file mode 100644
index 0000000..bee13c8
--- /dev/null
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioTrackShared"
+//#define LOG_NDEBUG 0
+
+#include <private/media/AudioTrackShared.h>
+#include <utils/Log.h>
+
+namespace android {
+
+audio_track_cblk_t::audio_track_cblk_t()
+ : lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0),
+ userBase(0), serverBase(0), frameCount_(0),
+ loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), mVolumeLR(0x10001000),
+ mSendLevel(0), flags(0)
+{
+}
+
+uint32_t audio_track_cblk_t::stepUser(size_t stepCount, size_t frameCount, bool isOut)
+{
+ ALOGV("stepuser %08x %08x %d", user, server, stepCount);
+
+ uint32_t u = user;
+ u += stepCount;
+ // Ensure that user is never ahead of server for AudioRecord
+ if (isOut) {
+ // If stepServer() has been called once, switch to normal obtainBuffer() timeout period
+ if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS-1) {
+ bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+ }
+ } else if (u > server) {
+ ALOGW("stepUser occurred after track reset");
+ u = server;
+ }
+
+ if (u >= frameCount) {
+ // common case, user didn't just wrap
+ if (u - frameCount >= userBase ) {
+ userBase += frameCount;
+ }
+ } else if (u >= userBase + frameCount) {
+ // user just wrapped
+ userBase += frameCount;
+ }
+
+ user = u;
+
+ // Clear flow control error condition as new data has been written/read to/from buffer.
+ if (flags & CBLK_UNDERRUN) {
+ android_atomic_and(~CBLK_UNDERRUN, &flags);
+ }
+
+ return u;
+}
+
+bool audio_track_cblk_t::stepServer(size_t stepCount, size_t frameCount, bool isOut)
+{
+ ALOGV("stepserver %08x %08x %d", user, server, stepCount);
+
+ if (!tryLock()) {
+ ALOGW("stepServer() could not lock cblk");
+ return false;
+ }
+
+ uint32_t s = server;
+ bool flushed = (s == user);
+
+ s += stepCount;
+ if (isOut) {
+ // Mark that we have read the first buffer so that next time stepUser() is called
+ // we switch to normal obtainBuffer() timeout period
+ if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS) {
+ bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS - 1;
+ }
+ // It is possible that we receive a flush()
+ // while the mixer is processing a block: in this case,
+ // stepServer() is called After the flush() has reset u & s and
+ // we have s > u
+ if (flushed) {
+ ALOGW("stepServer occurred after track reset");
+ s = user;
+ }
+ }
+
+ if (s >= loopEnd) {
+ ALOGW_IF(s > loopEnd, "stepServer: s %u > loopEnd %u", s, loopEnd);
+ s = loopStart;
+ if (--loopCount == 0) {
+ loopEnd = UINT_MAX;
+ loopStart = UINT_MAX;
+ }
+ }
+
+ if (s >= frameCount) {
+ // common case, server didn't just wrap
+ if (s - frameCount >= serverBase ) {
+ serverBase += frameCount;
+ }
+ } else if (s >= serverBase + frameCount) {
+ // server just wrapped
+ serverBase += frameCount;
+ }
+
+ server = s;
+
+ if (!(flags & CBLK_INVALID)) {
+ cv.signal();
+ }
+ lock.unlock();
+ return true;
+}
+
+void* audio_track_cblk_t::buffer(void *buffers, size_t frameSize, uint32_t offset) const
+{
+ return (int8_t *)buffers + (offset - userBase) * frameSize;
+}
+
+uint32_t audio_track_cblk_t::framesAvailable(size_t frameCount, bool isOut)
+{
+ Mutex::Autolock _l(lock);
+ return framesAvailable_l(frameCount, isOut);
+}
+
+uint32_t audio_track_cblk_t::framesAvailable_l(size_t frameCount, bool isOut)
+{
+ uint32_t u = user;
+ uint32_t s = server;
+
+ if (isOut) {
+ uint32_t limit = (s < loopStart) ? s : loopStart;
+ return limit + frameCount - u;
+ } else {
+ return frameCount + u - s;
+ }
+}
+
+uint32_t audio_track_cblk_t::framesReady(bool isOut)
+{
+ uint32_t u = user;
+ uint32_t s = server;
+
+ if (isOut) {
+ if (u < loopEnd) {
+ return u - s;
+ } else {
+ // do not block on mutex shared with client on AudioFlinger side
+ if (!tryLock()) {
+ ALOGW("framesReady() could not lock cblk");
+ return 0;
+ }
+ uint32_t frames = UINT_MAX;
+ if (loopCount >= 0) {
+ frames = (loopEnd - loopStart)*loopCount + u - s;
+ }
+ lock.unlock();
+ return frames;
+ }
+ } else {
+ return s - u;
+ }
+}
+
+bool audio_track_cblk_t::tryLock()
+{
+ // the code below simulates lock-with-timeout
+ // we MUST do this to protect the AudioFlinger server
+ // as this lock is shared with the client.
+ status_t err;
+
+ err = lock.tryLock();
+ if (err == -EBUSY) { // just wait a bit
+ usleep(1000);
+ err = lock.tryLock();
+ }
+ if (err != NO_ERROR) {
+ // probably, the client just died.
+ return false;
+ }
+ return true;
+}
+
+} // namespace android
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index a010bb6..c5fbbf0 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -32,7 +32,7 @@
CREATE_TRACK = IBinder::FIRST_CALL_TRANSACTION,
OPEN_RECORD,
SAMPLE_RATE,
- CHANNEL_COUNT, // obsolete
+ RESERVED, // obsolete, was CHANNEL_COUNT
FORMAT,
FRAME_COUNT,
LATENCY,
@@ -191,17 +191,6 @@
return reply.readInt32();
}
-#if 0
- virtual int channelCount(audio_io_handle_t output) const
- {
- Parcel data, reply;
- data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32((int32_t) output);
- remote()->transact(CHANNEL_COUNT, data, &reply);
- return reply.readInt32();
- }
-#endif
-
virtual audio_format_t format(audio_io_handle_t output) const
{
Parcel data, reply;
@@ -768,13 +757,6 @@
reply->writeInt32( sampleRate((audio_io_handle_t) data.readInt32()) );
return NO_ERROR;
} break;
-#if 0
- case CHANNEL_COUNT: {
- CHECK_INTERFACE(IAudioFlinger, data, reply);
- reply->writeInt32( channelCount((audio_io_handle_t) data.readInt32()) );
- return NO_ERROR;
- } break;
-#endif
case FORMAT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
reply->writeInt32( format((audio_io_handle_t) data.readInt32()) );
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index 867d1a5..e92f8aa 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -33,7 +33,7 @@
START,
STOP,
FLUSH,
- MUTE,
+ RESERVED, // was MUTE
PAUSE,
ATTACH_AUX_EFFECT,
ALLOCATE_TIMED_BUFFER,
@@ -88,14 +88,6 @@
remote()->transact(FLUSH, data, &reply);
}
- virtual void mute(bool e)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
- data.writeInt32(e);
- remote()->transact(MUTE, data, &reply);
- }
-
virtual void pause()
{
Parcel data, reply;
@@ -192,11 +184,6 @@
flush();
return NO_ERROR;
} break;
- case MUTE: {
- CHECK_INTERFACE(IAudioTrack, data, reply);
- mute( data.readInt32() );
- return NO_ERROR;
- } break;
case PAUSE: {
CHECK_INTERFACE(IAudioTrack, data, reply);
pause();
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index b2afec7..1a62f9d 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1424,18 +1424,15 @@
if (mFileMetaData != NULL) {
ALOGV("chunk_data_size = %lld and data_offset = %lld",
chunk_data_size, data_offset);
- uint8_t *buffer = new uint8_t[chunk_data_size + 1];
+ sp<ABuffer> buffer = new ABuffer(chunk_data_size + 1);
if (mDataSource->readAt(
- data_offset, buffer, chunk_data_size) != (ssize_t)chunk_data_size) {
- delete[] buffer;
- buffer = NULL;
-
+ data_offset, buffer->data(), chunk_data_size) != (ssize_t)chunk_data_size) {
return ERROR_IO;
}
const int kSkipBytesOfDataBox = 16;
mFileMetaData->setData(
kKeyAlbumArt, MetaData::TYPE_NONE,
- buffer + kSkipBytesOfDataBox, chunk_data_size - kSkipBytesOfDataBox);
+ buffer->data() + kSkipBytesOfDataBox, chunk_data_size - kSkipBytesOfDataBox);
}
*offset += chunk_size;
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 46a8e0f..6d3f0a1 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -385,7 +385,6 @@
virtual status_t start();
virtual void stop();
virtual void flush();
- virtual void mute(bool);
virtual void pause();
virtual status_t attachAuxEffect(int effectId);
virtual status_t allocateTimedBuffer(size_t size,
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index b898924..37e39a0 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -44,7 +44,6 @@
void flush();
void destroy();
- void mute(bool);
int name() const { return mName; }
audio_stream_type_t streamType() const {
@@ -78,7 +77,6 @@
virtual size_t framesReady() const;
- bool isMuted() const { return mMute; }
bool isPausing() const {
return mState == PAUSING;
}
@@ -111,11 +109,6 @@
protected:
- // written by Track::mute() called by binder thread(s), without a mutex or barrier.
- // read by Track::isMuted() called by playback thread, also without a mutex or barrier.
- // The lack of mutex or barrier is safe because the mute status is only used by itself.
- bool mMute;
-
// FILLED state is used for suppressing volume ramp at begin of playing
enum {FS_INVALID, FS_FILLING, FS_FILLED, FS_ACTIVE};
mutable uint8_t mFillingUpStatus;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index fd64395..a285e6c 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2544,8 +2544,7 @@
}
// cache the combined master volume and stream type volume for fast mixer; this
// lacks any synchronization or barrier so VolumeProvider may read a stale value
- track->mCachedVolume = track->isMuted() ?
- 0 : masterVolume * mStreamTypes[track->streamType()].volume;
+ track->mCachedVolume = masterVolume * mStreamTypes[track->streamType()].volume;
++fastTracks;
} else {
// was it previously active?
@@ -2637,8 +2636,7 @@
// compute volume for this track
uint32_t vl, vr, va;
- if (track->isMuted() || track->isPausing() ||
- mStreamTypes[track->streamType()].mute) {
+ if (track->isPausing() || mStreamTypes[track->streamType()].mute) {
vl = vr = va = 0;
if (track->isPausing()) {
track->setPaused();
@@ -3139,8 +3137,7 @@
// compute volume for this track
float left, right;
- if (track->isMuted() || mMasterMute || track->isPausing() ||
- mStreamTypes[track->streamType()].mute) {
+ if (mMasterMute || track->isPausing() || mStreamTypes[track->streamType()].mute) {
left = right = 0;
if (track->isPausing()) {
track->setPaused();
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 2c6ba8b..e8ca5ee 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -248,10 +248,6 @@
mTrack->flush();
}
-void AudioFlinger::TrackHandle::mute(bool e) {
- mTrack->mute(e);
-}
-
void AudioFlinger::TrackHandle::pause() {
mTrack->pause();
}
@@ -315,7 +311,6 @@
IAudioFlinger::track_flags_t flags)
: TrackBase(thread, client, sampleRate, format, channelMask, frameCount, sharedBuffer,
sessionId),
- mMute(false),
mFillingUpStatus(FS_INVALID),
// mRetryCount initialized later when needed
mSharedBuffer(sharedBuffer),
@@ -397,7 +392,7 @@
/*static*/ void AudioFlinger::PlaybackThread::Track::appendDumpHeader(String8& result)
{
- result.append(" Name Client Type Fmt Chn mask Session StpCnt fCount S M F SRate "
+ result.append(" Name Client Type Fmt Chn mask Session StpCnt fCount S F SRate "
"L dB R dB Server User Main buf Aux Buf Flags Underruns\n");
}
@@ -461,7 +456,7 @@
nowInUnderrun = '?';
break;
}
- snprintf(&buffer[7], size-7, " %6d %4u %3u 0x%08x %7u %6u %6u %1c %1d %1d %5u %5.2g %5.2g "
+ snprintf(&buffer[7], size-7, " %6d %4u %3u 0x%08x %7u %6u %6u %1c %1d %5u %5.2g %5.2g "
"0x%08x 0x%08x 0x%08x 0x%08x %#5x %9u%c\n",
(mClient == 0) ? getpid_cached : mClient->pid(),
mStreamType,
@@ -471,7 +466,6 @@
mStepCount,
mFrameCount,
stateChar,
- mMute,
mFillingUpStatus,
mCblk->sampleRate,
20.0 * log10((vlr & 0xFFFF) / 4096.0),
@@ -708,11 +702,6 @@
}
}
-void AudioFlinger::PlaybackThread::Track::mute(bool muted)
-{
- mMute = muted;
-}
-
status_t AudioFlinger::PlaybackThread::Track::attachAuxEffect(int EffectId)
{
status_t status = DEAD_OBJECT;