summaryrefslogtreecommitdiffstats
path: root/services/audioflinger/Threads.cpp
diff options
context:
space:
mode:
authorAndy Hung <hunga@google.com>2014-02-25 17:24:40 -0800
committerAndy Hung <hunga@google.com>2014-02-27 18:45:57 -0800
commit69aed5f0f4a3be3996d1e78a0473e1a72c1547da (patch)
treefd8fcfcc236538dd9ef08f515e628b263933ee66 /services/audioflinger/Threads.cpp
parent25c2dac12114699e90deb1c579cadebce7b91a97 (diff)
downloadframeworks_av-69aed5f0f4a3be3996d1e78a0473e1a72c1547da.zip
frameworks_av-69aed5f0f4a3be3996d1e78a0473e1a72c1547da.tar.gz
frameworks_av-69aed5f0f4a3be3996d1e78a0473e1a72c1547da.tar.bz2
Add MixerBuffer for accumulation of float audio
Path into and out of MixerBuffer is set up, but not currently enabled. Change-Id: I9d50752607d22dd2a3d9cc7e053babf8dfb22958 Signed-off-by: Andy Hung <hunga@google.com>
Diffstat (limited to 'services/audioflinger/Threads.cpp')
-rw-r--r--services/audioflinger/Threads.cpp100
1 files changed, 90 insertions, 10 deletions
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index be6fa19..b3d1dbe 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1067,6 +1067,11 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge
type_t type)
: ThreadBase(audioFlinger, id, device, AUDIO_DEVICE_NONE, type),
mNormalFrameCount(0), mSinkBuffer(NULL),
+ mMixerBufferEnabled(false),
+ mMixerBuffer(NULL),
+ mMixerBufferSize(0),
+ mMixerBufferFormat(AUDIO_FORMAT_INVALID),
+ mMixerBufferValid(false),
mSuspended(0), mBytesWritten(0),
mActiveTracksGeneration(0),
// mStreamTypes[] initialized in constructor body
@@ -1126,6 +1131,7 @@ AudioFlinger::PlaybackThread::~PlaybackThread()
{
mAudioFlinger->unregisterWriter(mNBLogWriter);
delete[] mSinkBuffer;
+ free(mMixerBuffer);
}
void AudioFlinger::PlaybackThread::dump(int fd, const Vector<String16>& args)
@@ -1211,6 +1217,7 @@ void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>&
fdprintf(fd, " Blocked in write: %s\n", mInWrite ? "yes" : "no");
fdprintf(fd, " Suspend count: %d\n", mSuspended);
fdprintf(fd, " Sink buffer : %p\n", mSinkBuffer);
+ fdprintf(fd, " Mixer buffer: %p\n", mMixerBuffer);
fdprintf(fd, " Fast track availMask=%#x\n", mFastTrackAvailMask);
dumpBase(fd, args);
@@ -1764,6 +1771,17 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l()
mSinkBuffer = new int16_t[(normalBufferSize + 1) >> 1];
memset(mSinkBuffer, 0, normalBufferSize);
+ // We resize the mMixerBuffer according to the requirements of the sink buffer which
+ // drives the output.
+ free(mMixerBuffer);
+ mMixerBuffer = NULL;
+ if (mMixerBufferEnabled) {
+ mMixerBufferFormat = AUDIO_FORMAT_PCM_FLOAT; // also valid: AUDIO_FORMAT_PCM_16_BIT.
+ mMixerBufferSize = mNormalFrameCount * mChannelCount
+ * audio_bytes_per_sample(mMixerBufferFormat);
+ (void)posix_memalign(&mMixerBuffer, 32, mMixerBufferSize);
+ }
+
// force reconfiguration of effect chains and engines to take new buffer size and audio
// parameters into account
// Note that mLock is not held when readOutputParameters_l() is called from the constructor
@@ -2355,6 +2373,23 @@ bool AudioFlinger::PlaybackThread::threadLoop()
if (mMixerStatus == MIXER_TRACKS_READY) {
// threadLoop_mix() sets mCurrentWriteLength
threadLoop_mix();
+
+ // Merge mMixerBuffer data into mSinkBuffer
+ // This is done pre-effects computation; if effects change to
+ // support higher precision, this needs to move.
+ //
+ // mMixerBufferValid is only set true by MixerThread::prepareTracks_l().
+ if (mMixerBufferValid) {
+ if (mMixerBufferFormat == AUDIO_FORMAT_PCM_FLOAT) {
+ memcpy_to_i16_from_float(mSinkBuffer,
+ reinterpret_cast<float*>(mMixerBuffer),
+ mNormalFrameCount * mChannelCount);
+ } else { // mMixerBufferFormat == AUDIO_FORMAT_PCM_16_BIT
+ memcpy(mSinkBuffer,
+ mMixerBuffer,
+ mNormalFrameCount * mChannelCount * sizeof(int16_t));
+ }
+ }
} else if ((mMixerStatus != MIXER_DRAIN_TRACK)
&& (mMixerStatus != MIXER_DRAIN_ALL)) {
// threadLoop_sleepTime sets sleepTime to 0 if data
@@ -2908,6 +2943,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
state = sq->begin();
}
+ mMixerBufferValid = false; // mMixerBuffer has no valid data until appropriate tracks found.
+
for (size_t i=0 ; i<count ; i++) {
const sp<Track> t = mActiveTracks[i].promote();
if (t == 0) {
@@ -3109,10 +3146,11 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
mixedTracks++;
- // track->mainBuffer() != mSinkBuffer means there is an effect chain
- // connected to the track
+ // track->mainBuffer() != mSinkBuffer or mMixerBuffer means
+ // there is an effect chain connected to the track
chain.clear();
- if (track->mainBuffer() != mSinkBuffer) {
+ if (track->mainBuffer() != mSinkBuffer &&
+ track->mainBuffer() != mMixerBuffer) {
chain = getEffectChain_l(track->sessionId());
// Delegate volume control to effect in track effect chain if needed
if (chain != 0) {
@@ -3238,10 +3276,40 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
AudioMixer::RESAMPLE,
AudioMixer::SAMPLE_RATE,
(void *)(uintptr_t)reqSampleRate);
- mAudioMixer->setParameter(
- name,
- AudioMixer::TRACK,
- AudioMixer::MAIN_BUFFER, (void *)track->mainBuffer());
+ /*
+ * Select the appropriate output buffer for the track.
+ *
+ * For tracks with effects, only mSinkBuffer can be used (at this time).
+ *
+ * Other tracks can use mMixerBuffer for higher precision
+ * channel accumulation. If this buffer is enabled
+ * (mMixerBufferEnabled true), then selected tracks will accumulate
+ * into it.
+ *
+ */
+ if (mMixerBufferEnabled
+ && (track->mainBuffer() == mSinkBuffer
+ || track->mainBuffer() == mMixerBuffer)) {
+ mAudioMixer->setParameter(
+ name,
+ AudioMixer::TRACK,
+ AudioMixer::SINK_FORMAT, (void *)mMixerBufferFormat);
+ mAudioMixer->setParameter(
+ name,
+ AudioMixer::TRACK,
+ AudioMixer::MAIN_BUFFER, (void *)mMixerBuffer);
+ // TODO: override track->mainBuffer()?
+ mMixerBufferValid = true;
+ } else {
+ mAudioMixer->setParameter(
+ name,
+ AudioMixer::TRACK,
+ AudioMixer::SINK_FORMAT, (void *)AUDIO_FORMAT_PCM_16_BIT);
+ mAudioMixer->setParameter(
+ name,
+ AudioMixer::TRACK,
+ AudioMixer::MAIN_BUFFER, (void *)track->mainBuffer());
+ }
mAudioMixer->setParameter(
name,
AudioMixer::TRACK,
@@ -3355,12 +3423,24 @@ track_is_ready: ;
// remove all the tracks that need to be...
removeTracks_l(*tracksToRemove);
- // sink buffer must be cleared if all tracks are connected to an
- // effect chain as in this case the mixer will not write to
- // sink buffer and track effects will accumulate into it
+ // sink or mix buffer must be cleared if all tracks are connected to an
+ // effect chain as in this case the mixer will not write to the sink or mix buffer
+ // and track effects will accumulate into it
if ((mBytesRemaining == 0) && ((mixedTracks != 0 && mixedTracks == tracksWithEffect) ||
(mixedTracks == 0 && fastTracks > 0))) {
// FIXME as a performance optimization, should remember previous zero status
+ if (mMixerBufferValid) {
+ memset(mMixerBuffer, 0, mMixerBufferSize);
+ // TODO: In testing, mSinkBuffer below need not be cleared because
+ // the PlaybackThread::threadLoop() copies mMixerBuffer into mSinkBuffer
+ // after mixing.
+ //
+ // To enforce this guarantee:
+ // ((mixedTracks != 0 && mixedTracks == tracksWithEffect) ||
+ // (mixedTracks == 0 && fastTracks > 0))
+ // must imply MIXER_TRACKS_READY.
+ // Later, we may clear buffers regardless, and skip much of this logic.
+ }
memset(mSinkBuffer, 0, mNormalFrameCount * mChannelCount * sizeof(int16_t));
}