From 98ef978df4e928f486d244c4d7f7ad9f13111e98 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Tue, 4 Mar 2014 14:46:50 -0800 Subject: Add mEffectBuffer to AudioFlinger Change-Id: Icf97c50040bc127723d56eb4d2fb6e790a7253d9 Signed-off-by: Andy Hung --- services/audioflinger/Threads.cpp | 96 ++++++++++++++++++++++++++++++--------- 1 file changed, 75 insertions(+), 21 deletions(-) (limited to 'services/audioflinger/Threads.cpp') diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 8fdb50d..82c516c 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -34,6 +34,7 @@ #include #include #include +#include // NBAIO implementations #include @@ -820,6 +821,15 @@ sp AudioFlinger::ThreadBase::createEffect_l( goto Exit; } + // Reject any effect on Direct output threads for now, since the format of + // mSinkBuffer is not guaranteed to be compatible with effect processing (PCM 16 stereo). + if (mType == DIRECT) { + ALOGW("createEffect_l() Cannot add effect %s on Direct output type thread %s", + desc->name, mName); + lStatus = BAD_VALUE; + goto Exit; + } + // Allow global effects only on offloaded and mixer threads if (sessionId == AUDIO_SESSION_OUTPUT_MIX) { switch (mType) { @@ -1072,6 +1082,11 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp& audioFlinge mMixerBufferSize(0), mMixerBufferFormat(AUDIO_FORMAT_INVALID), mMixerBufferValid(false), + mEffectBufferEnabled(false), + mEffectBuffer(NULL), + mEffectBufferSize(0), + mEffectBufferFormat(AUDIO_FORMAT_INVALID), + mEffectBufferValid(false), mSuspended(0), mBytesWritten(0), mActiveTracksGeneration(0), // mStreamTypes[] initialized in constructor body @@ -1132,6 +1147,7 @@ AudioFlinger::PlaybackThread::~PlaybackThread() mAudioFlinger->unregisterWriter(mNBLogWriter); delete[] mSinkBuffer; free(mMixerBuffer); + free(mEffectBuffer); } void AudioFlinger::PlaybackThread::dump(int fd, const Vector& args) @@ -1218,6 +1234,7 @@ void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector& fdprintf(fd, " Suspend count: %d\n", mSuspended); fdprintf(fd, " Sink buffer : %p\n", mSinkBuffer); fdprintf(fd, " Mixer buffer: %p\n", mMixerBuffer); + fdprintf(fd, " Effect buffer: %p\n", mEffectBuffer); fdprintf(fd, " Fast track availMask=%#x\n", mFastTrackAvailMask); dumpBase(fd, args); @@ -1781,6 +1798,14 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l() * audio_bytes_per_sample(mMixerBufferFormat); (void)posix_memalign(&mMixerBuffer, 32, mMixerBufferSize); } + free(mEffectBuffer); + mEffectBuffer = NULL; + if (mEffectBufferEnabled) { + mEffectBufferFormat = AUDIO_FORMAT_PCM_16_BIT; // Note: Effects support 16b only + mEffectBufferSize = mNormalFrameCount * mChannelCount + * audio_bytes_per_sample(mEffectBufferFormat); + (void)posix_memalign(&mEffectBuffer, 32, mEffectBufferSize); + } // force reconfiguration of effect chains and engines to take new buffer size and audio // parameters into account @@ -2086,7 +2111,8 @@ void AudioFlinger::PlaybackThread::invalidateTracks(audio_stream_type_t streamTy status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp& chain) { int session = chain->sessionId(); - int16_t *buffer = mSinkBuffer; + int16_t *buffer = mEffectBufferEnabled + ? reinterpret_cast(mEffectBuffer) : mSinkBuffer; bool ownsBuffer = false; ALOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session); @@ -2126,7 +2152,8 @@ status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp& c } chain->setInBuffer(buffer, ownsBuffer); - chain->setOutBuffer(mSinkBuffer); + chain->setOutBuffer(mEffectBufferEnabled + ? reinterpret_cast(mEffectBuffer) : mSinkBuffer); // Effect chain for session AUDIO_SESSION_OUTPUT_STAGE is inserted at end of effect // chains list in order to be processed last as it contains output stage effects // Effect chain for session AUDIO_SESSION_OUTPUT_MIX is inserted before @@ -2373,23 +2400,6 @@ 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(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 @@ -2399,6 +2409,24 @@ bool AudioFlinger::PlaybackThread::threadLoop() mCurrentWriteLength = mSinkBufferSize; } } + // Either threadLoop_mix() or threadLoop_sleepTime() should have set + // mMixerBuffer with data if mMixerBufferValid is true and sleepTime == 0. + // Merge mMixerBuffer data into mEffectBuffer (if any effects are valid) + // or mSinkBuffer (if there are no effects). + // + // 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(). + // TODO use sleepTime == 0 as an additional condition. + if (mMixerBufferValid) { + void *buffer = mEffectBufferValid ? mEffectBuffer : mSinkBuffer; + audio_format_t format = mEffectBufferValid ? mEffectBufferFormat : mFormat; + + memcpy_by_audio_format(buffer, format, mMixerBuffer, mMixerBufferFormat, + mNormalFrameCount * mChannelCount); + } + mBytesRemaining = mCurrentWriteLength; if (isSuspended()) { sleepTime = suspendSleepTimeUs(); @@ -2424,6 +2452,16 @@ bool AudioFlinger::PlaybackThread::threadLoop() } } + // Only if the Effects buffer is enabled and there is data in the + // Effects buffer (buffer valid), we need to + // copy into the sink buffer. + // TODO use sleepTime == 0 as an additional condition. + if (mEffectBufferValid) { + //ALOGV("writing effect buffer to sink buffer format %#x", mFormat); + memcpy_by_audio_format(mSinkBuffer, mFormat, mEffectBuffer, mEffectBufferFormat, + mNormalFrameCount * mChannelCount); + } + // enable changes in effect chain unlockEffectChains(effectChains); @@ -2896,7 +2934,13 @@ void AudioFlinger::MixerThread::threadLoop_sleepTime() sleepTime = idleSleepTime; } } else if (mBytesWritten != 0 || (mMixerStatus == MIXER_TRACKS_ENABLED)) { - memset(mSinkBuffer, 0, mSinkBufferSize); + // clear out mMixerBuffer or mSinkBuffer, to ensure buffers are cleared + // before effects processing or output. + if (mMixerBufferValid) { + memset(mMixerBuffer, 0, mMixerBufferSize); + } else { + memset(mSinkBuffer, 0, mSinkBufferSize); + } sleepTime = 0; ALOGV_IF(mBytesWritten == 0 && (mMixerStatus == MIXER_TRACKS_ENABLED), "anticipated start"); @@ -2944,6 +2988,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac } mMixerBufferValid = false; // mMixerBuffer has no valid data until appropriate tracks found. + mEffectBufferValid = false; // mEffectBuffer has no valid data until tracks found. for (size_t i=0 ; i t = mActiveTracks[i].promote(); @@ -3151,6 +3196,9 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac chain.clear(); if (track->mainBuffer() != mSinkBuffer && track->mainBuffer() != mMixerBuffer) { + if (mEffectBufferEnabled) { + mEffectBufferValid = true; // Later can set directly. + } chain = getEffectChain_l(track->sessionId()); // Delegate volume control to effect in track effect chain if needed if (chain != 0) { @@ -3279,7 +3327,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac /* * Select the appropriate output buffer for the track. * - * For tracks with effects, only mSinkBuffer can be used (at this time). + * Tracks with effects go into their own effects chain buffer + * and from there into either mEffectBuffer or mSinkBuffer. * * Other tracks can use mMixerBuffer for higher precision * channel accumulation. If this buffer is enabled @@ -3441,6 +3490,11 @@ track_is_ready: ; // must imply MIXER_TRACKS_READY. // Later, we may clear buffers regardless, and skip much of this logic. } + // TODO - either mEffectBuffer or mSinkBuffer needs to be cleared. + if (mEffectBufferValid) { + memset(mEffectBuffer, 0, mEffectBufferSize); + } + // FIXME as a performance optimization, should remember previous zero status memset(mSinkBuffer, 0, mNormalFrameCount * mChannelCount * sizeof(int16_t)); } -- cgit v1.1