Merge "Effect for multichannel PCM downmix to stereo"
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 9f2bd3a..95b9d86 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -135,8 +135,10 @@
* format: Audio format (e.g AUDIO_FORMAT_PCM_16_BIT for signed
* 16 bits per sample).
* channelMask: Channel mask: see audio_channels_t.
- * frameCount: Total size of track PCM buffer in frames. This defines the
- * latency of the track.
+ * frameCount: Minimum size of track PCM buffer in frames. This defines 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.
* flags: Reserved for future use.
* cbf: Callback function. If not null, this function is called periodically
* to request new PCM data.
diff --git a/include/media/stagefright/MediaSourceSplitter.h b/include/media/stagefright/MediaSourceSplitter.h
deleted file mode 100644
index 568f4c2..0000000
--- a/include/media/stagefright/MediaSourceSplitter.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-// This class provides a way to split a single media source into multiple sources.
-// The constructor takes in the real mediaSource and createClient() can then be
-// used to create multiple sources served from this real mediaSource.
-//
-// Usage:
-// - Create MediaSourceSplitter by passing in a real mediaSource from which
-// multiple duplicate channels are needed.
-// - Create a client using createClient() and use it as any other mediaSource.
-//
-// Note that multiple clients can be created using createClient() and
-// started/stopped in any order. MediaSourceSplitter stops the real source only
-// when all clients have been stopped.
-//
-// If a new client is created/started after some existing clients have already
-// started, the new client will start getting its read frames from the current
-// time.
-
-#ifndef MEDIA_SOURCE_SPLITTER_H_
-
-#define MEDIA_SOURCE_SPLITTER_H_
-
-#include <media/stagefright/MediaSource.h>
-#include <utils/threads.h>
-#include <utils/Vector.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-class MediaBuffer;
-class MetaData;
-
-class MediaSourceSplitter : public RefBase {
-public:
- // Constructor
- // mediaSource: The real mediaSource. The class keeps a reference to it to
- // implement the various clients.
- MediaSourceSplitter(sp<MediaSource> mediaSource);
-
- ~MediaSourceSplitter();
-
- // Creates a new client of base type MediaSource. Multiple clients can be
- // created which get their data through the same real mediaSource. These
- // clients can then be used like any other MediaSource, all of which provide
- // data from the same real source.
- sp<MediaSource> createClient();
-
-private:
- // Total number of clients created through createClient().
- int32_t mNumberOfClients;
-
- // reference to the real MediaSource passed to the constructor.
- sp<MediaSource> mSource;
-
- // Stores pointer to the MediaBuffer read from the real MediaSource.
- // All clients use this to implement the read() call.
- MediaBuffer *mLastReadMediaBuffer;
-
- // Status code for read from the real MediaSource. All clients return
- // this for their read().
- status_t mLastReadStatus;
-
- // Boolean telling whether the real MediaSource has started.
- bool mSourceStarted;
-
- // List of booleans, one for each client, storing whether the corresponding
- // client's start() has been called.
- Vector<bool> mClientsStarted;
-
- // Stores the number of clients which are currently started.
- int32_t mNumberOfClientsStarted;
-
- // Since different clients call read() asynchronously, we need to keep track
- // of what data is currently read into the mLastReadMediaBuffer.
- // mCurrentReadBit stores the bit for the current read buffer. This bit
- // flips each time a new buffer is read from the source.
- // mClientsDesiredReadBit stores the bit for the next desired read buffer
- // for each client. This bit flips each time read() is completed for this
- // client.
- bool mCurrentReadBit;
- Vector<bool> mClientsDesiredReadBit;
-
- // Number of clients whose current read has been completed.
- int32_t mNumberOfCurrentReads;
-
- // Boolean telling whether the last read has been completed for all clients.
- // The variable is reset to false each time buffer is read from the real
- // source.
- bool mLastReadCompleted;
-
- // A global mutex for access to critical sections.
- Mutex mLock;
-
- // Condition variable for waiting on read from source to complete.
- Condition mReadFromSourceCondition;
-
- // Condition variable for waiting on all client's last read to complete.
- Condition mAllReadsCompleteCondition;
-
- // Functions used by Client to implement the MediaSource interface.
-
- // If the real source has not been started yet by any client, starts it.
- status_t start(int clientId, MetaData *params);
-
- // Stops the real source after all clients have called stop().
- status_t stop(int clientId);
-
- // returns the real source's getFormat().
- sp<MetaData> getFormat(int clientId);
-
- // If the client's desired buffer has already been read into
- // mLastReadMediaBuffer, points the buffer to that. Otherwise if it is the
- // master client, reads the buffer from source or else waits for the master
- // client to read the buffer and uses that.
- status_t read(int clientId,
- MediaBuffer **buffer, const MediaSource::ReadOptions *options = NULL);
-
- // Not implemented right now.
- status_t pause(int clientId);
-
- // Function which reads a buffer from the real source into
- // mLastReadMediaBuffer
- void readFromSource_lock(const MediaSource::ReadOptions *options);
-
- // Waits until read from the real source has been completed.
- // _lock means that the function should be called when the thread has already
- // obtained the lock for the mutex mLock.
- void waitForReadFromSource_lock(int32_t clientId);
-
- // Waits until all clients have read the current buffer in
- // mLastReadCompleted.
- void waitForAllClientsLastRead_lock(int32_t clientId);
-
- // Each client calls this after it completes its read(). Once all clients
- // have called this for the current buffer, the function calls
- // mAllReadsCompleteCondition.broadcast() to signal the waiting clients.
- void signalReadComplete_lock(bool readAborted);
-
- // Make these constructors private.
- MediaSourceSplitter();
- MediaSourceSplitter(const MediaSourceSplitter &);
- MediaSourceSplitter &operator=(const MediaSourceSplitter &);
-
- // This class implements the MediaSource interface. Each client stores a
- // reference to the parent MediaSourceSplitter and uses it to complete the
- // various calls.
- class Client : public MediaSource {
- public:
- // Constructor stores reference to the parent MediaSourceSplitter and it
- // client id.
- Client(sp<MediaSourceSplitter> splitter, int32_t clientId);
-
- // MediaSource interface
- virtual status_t start(MetaData *params = NULL);
-
- virtual status_t stop();
-
- virtual sp<MetaData> getFormat();
-
- virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
-
- virtual status_t pause();
-
- private:
- // Refernce to the parent MediaSourceSplitter
- sp<MediaSourceSplitter> mSplitter;
-
- // Id of this client.
- int32_t mClientId;
- };
-
- friend class Client;
-};
-
-} // namespace android
-
-#endif // MEDIA_SOURCE_SPLITTER_H_
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 4890f05..a1c99e5 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -784,12 +784,9 @@
mNotificationFramesAct = frameCount/2;
}
if (frameCount < minFrameCount) {
- if (enforceFrameCount) {
- ALOGE("Invalid buffer size: minFrameCount %d, frameCount %d", minFrameCount, frameCount);
- return BAD_VALUE;
- } else {
- frameCount = minFrameCount;
- }
+ ALOGW_IF(enforceFrameCount, "Minimum buffer size corrected from %d to %d",
+ frameCount, minFrameCount);
+ frameCount = minFrameCount;
}
} else {
// Ensure that buffer alignment matches channelCount
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index bd3e07a..1a85c9c 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -325,7 +325,7 @@
mStreamType, mLeftVolume, mRightVolume);
result.append(buffer);
snprintf(buffer, 255, " msec per frame(%f), latency (%d)\n",
- mMsecsPerFrame, mLatency);
+ mMsecsPerFrame, (mTrack != 0) ? mTrack->latency() : -1);
result.append(buffer);
snprintf(buffer, 255, " aux effect id(%d), send level (%f)\n",
mAuxEffectId, mSendLevel);
@@ -1384,7 +1384,6 @@
mRightVolume = 1.0;
mPlaybackRatePermille = 1000;
mSampleRateHz = 0;
- mLatency = 0;
mMsecsPerFrame = 0;
mAuxEffectId = 0;
mSendLevel = 0.0;
@@ -1443,7 +1442,8 @@
uint32_t MediaPlayerService::AudioOutput::latency () const
{
- return mLatency;
+ if (mTrack == 0) return 0;
+ return mTrack->latency();
}
float MediaPlayerService::AudioOutput::msecsPerFrame() const
@@ -1533,7 +1533,6 @@
mSampleRateHz = sampleRate;
mMsecsPerFrame = mPlaybackRatePermille / (float) sampleRate;
- mLatency = t->latency();
mTrack = t;
status_t res = t->setSampleRate(mPlaybackRatePermille * mSampleRateHz / 1000);
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 681ecab..85cec22 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -118,7 +118,6 @@
int32_t mPlaybackRatePermille;
uint32_t mSampleRateHz; // sample rate of the content, as set in open()
float mMsecsPerFrame;
- uint32_t mLatency;
int mSessionId;
float mSendLevel;
int mAuxEffectId;
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 21d6866..5aea8d0 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -34,7 +34,6 @@
MediaDefs.cpp \
MediaExtractor.cpp \
MediaSource.cpp \
- MediaSourceSplitter.cpp \
MetaData.cpp \
NuCachedSource2.cpp \
NuMediaExtractor.cpp \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 9427ef7..650b6c4 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -427,6 +427,12 @@
break;
}
+ if (mAudioSink != NULL) {
+ mLatencyUs = (int64_t)mAudioSink->latency() * 1000;
+ } else {
+ mLatencyUs = (int64_t)mAudioTrack->latency() * 1000;
+ }
+
CHECK(mInputBuffer->meta_data()->findInt64(
kKeyTime, &mPositionTimeMediaUs));
diff --git a/media/libstagefright/MediaSourceSplitter.cpp b/media/libstagefright/MediaSourceSplitter.cpp
deleted file mode 100644
index 3b64ded..0000000
--- a/media/libstagefright/MediaSourceSplitter.cpp
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2010 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_NDEBUG 0
-#define LOG_TAG "MediaSourceSplitter"
-#include <utils/Log.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaSourceSplitter.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-MediaSourceSplitter::MediaSourceSplitter(sp<MediaSource> mediaSource) {
- mNumberOfClients = 0;
- mSource = mediaSource;
- mSourceStarted = false;
-
- mNumberOfClientsStarted = 0;
- mNumberOfCurrentReads = 0;
- mCurrentReadBit = 0;
- mLastReadCompleted = true;
-}
-
-MediaSourceSplitter::~MediaSourceSplitter() {
-}
-
-sp<MediaSource> MediaSourceSplitter::createClient() {
- Mutex::Autolock autoLock(mLock);
-
- sp<MediaSource> client = new Client(this, mNumberOfClients++);
- mClientsStarted.push(false);
- mClientsDesiredReadBit.push(0);
- return client;
-}
-
-status_t MediaSourceSplitter::start(int clientId, MetaData *params) {
- Mutex::Autolock autoLock(mLock);
-
- ALOGV("start client (%d)", clientId);
- if (mClientsStarted[clientId]) {
- return OK;
- }
-
- mNumberOfClientsStarted++;
-
- if (!mSourceStarted) {
- ALOGV("Starting real source from client (%d)", clientId);
- status_t err = mSource->start(params);
-
- if (err == OK) {
- mSourceStarted = true;
- mClientsStarted.editItemAt(clientId) = true;
- mClientsDesiredReadBit.editItemAt(clientId) = !mCurrentReadBit;
- }
-
- return err;
- } else {
- mClientsStarted.editItemAt(clientId) = true;
- if (mLastReadCompleted) {
- // Last read was completed. So join in the threads for the next read.
- mClientsDesiredReadBit.editItemAt(clientId) = !mCurrentReadBit;
- } else {
- // Last read is ongoing. So join in the threads for the current read.
- mClientsDesiredReadBit.editItemAt(clientId) = mCurrentReadBit;
- }
- return OK;
- }
-}
-
-status_t MediaSourceSplitter::stop(int clientId) {
- Mutex::Autolock autoLock(mLock);
-
- ALOGV("stop client (%d)", clientId);
- CHECK(clientId >= 0 && clientId < mNumberOfClients);
- CHECK(mClientsStarted[clientId]);
-
- if (--mNumberOfClientsStarted == 0) {
- ALOGV("Stopping real source from client (%d)", clientId);
- status_t err = mSource->stop();
- mSourceStarted = false;
- mClientsStarted.editItemAt(clientId) = false;
- return err;
- } else {
- mClientsStarted.editItemAt(clientId) = false;
- if (!mLastReadCompleted && (mClientsDesiredReadBit[clientId] == mCurrentReadBit)) {
- // !mLastReadCompleted implies that buffer has been read from source, but all
- // clients haven't read it.
- // mClientsDesiredReadBit[clientId] == mCurrentReadBit implies that this
- // client would have wanted to read from this buffer. (i.e. it has not yet
- // called read() for the current read buffer.)
- // Since other threads may be waiting for all the clients' reads to complete,
- // signal that this read has been aborted.
- signalReadComplete_lock(true);
- }
- return OK;
- }
-}
-
-sp<MetaData> MediaSourceSplitter::getFormat(int clientId) {
- Mutex::Autolock autoLock(mLock);
-
- ALOGV("getFormat client (%d)", clientId);
- return mSource->getFormat();
-}
-
-status_t MediaSourceSplitter::read(int clientId,
- MediaBuffer **buffer, const MediaSource::ReadOptions *options) {
- Mutex::Autolock autoLock(mLock);
-
- CHECK(clientId >= 0 && clientId < mNumberOfClients);
-
- ALOGV("read client (%d)", clientId);
- *buffer = NULL;
-
- if (!mClientsStarted[clientId]) {
- return OK;
- }
-
- if (mCurrentReadBit != mClientsDesiredReadBit[clientId]) {
- // Desired buffer has not been read from source yet.
-
- // If the current client is the special client with clientId = 0
- // then read from source, else wait until the client 0 has finished
- // reading from source.
- if (clientId == 0) {
- // Wait for all client's last read to complete first so as to not
- // corrupt the buffer at mLastReadMediaBuffer.
- waitForAllClientsLastRead_lock(clientId);
-
- readFromSource_lock(options);
- *buffer = mLastReadMediaBuffer;
- } else {
- waitForReadFromSource_lock(clientId);
-
- *buffer = mLastReadMediaBuffer;
- (*buffer)->add_ref();
- }
- CHECK(mCurrentReadBit == mClientsDesiredReadBit[clientId]);
- } else {
- // Desired buffer has already been read from source. Use the cached data.
- CHECK(clientId != 0);
-
- *buffer = mLastReadMediaBuffer;
- (*buffer)->add_ref();
- }
-
- mClientsDesiredReadBit.editItemAt(clientId) = !mClientsDesiredReadBit[clientId];
- signalReadComplete_lock(false);
-
- return mLastReadStatus;
-}
-
-void MediaSourceSplitter::readFromSource_lock(const MediaSource::ReadOptions *options) {
- mLastReadStatus = mSource->read(&mLastReadMediaBuffer , options);
-
- mCurrentReadBit = !mCurrentReadBit;
- mLastReadCompleted = false;
- mReadFromSourceCondition.broadcast();
-}
-
-void MediaSourceSplitter::waitForReadFromSource_lock(int32_t clientId) {
- mReadFromSourceCondition.wait(mLock);
-}
-
-void MediaSourceSplitter::waitForAllClientsLastRead_lock(int32_t clientId) {
- if (mLastReadCompleted) {
- return;
- }
- mAllReadsCompleteCondition.wait(mLock);
- CHECK(mLastReadCompleted);
-}
-
-void MediaSourceSplitter::signalReadComplete_lock(bool readAborted) {
- if (!readAborted) {
- mNumberOfCurrentReads++;
- }
-
- if (mNumberOfCurrentReads == mNumberOfClientsStarted) {
- mLastReadCompleted = true;
- mNumberOfCurrentReads = 0;
- mAllReadsCompleteCondition.broadcast();
- }
-}
-
-status_t MediaSourceSplitter::pause(int clientId) {
- return ERROR_UNSUPPORTED;
-}
-
-// Client
-
-MediaSourceSplitter::Client::Client(
- sp<MediaSourceSplitter> splitter,
- int32_t clientId) {
- mSplitter = splitter;
- mClientId = clientId;
-}
-
-status_t MediaSourceSplitter::Client::start(MetaData *params) {
- return mSplitter->start(mClientId, params);
-}
-
-status_t MediaSourceSplitter::Client::stop() {
- return mSplitter->stop(mClientId);
-}
-
-sp<MetaData> MediaSourceSplitter::Client::getFormat() {
- return mSplitter->getFormat(mClientId);
-}
-
-status_t MediaSourceSplitter::Client::read(
- MediaBuffer **buffer, const ReadOptions *options) {
- return mSplitter->read(mClientId, buffer, options);
-}
-
-status_t MediaSourceSplitter::Client::pause() {
- return mSplitter->pause(mClientId);
-}
-
-} // namespace android
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index f4b5d4f..6d345bb 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -26,8 +26,6 @@
#include "include/TimedEventQueue.h"
-#include <cutils/sched_policy.h>
-
#include <sys/prctl.h>
#include <sys/time.h>
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index b972548..fe068af 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -310,10 +310,10 @@
}
result.append("Global session refs:\n");
- result.append(" session pid cnt\n");
+ result.append(" session pid count\n");
for (size_t i = 0; i < mAudioSessionRefs.size(); i++) {
AudioSessionRef *r = mAudioSessionRefs[i];
- snprintf(buffer, SIZE, " %7d %3d %3d\n", r->sessionid, r->pid, r->cnt);
+ snprintf(buffer, SIZE, " %7d %3d %3d\n", r->mSessionid, r->mPid, r->mCnt);
result.append(buffer);
}
write(fd, result.string(), result.size());
@@ -1036,9 +1036,9 @@
bool removed = false;
for (size_t i = 0; i< num; ) {
AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
- ALOGV(" pid %d @ %d", ref->pid, i);
- if (ref->pid == pid) {
- ALOGV(" removing entry for pid %d session %d", pid, ref->sessionid);
+ ALOGV(" pid %d @ %d", ref->mPid, i);
+ if (ref->mPid == pid) {
+ ALOGV(" removing entry for pid %d session %d", pid, ref->mSessionid);
mAudioSessionRefs.removeAt(i);
delete ref;
removed = true;
@@ -1993,12 +1993,8 @@
bool AudioFlinger::PlaybackThread::threadLoop()
{
- // MIXER || DUPLICATING
Vector< sp<Track> > tracksToRemove;
- // DIRECT
- sp<Track> trackToRemove;
-
standbyTime = systemTime();
mixBufferSize = mFrameCount * mFrameSize;
@@ -2067,9 +2063,7 @@
maxPeriod = seconds(mFrameCount) / mSampleRate * 15;
}
-if (mType == DUPLICATING) {
- updateWaitTime();
-}
+ updateWaitTime_l();
activeSleepTime = activeSleepTimeUs();
idleSleepTime = idleSleepTimeUs();
@@ -2144,17 +2138,11 @@
}
}
-// FIXME merge these
-if (mType == MIXER || mType == DUPLICATING) {
mixerStatus = prepareTracks_l(&tracksToRemove);
-}
-if (mType == DIRECT) {
- mixerStatus = threadLoop_prepareTracks_l(trackToRemove);
// see FIXME in AudioFlinger.h
if (mixerStatus == MIXER_CONTINUE) {
continue;
}
-}
// prevent any changes in effect chain list and in each effect chain
// during mixing and effect process as the audio buffers could be deleted
@@ -2178,14 +2166,6 @@
// only process effects if we're going to write
if (sleepTime == 0) {
-
- if (mixerStatus == MIXER_TRACKS_READY) {
-
- // Non-trivial for DIRECT only
- applyVolume();
-
- }
-
for (size_t i = 0; i < effectChains.size(); i ++) {
effectChains[i]->process_l();
}
@@ -2226,17 +2206,13 @@
// finally let go of removed track(s), without the lock held
// since we can't guarantee the destructors won't acquire that
// same lock.
+ tracksToRemove.clear();
// FIXME merge these
-if (mType == MIXER) {
- tracksToRemove.clear();
-}
if (mType == DIRECT) {
- trackToRemove.clear();
activeTrack.clear();
}
if (mType == DUPLICATING) {
- tracksToRemove.clear();
outputTracks.clear();
}
@@ -2267,79 +2243,79 @@
// shared by MIXER and DIRECT, overridden by DUPLICATING
void AudioFlinger::PlaybackThread::threadLoop_write()
{
- // FIXME rewrite to reduce number of system calls
- mLastWriteTime = systemTime();
- mInWrite = true;
- mBytesWritten += mixBufferSize;
- int bytesWritten = (int)mOutput->stream->write(mOutput->stream, mMixBuffer, mixBufferSize);
- if (bytesWritten < 0) mBytesWritten -= mixBufferSize;
- mNumWrites++;
- mInWrite = false;
+ // FIXME rewrite to reduce number of system calls
+ mLastWriteTime = systemTime();
+ mInWrite = true;
+ mBytesWritten += mixBufferSize;
+ int bytesWritten = (int)mOutput->stream->write(mOutput->stream, mMixBuffer, mixBufferSize);
+ if (bytesWritten < 0) mBytesWritten -= mixBufferSize;
+ mNumWrites++;
+ mInWrite = false;
}
// shared by MIXER and DIRECT, overridden by DUPLICATING
void AudioFlinger::PlaybackThread::threadLoop_standby()
{
- ALOGV("Audio hardware entering standby, mixer %p, suspend count %u", this, mSuspended);
- mOutput->stream->common.standby(&mOutput->stream->common);
+ ALOGV("Audio hardware entering standby, mixer %p, suspend count %u", this, mSuspended);
+ mOutput->stream->common.standby(&mOutput->stream->common);
}
void AudioFlinger::MixerThread::threadLoop_mix()
{
- // obtain the presentation timestamp of the next output buffer
- int64_t pts;
- status_t status = INVALID_OPERATION;
+ // obtain the presentation timestamp of the next output buffer
+ int64_t pts;
+ status_t status = INVALID_OPERATION;
- if (NULL != mOutput->stream->get_next_write_timestamp) {
- status = mOutput->stream->get_next_write_timestamp(
- mOutput->stream, &pts);
- }
+ if (NULL != mOutput->stream->get_next_write_timestamp) {
+ status = mOutput->stream->get_next_write_timestamp(
+ mOutput->stream, &pts);
+ }
- if (status != NO_ERROR) {
- pts = AudioBufferProvider::kInvalidPTS;
- }
+ if (status != NO_ERROR) {
+ pts = AudioBufferProvider::kInvalidPTS;
+ }
- // mix buffers...
- mAudioMixer->process(pts);
- // increase sleep time progressively when application underrun condition clears.
- // Only increase sleep time if the mixer is ready for two consecutive times to avoid
- // that a steady state of alternating ready/not ready conditions keeps the sleep time
- // such that we would underrun the audio HAL.
- if ((sleepTime == 0) && (sleepTimeShift > 0)) {
- sleepTimeShift--;
- }
- sleepTime = 0;
- standbyTime = systemTime() + mStandbyTimeInNsecs;
- //TODO: delay standby when effects have a tail
+ // mix buffers...
+ mAudioMixer->process(pts);
+ // increase sleep time progressively when application underrun condition clears.
+ // Only increase sleep time if the mixer is ready for two consecutive times to avoid
+ // that a steady state of alternating ready/not ready conditions keeps the sleep time
+ // such that we would underrun the audio HAL.
+ if ((sleepTime == 0) && (sleepTimeShift > 0)) {
+ sleepTimeShift--;
+ }
+ sleepTime = 0;
+ standbyTime = systemTime() + mStandbyTimeInNsecs;
+ //TODO: delay standby when effects have a tail
}
void AudioFlinger::MixerThread::threadLoop_sleepTime()
{
- // If no tracks are ready, sleep once for the duration of an output
- // buffer size, then write 0s to the output
- if (sleepTime == 0) {
- if (mixerStatus == MIXER_TRACKS_ENABLED) {
- sleepTime = activeSleepTime >> sleepTimeShift;
- if (sleepTime < kMinThreadSleepTimeUs) {
- sleepTime = kMinThreadSleepTimeUs;
- }
- // reduce sleep time in case of consecutive application underruns to avoid
- // starving the audio HAL. As activeSleepTimeUs() is larger than a buffer
- // duration we would end up writing less data than needed by the audio HAL if
- // the condition persists.
- if (sleepTimeShift < kMaxThreadSleepTimeShift) {
- sleepTimeShift++;
- }
- } else {
- sleepTime = idleSleepTime;
- }
- } else if (mBytesWritten != 0 ||
- (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)) {
- memset (mMixBuffer, 0, mixBufferSize);
- sleepTime = 0;
- ALOGV_IF((mBytesWritten == 0 && (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)), "anticipated start");
+ // If no tracks are ready, sleep once for the duration of an output
+ // buffer size, then write 0s to the output
+ if (sleepTime == 0) {
+ if (mixerStatus == MIXER_TRACKS_ENABLED) {
+ sleepTime = activeSleepTime >> sleepTimeShift;
+ if (sleepTime < kMinThreadSleepTimeUs) {
+ sleepTime = kMinThreadSleepTimeUs;
}
- // TODO add standby time extension fct of effect tail
+ // reduce sleep time in case of consecutive application underruns to avoid
+ // starving the audio HAL. As activeSleepTimeUs() is larger than a buffer
+ // duration we would end up writing less data than needed by the audio HAL if
+ // the condition persists.
+ if (sleepTimeShift < kMaxThreadSleepTimeShift) {
+ sleepTimeShift++;
+ }
+ } else {
+ sleepTime = idleSleepTime;
+ }
+ } else if (mBytesWritten != 0 ||
+ (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)) {
+ memset (mMixBuffer, 0, mixBufferSize);
+ sleepTime = 0;
+ ALOGV_IF((mBytesWritten == 0 && (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)), "anticipated start");
+ }
+ // TODO add standby time extension fct of effect tail
}
// prepareTracks_l() must be called with ThreadBase::mLock held
@@ -2854,177 +2830,182 @@
mRightVolShort = rightVol;
}
-AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::threadLoop_prepareTracks_l(
- sp<Track>& trackToRemove
+AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prepareTracks_l(
+ Vector< sp<Track> > *tracksToRemove
)
{
-// FIXME Temporarily renamed to avoid confusion with the member "mixerStatus"
-mixer_state mixerStatus_ = MIXER_IDLE;
+ sp<Track> trackToRemove;
- // find out which tracks need to be processed
- if (mActiveTracks.size() != 0) {
- sp<Track> t = mActiveTracks[0].promote();
- // see FIXME in AudioFlinger.h, return MIXER_IDLE might also work
- if (t == 0) return MIXER_CONTINUE;
- //if (t == 0) continue;
+ // FIXME Temporarily renamed to avoid confusion with the member "mixerStatus"
+ mixer_state mixerStatus_ = MIXER_IDLE;
- Track* const track = t.get();
- audio_track_cblk_t* cblk = track->cblk();
+ // find out which tracks need to be processed
+ if (mActiveTracks.size() != 0) {
+ sp<Track> t = mActiveTracks[0].promote();
+ // see FIXME in AudioFlinger.h, return MIXER_IDLE might also work
+ if (t == 0) return MIXER_CONTINUE;
+ //if (t == 0) continue;
- // The first time a track is added we wait
- // for all its buffers to be filled before processing it
- if (cblk->framesReady() && track->isReady() &&
- !track->isPaused() && !track->isTerminated())
- {
- //ALOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
+ Track* const track = t.get();
+ audio_track_cblk_t* cblk = track->cblk();
- if (track->mFillingUpStatus == Track::FS_FILLED) {
- track->mFillingUpStatus = Track::FS_ACTIVE;
- mLeftVolFloat = mRightVolFloat = 0;
- mLeftVolShort = mRightVolShort = 0;
- if (track->mState == TrackBase::RESUMING) {
- track->mState = TrackBase::ACTIVE;
- rampVolume = true;
- }
- } else if (cblk->server != 0) {
- // If the track is stopped before the first frame was mixed,
- // do not apply ramp
- rampVolume = true;
- }
- // compute volume for this track
- float left, right;
- if (track->isMuted() || mMasterMute || track->isPausing() ||
- mStreamTypes[track->streamType()].mute) {
- left = right = 0;
- if (track->isPausing()) {
- track->setPaused();
- }
- } else {
- float typeVolume = mStreamTypes[track->streamType()].volume;
- float v = mMasterVolume * typeVolume;
- uint32_t vlr = cblk->getVolumeLR();
- float v_clamped = v * (vlr & 0xFFFF);
- if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
- left = v_clamped/MAX_GAIN;
- v_clamped = v * (vlr >> 16);
- if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
- right = v_clamped/MAX_GAIN;
- }
+ // The first time a track is added we wait
+ // for all its buffers to be filled before processing it
+ if (cblk->framesReady() && track->isReady() &&
+ !track->isPaused() && !track->isTerminated())
+ {
+ //ALOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
- if (left != mLeftVolFloat || right != mRightVolFloat) {
- mLeftVolFloat = left;
- mRightVolFloat = right;
+ if (track->mFillingUpStatus == Track::FS_FILLED) {
+ track->mFillingUpStatus = Track::FS_ACTIVE;
+ mLeftVolFloat = mRightVolFloat = 0;
+ mLeftVolShort = mRightVolShort = 0;
+ if (track->mState == TrackBase::RESUMING) {
+ track->mState = TrackBase::ACTIVE;
+ rampVolume = true;
+ }
+ } else if (cblk->server != 0) {
+ // If the track is stopped before the first frame was mixed,
+ // do not apply ramp
+ rampVolume = true;
+ }
+ // compute volume for this track
+ float left, right;
+ if (track->isMuted() || mMasterMute || track->isPausing() ||
+ mStreamTypes[track->streamType()].mute) {
+ left = right = 0;
+ if (track->isPausing()) {
+ track->setPaused();
+ }
+ } else {
+ float typeVolume = mStreamTypes[track->streamType()].volume;
+ float v = mMasterVolume * typeVolume;
+ uint32_t vlr = cblk->getVolumeLR();
+ float v_clamped = v * (vlr & 0xFFFF);
+ if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+ left = v_clamped/MAX_GAIN;
+ v_clamped = v * (vlr >> 16);
+ if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+ right = v_clamped/MAX_GAIN;
+ }
- // If audio HAL implements volume control,
- // force software volume to nominal value
- if (mOutput->stream->set_volume(mOutput->stream, left, right) == NO_ERROR) {
- left = 1.0f;
- right = 1.0f;
- }
+ if (left != mLeftVolFloat || right != mRightVolFloat) {
+ mLeftVolFloat = left;
+ mRightVolFloat = right;
- // Convert volumes from float to 8.24
- uint32_t vl = (uint32_t)(left * (1 << 24));
- uint32_t vr = (uint32_t)(right * (1 << 24));
+ // If audio HAL implements volume control,
+ // force software volume to nominal value
+ if (mOutput->stream->set_volume(mOutput->stream, left, right) == NO_ERROR) {
+ left = 1.0f;
+ right = 1.0f;
+ }
- // Delegate volume control to effect in track effect chain if needed
- // only one effect chain can be present on DirectOutputThread, so if
- // there is one, the track is connected to it
- if (!mEffectChains.isEmpty()) {
- // Do not ramp volume if volume is controlled by effect
- if (mEffectChains[0]->setVolume_l(&vl, &vr)) {
- rampVolume = false;
- }
- }
+ // Convert volumes from float to 8.24
+ uint32_t vl = (uint32_t)(left * (1 << 24));
+ uint32_t vr = (uint32_t)(right * (1 << 24));
- // Convert volumes from 8.24 to 4.12 format
- uint32_t v_clamped = (vl + (1 << 11)) >> 12;
- if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
- leftVol = (uint16_t)v_clamped;
- v_clamped = (vr + (1 << 11)) >> 12;
- if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
- rightVol = (uint16_t)v_clamped;
- } else {
- leftVol = mLeftVolShort;
- rightVol = mRightVolShort;
+ // Delegate volume control to effect in track effect chain if needed
+ // only one effect chain can be present on DirectOutputThread, so if
+ // there is one, the track is connected to it
+ if (!mEffectChains.isEmpty()) {
+ // Do not ramp volume if volume is controlled by effect
+ if (mEffectChains[0]->setVolume_l(&vl, &vr)) {
rampVolume = false;
}
+ }
- // reset retry count
- track->mRetryCount = kMaxTrackRetriesDirect;
- activeTrack = t;
- mixerStatus_ = MIXER_TRACKS_READY;
+ // Convert volumes from 8.24 to 4.12 format
+ uint32_t v_clamped = (vl + (1 << 11)) >> 12;
+ if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
+ leftVol = (uint16_t)v_clamped;
+ v_clamped = (vr + (1 << 11)) >> 12;
+ if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
+ rightVol = (uint16_t)v_clamped;
+ } else {
+ leftVol = mLeftVolShort;
+ rightVol = mRightVolShort;
+ rampVolume = false;
+ }
+
+ // reset retry count
+ track->mRetryCount = kMaxTrackRetriesDirect;
+ activeTrack = t;
+ mixerStatus_ = MIXER_TRACKS_READY;
+ } else {
+ //ALOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
+ if (track->isStopped()) {
+ track->reset();
+ }
+ if (track->isTerminated() || track->isStopped() || track->isPaused()) {
+ // We have consumed all the buffers of this track.
+ // Remove it from the list of active tracks.
+ trackToRemove = track;
+ } else {
+ // No buffers for this track. Give it a few chances to
+ // fill a buffer, then remove it from active list.
+ if (--(track->mRetryCount) <= 0) {
+ ALOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
+ trackToRemove = track;
} else {
- //ALOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
- if (track->isStopped()) {
- track->reset();
- }
- if (track->isTerminated() || track->isStopped() || track->isPaused()) {
- // We have consumed all the buffers of this track.
- // Remove it from the list of active tracks.
- trackToRemove = track;
- } else {
- // No buffers for this track. Give it a few chances to
- // fill a buffer, then remove it from active list.
- if (--(track->mRetryCount) <= 0) {
- ALOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
- trackToRemove = track;
- } else {
- mixerStatus_ = MIXER_TRACKS_ENABLED;
- }
- }
+ mixerStatus_ = MIXER_TRACKS_ENABLED;
}
}
+ }
+ }
- // remove all the tracks that need to be...
- if (CC_UNLIKELY(trackToRemove != 0)) {
- mActiveTracks.remove(trackToRemove);
- if (!mEffectChains.isEmpty()) {
- ALOGV("stopping track on chain %p for session Id: %d", effectChains[0].get(),
- trackToRemove->sessionId());
- mEffectChains[0]->decActiveTrackCnt();
- }
- if (trackToRemove->isTerminated()) {
- removeTrack_l(trackToRemove);
- }
- }
+ // FIXME merge this with similar code for removing multiple tracks
+ // remove all the tracks that need to be...
+ if (CC_UNLIKELY(trackToRemove != 0)) {
+ tracksToRemove->add(trackToRemove);
+ mActiveTracks.remove(trackToRemove);
+ if (!mEffectChains.isEmpty()) {
+ ALOGV("stopping track on chain %p for session Id: %d", effectChains[0].get(),
+ trackToRemove->sessionId());
+ mEffectChains[0]->decActiveTrackCnt();
+ }
+ if (trackToRemove->isTerminated()) {
+ removeTrack_l(trackToRemove);
+ }
+ }
-return mixerStatus_;
+ return mixerStatus_;
}
void AudioFlinger::DirectOutputThread::threadLoop_mix()
{
- AudioBufferProvider::Buffer buffer;
- size_t frameCount = mFrameCount;
- int8_t *curBuf = (int8_t *)mMixBuffer;
- // output audio to hardware
- while (frameCount) {
- buffer.frameCount = frameCount;
- activeTrack->getNextBuffer(&buffer);
- if (CC_UNLIKELY(buffer.raw == NULL)) {
- memset(curBuf, 0, frameCount * mFrameSize);
- break;
- }
- memcpy(curBuf, buffer.raw, buffer.frameCount * mFrameSize);
- frameCount -= buffer.frameCount;
- curBuf += buffer.frameCount * mFrameSize;
- activeTrack->releaseBuffer(&buffer);
- }
- sleepTime = 0;
- standbyTime = systemTime() + standbyDelay;
+ AudioBufferProvider::Buffer buffer;
+ size_t frameCount = mFrameCount;
+ int8_t *curBuf = (int8_t *)mMixBuffer;
+ // output audio to hardware
+ while (frameCount) {
+ buffer.frameCount = frameCount;
+ activeTrack->getNextBuffer(&buffer);
+ if (CC_UNLIKELY(buffer.raw == NULL)) {
+ memset(curBuf, 0, frameCount * mFrameSize);
+ break;
+ }
+ memcpy(curBuf, buffer.raw, buffer.frameCount * mFrameSize);
+ frameCount -= buffer.frameCount;
+ curBuf += buffer.frameCount * mFrameSize;
+ activeTrack->releaseBuffer(&buffer);
+ }
+ sleepTime = 0;
+ standbyTime = systemTime() + standbyDelay;
+ applyVolume();
}
void AudioFlinger::DirectOutputThread::threadLoop_sleepTime()
{
- if (sleepTime == 0) {
- if (mixerStatus == MIXER_TRACKS_ENABLED) {
- sleepTime = activeSleepTime;
- } else {
- sleepTime = idleSleepTime;
- }
- } else if (mBytesWritten != 0 && audio_is_linear_pcm(mFormat)) {
- memset (mMixBuffer, 0, mFrameCount * mFrameSize);
- sleepTime = 0;
- }
+ if (sleepTime == 0) {
+ if (mixerStatus == MIXER_TRACKS_ENABLED) {
+ sleepTime = activeSleepTime;
+ } else {
+ sleepTime = idleSleepTime;
+ }
+ } else if (mBytesWritten != 0 && audio_is_linear_pcm(mFormat)) {
+ memset (mMixBuffer, 0, mFrameCount * mFrameSize);
+ sleepTime = 0;
+ }
}
// getTrackName_l() must be called with ThreadBase::mLock held
@@ -3139,52 +3120,52 @@
void AudioFlinger::DuplicatingThread::threadLoop_mix()
{
- // mix buffers...
- if (outputsReady(outputTracks)) {
- mAudioMixer->process(AudioBufferProvider::kInvalidPTS);
- } else {
- memset(mMixBuffer, 0, mixBufferSize);
- }
- sleepTime = 0;
- writeFrames = mFrameCount;
+ // mix buffers...
+ if (outputsReady(outputTracks)) {
+ mAudioMixer->process(AudioBufferProvider::kInvalidPTS);
+ } else {
+ memset(mMixBuffer, 0, mixBufferSize);
+ }
+ sleepTime = 0;
+ writeFrames = mFrameCount;
}
void AudioFlinger::DuplicatingThread::threadLoop_sleepTime()
{
- if (sleepTime == 0) {
- if (mixerStatus == MIXER_TRACKS_ENABLED) {
- sleepTime = activeSleepTime;
- } else {
- sleepTime = idleSleepTime;
- }
- } else if (mBytesWritten != 0) {
- // flush remaining overflow buffers in output tracks
- for (size_t i = 0; i < outputTracks.size(); i++) {
- if (outputTracks[i]->isActive()) {
- sleepTime = 0;
- writeFrames = 0;
- memset(mMixBuffer, 0, mixBufferSize);
- break;
- }
- }
+ if (sleepTime == 0) {
+ if (mixerStatus == MIXER_TRACKS_ENABLED) {
+ sleepTime = activeSleepTime;
+ } else {
+ sleepTime = idleSleepTime;
+ }
+ } else if (mBytesWritten != 0) {
+ // flush remaining overflow buffers in output tracks
+ for (size_t i = 0; i < outputTracks.size(); i++) {
+ if (outputTracks[i]->isActive()) {
+ sleepTime = 0;
+ writeFrames = 0;
+ memset(mMixBuffer, 0, mixBufferSize);
+ break;
}
+ }
+ }
}
void AudioFlinger::DuplicatingThread::threadLoop_write()
{
- standbyTime = systemTime() + mStandbyTimeInNsecs;
- for (size_t i = 0; i < outputTracks.size(); i++) {
- outputTracks[i]->write(mMixBuffer, writeFrames);
- }
- mBytesWritten += mixBufferSize;
+ standbyTime = systemTime() + mStandbyTimeInNsecs;
+ for (size_t i = 0; i < outputTracks.size(); i++) {
+ outputTracks[i]->write(mMixBuffer, writeFrames);
+ }
+ mBytesWritten += mixBufferSize;
}
void AudioFlinger::DuplicatingThread::threadLoop_standby()
{
- // DuplicatingThread implements standby by stopping all tracks
- for (size_t i = 0; i < outputTracks.size(); i++) {
- outputTracks[i]->stop();
- }
+ // DuplicatingThread implements standby by stopping all tracks
+ for (size_t i = 0; i < outputTracks.size(); i++) {
+ outputTracks[i]->stop();
+ }
}
void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread)
@@ -3202,7 +3183,7 @@
thread->setStreamVolume(AUDIO_STREAM_CNT, 1.0f);
mOutputTracks.add(outputTrack);
ALOGV("addOutputTrack() track %p, on thread %p", outputTrack, thread);
- updateWaitTime();
+ updateWaitTime_l();
}
}
@@ -3213,14 +3194,15 @@
if (mOutputTracks[i]->thread() == thread) {
mOutputTracks[i]->destroy();
mOutputTracks.removeAt(i);
- updateWaitTime();
+ updateWaitTime_l();
return;
}
}
ALOGV("removeOutputTrack(): unkonwn thread: %p", thread);
}
-void AudioFlinger::DuplicatingThread::updateWaitTime()
+// caller must hold mLock
+void AudioFlinger::DuplicatingThread::updateWaitTime_l()
{
mWaitTimeMs = UINT_MAX;
for (size_t i = 0; i < mOutputTracks.size(); i++) {
@@ -5700,9 +5682,9 @@
size_t num = mAudioSessionRefs.size();
for (size_t i = 0; i< num; i++) {
AudioSessionRef *ref = mAudioSessionRefs.editItemAt(i);
- if (ref->sessionid == audioSession && ref->pid == caller) {
- ref->cnt++;
- ALOGV(" incremented refcount to %d", ref->cnt);
+ if (ref->mSessionid == audioSession && ref->mPid == caller) {
+ ref->mCnt++;
+ ALOGV(" incremented refcount to %d", ref->mCnt);
return;
}
}
@@ -5718,10 +5700,10 @@
size_t num = mAudioSessionRefs.size();
for (size_t i = 0; i< num; i++) {
AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
- if (ref->sessionid == audioSession && ref->pid == caller) {
- ref->cnt--;
- ALOGV(" decremented refcount to %d", ref->cnt);
- if (ref->cnt == 0) {
+ if (ref->mSessionid == audioSession && ref->mPid == caller) {
+ ref->mCnt--;
+ ALOGV(" decremented refcount to %d", ref->mCnt);
+ if (ref->mCnt == 0) {
mAudioSessionRefs.removeAt(i);
delete ref;
purgeStaleEffects_l();
@@ -5766,9 +5748,9 @@
bool found = false;
for (size_t k = 0; k < numsessionrefs; k++) {
AudioSessionRef *ref = mAudioSessionRefs.itemAt(k);
- if (ref->sessionid == sessionid) {
+ if (ref->mSessionid == sessionid) {
ALOGV(" session %d still exists for %d with %d refs",
- sessionid, ref->pid, ref->cnt);
+ sessionid, ref->mPid, ref->mCnt);
found = true;
break;
}
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index c7ac0a8..8ca4f89 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -534,7 +534,10 @@
friend class RecordTrack;
const type_t mType;
+
+ // Used by parameters, config events, addTrack_l, exit
Condition mWaitWorkCV;
+
const sp<AudioFlinger> mAudioFlinger;
uint32_t mSampleRate;
size_t mFrameCount;
@@ -542,9 +545,30 @@
uint16_t mChannelCount;
size_t mFrameSize;
audio_format_t mFormat;
+
+ // Parameter sequence by client: binder thread calling setParameters():
+ // 1. Lock mLock
+ // 2. Append to mNewParameters
+ // 3. mWaitWorkCV.signal
+ // 4. mParamCond.waitRelative with timeout
+ // 5. read mParamStatus
+ // 6. mWaitWorkCV.signal
+ // 7. Unlock
+ //
+ // Parameter sequence by server: threadLoop calling checkForNewParameters_l():
+ // 1. Lock mLock
+ // 2. If there is an entry in mNewParameters proceed ...
+ // 2. Read first entry in mNewParameters
+ // 3. Process
+ // 4. Remove first entry from mNewParameters
+ // 5. Set mParamStatus
+ // 6. mParamCond.signal
+ // 7. mWaitWorkCV.wait with timeout (this is to avoid overwriting mParamStatus)
+ // 8. Unlock
Condition mParamCond;
Vector<String8> mNewParameters;
status_t mParamStatus;
+
Vector<ConfigEvent> mConfigEvents;
bool mStandby;
const audio_io_handle_t mId;
@@ -584,7 +608,7 @@
// standby mode does not have an enum value
// suspend by audio policy manager is orthogonal to mixer state
#if 1
- // FIXME remove these hacks for threadLoop_prepareTracks_l
+ // FIXME remove this hack for prepareTracks_l()
, MIXER_CONTINUE // "continue;"
#endif
};
@@ -812,17 +836,16 @@
virtual void threadLoop_standby();
// Non-trivial for DUPLICATING only
- virtual void updateWaitTime() { }
+ virtual void updateWaitTime_l() { }
// Non-trivial for DIRECT only
virtual void applyVolume() { }
- // FIXME merge these
- // Non-trivial for MIXER and DUPLICATING only
- virtual mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove) { return MIXER_IDLE; }
- // Non-trivial for DIRECT only
- virtual mixer_state threadLoop_prepareTracks_l(sp<Track>& trackToRemove)
- { return MIXER_IDLE; }
+ // prepareTracks_l reads and writes mActiveTracks, and also returns the
+ // pending set of tracks to remove via Vector 'tracksToRemove'. The caller is
+ // responsible for clearing or destroying this Vector later on, when it
+ // is safe to do so. That will drop the final ref count and destroy the tracks.
+ virtual mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove) = 0;
public:
@@ -970,10 +993,6 @@
virtual status_t dumpInternals(int fd, const Vector<String16>& args);
protected:
- // prepareTracks_l reads and writes mActiveTracks, and also returns the
- // pending set of tracks to remove via Vector 'tracksToRemove'. The caller is
- // responsible for clearing or destroying this Vector later on, when it
- // is safe to do so. That will drop the final ref count and destroy the tracks.
virtual mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove);
virtual int getTrackName_l();
virtual void deleteTrackName_l(int name);
@@ -1006,10 +1025,9 @@
virtual uint32_t suspendSleepTimeUs();
// threadLoop snippets
- virtual mixer_state threadLoop_prepareTracks_l(sp<Track>& trackToRemove);
+ virtual mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove);
virtual void threadLoop_mix();
virtual void threadLoop_sleepTime();
- virtual void applyVolume();
// volumes last sent to audio HAL with stream->set_volume()
// FIXME use standard representation and names
@@ -1023,6 +1041,9 @@
bool rampVolume;
uint16_t leftVol;
uint16_t rightVol;
+
+private:
+ void applyVolume(); // FIXME inline into threadLoop_mix()
};
class DuplicatingThread : public MixerThread {
@@ -1046,7 +1067,9 @@
virtual void threadLoop_sleepTime();
virtual void threadLoop_write();
virtual void threadLoop_standby();
- virtual void updateWaitTime();
+
+ // called from threadLoop, addOutputTrack, removeOutputTrack
+ virtual void updateWaitTime_l();
private:
uint32_t mWaitTimeMs;
@@ -1570,12 +1593,11 @@
// for mAudioSessionRefs only
struct AudioSessionRef {
- // FIXME rename parameter names when fields get "m" prefix
- AudioSessionRef(int sessionid_, pid_t pid_) :
- sessionid(sessionid_), pid(pid_), cnt(1) {}
- const int sessionid;
- const pid_t pid;
- int cnt;
+ AudioSessionRef(int sessionid, pid_t pid) :
+ mSessionid(sessionid), mPid(pid), mCnt(1) {}
+ const int mSessionid;
+ const pid_t mPid;
+ int mCnt;
};
friend class RecordThread;