summaryrefslogtreecommitdiffstats
path: root/services/audioflinger/Threads.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'services/audioflinger/Threads.cpp')
-rw-r--r--services/audioflinger/Threads.cpp188
1 files changed, 164 insertions, 24 deletions
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 7d2d550..c3ee6c2 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -13,6 +13,25 @@
** 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 file was modified by DTS, Inc. The portions of the
+** code that are surrounded by "DTS..." are copyrighted and
+** licensed separately, as follows:
+**
+** (C) 2015 DTS, Inc.
+**
+** 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.
+**
*/
@@ -72,6 +91,9 @@
#include <cpustats/ThreadCpuUsage.h>
#endif
+#ifdef SRS_PROCESSING
+#include "postpro_patch.h"
+#endif
// ----------------------------------------------------------------------------
// Note: the following macro is used for extremely verbose logging message. In
@@ -544,6 +566,7 @@ AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio
mSystemReady(systemReady)
{
memset(&mPatch, 0, sizeof(struct audio_patch));
+ mIsDirectPcm = false;
}
AudioFlinger::ThreadBase::~ThreadBase()
@@ -1154,7 +1177,8 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
// 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) {
+ // Exception: allow effects for Direct PCM
+ if (mType == DIRECT && !mIsDirectPcm) {
ALOGW("createEffect_l() Cannot add effect %s on Direct output type thread %s",
desc->name, mThreadName);
lStatus = BAD_VALUE;
@@ -1163,7 +1187,7 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
// Reject any effect on mixer or duplicating multichannel sinks.
// TODO: fix both format and multichannel issues with effects.
- if ((mType == MIXER || mType == DUPLICATING) && mChannelCount != FCC_2) {
+ if ((mType == MIXER || mType == DUPLICATING) && mChannelCount > FCC_2) {
ALOGW("createEffect_l() Cannot add effect %s for multichannel(%d) %s threads",
desc->name, mChannelCount, mType == MIXER ? "MIXER" : "DUPLICATING");
lStatus = BAD_VALUE;
@@ -1171,12 +1195,17 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
}
// Allow global effects only on offloaded and mixer threads
+ // Exception: allow effects for Direct PCM
if (sessionId == AUDIO_SESSION_OUTPUT_MIX) {
switch (mType) {
case MIXER:
case OFFLOAD:
break;
case DIRECT:
+ if (mIsDirectPcm) {
+ // Allow effects when direct PCM enabled on Direct output
+ break;
+ }
case DUPLICATING:
case RECORD:
default:
@@ -1229,7 +1258,13 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
if (lStatus != NO_ERROR) {
goto Exit;
}
- effect->setOffloaded(mType == OFFLOAD, mId);
+
+ bool setVal = false;
+ if (mType == OFFLOAD || (mType == DIRECT && mIsDirectPcm)) {
+ setVal = true;
+ }
+
+ effect->setOffloaded(setVal, mId);
lStatus = chain->addEffect_l(effect);
if (lStatus != NO_ERROR) {
@@ -1313,7 +1348,13 @@ status_t AudioFlinger::ThreadBase::addEffect_l(const sp<EffectModule>& effect)
return BAD_VALUE;
}
- effect->setOffloaded(mType == OFFLOAD, mId);
+ bool setval = false;
+
+ if ((mType == OFFLOAD) || (mType == DIRECT && mIsDirectPcm)) {
+ setval = true;
+ }
+
+ effect->setOffloaded(setval, mId);
status_t status = chain->addEffect_l(effect);
if (status != NO_ERROR) {
@@ -2167,6 +2208,7 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l()
kUseFastMixer == FastMixer_Dynamic)) {
size_t minNormalFrameCount = (kMinNormalSinkBufferSizeMs * mSampleRate) / 1000;
size_t maxNormalFrameCount = (kMaxNormalSinkBufferSizeMs * mSampleRate) / 1000;
+
// round up minimum and round down maximum to nearest 16 frames to satisfy AudioMixer
minNormalFrameCount = (minNormalFrameCount + 15) & ~15;
maxNormalFrameCount = maxNormalFrameCount & ~15;
@@ -2182,19 +2224,6 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l()
} else {
multiplier = (double) maxNormalFrameCount / (double) mFrameCount;
}
- } else {
- // prefer an even multiplier, for compatibility with doubling of fast tracks due to HAL
- // SRC (it would be unusual for the normal sink buffer size to not be a multiple of fast
- // track, but we sometimes have to do this to satisfy the maximum frame count
- // constraint)
- // FIXME this rounding up should not be done if no HAL SRC
- uint32_t truncMult = (uint32_t) multiplier;
- if ((truncMult & 1)) {
- if ((truncMult + 1) * mFrameCount <= maxNormalFrameCount) {
- ++truncMult;
- }
- }
- multiplier = (double) truncMult;
}
}
mNormalFrameCount = multiplier * mFrameCount;
@@ -2731,6 +2760,19 @@ bool AudioFlinger::PlaybackThread::threadLoop()
const String8 myName(String8::format("thread %p type %d TID %d", this, mType, gettid()));
acquireWakeLock();
+#ifdef SRS_PROCESSING
+ String8 bt_param = String8("bluetooth_enabled=0");
+ POSTPRO_PATCH_PARAMS_SET(bt_param);
+ if (mType == MIXER) {
+ POSTPRO_PATCH_OUTPROC_PLAY_INIT(this, myName);
+ } else if (mType == OFFLOAD) {
+ POSTPRO_PATCH_OUTPROC_DIRECT_INIT(this, myName);
+ POSTPRO_PATCH_OUTPROC_PLAY_ROUTE_BY_VALUE(this, mOutDevice);
+ } else if (mType == DIRECT) {
+ POSTPRO_PATCH_OUTPROC_DIRECT_INIT(this, myName);
+ POSTPRO_PATCH_OUTPROC_PLAY_ROUTE_BY_VALUE(this, mOutDevice);
+ }
+#endif
// mNBLogWriter->log can only be called while thread mutex mLock is held.
// So if you need to log when mutex is unlocked, set logString to a non-NULL string,
@@ -2906,7 +2948,8 @@ bool AudioFlinger::PlaybackThread::threadLoop()
}
// only process effects if we're going to write
- if (mSleepTimeUs == 0 && mType != OFFLOAD) {
+ if (mSleepTimeUs == 0 && mType != OFFLOAD &&
+ !(mType == DIRECT && mIsDirectPcm)) {
for (size_t i = 0; i < effectChains.size(); i ++) {
effectChains[i]->process_l();
}
@@ -2916,12 +2959,18 @@ bool AudioFlinger::PlaybackThread::threadLoop()
// was read from audio track: process only updates effect state
// and thus does have to be synchronized with audio writes but may have
// to be called while waiting for async write callback
- if (mType == OFFLOAD) {
+ if ((mType == OFFLOAD) || (mType == DIRECT && mIsDirectPcm)) {
for (size_t i = 0; i < effectChains.size(); i ++) {
effectChains[i]->process_l();
}
}
-
+#ifdef SRS_PROCESSING
+ // Offload thread
+ if (mType == OFFLOAD) {
+ char buffer[2];
+ POSTPRO_PATCH_OUTPROC_DIRECT_SAMPLES(this, AUDIO_FORMAT_PCM_16_BIT, (int16_t *) buffer, 2, 48000, 2);
+ }
+#endif
// 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.
@@ -2939,6 +2988,11 @@ bool AudioFlinger::PlaybackThread::threadLoop()
// mSleepTimeUs == 0 means we must write to audio hardware
if (mSleepTimeUs == 0) {
ssize_t ret = 0;
+#ifdef SRS_PROCESSING
+ if (mType == MIXER && mMixerStatus == MIXER_TRACKS_READY) {
+ POSTPRO_PATCH_OUTPROC_PLAY_SAMPLES(this, mFormat, mSinkBuffer, mSinkBufferSize, mSampleRate, mChannelCount);
+ }
+#endif
if (mBytesRemaining) {
ret = threadLoop_write();
if (ret < 0) {
@@ -2982,8 +3036,9 @@ bool AudioFlinger::PlaybackThread::threadLoop()
// the app won't fill fast enough to handle the sudden draw).
const int32_t deltaMs = delta / 1000000;
- const int32_t throttleMs = mHalfBufferMs - deltaMs;
- if ((signed)mHalfBufferMs >= throttleMs && throttleMs > 0) {
+ const int32_t halfBufferMs = mHalfBufferMs / (mEffectBufferValid ? 4 : 1);
+ const int32_t throttleMs = halfBufferMs - deltaMs;
+ if ((signed)halfBufferMs >= throttleMs && throttleMs > 0) {
usleep(throttleMs * 1000);
// notify of throttle start on verbose log
ALOGV_IF(mThreadThrottleEndMs == mThreadThrottleTimeMs,
@@ -3034,7 +3089,15 @@ bool AudioFlinger::PlaybackThread::threadLoop()
threadLoop_standby();
mStandby = true;
}
-
+#ifdef SRS_PROCESSING
+ if (mType == MIXER) {
+ POSTPRO_PATCH_OUTPROC_PLAY_EXIT(this, myName);
+ } else if (mType == OFFLOAD) {
+ POSTPRO_PATCH_OUTPROC_DIRECT_EXIT(this, myName);
+ } else if (mType == DIRECT) {
+ POSTPRO_PATCH_OUTPROC_DIRECT_EXIT(this, myName);
+ }
+#endif
releaseWakeLock();
mWakeLockUids.clear();
mActiveTracksGeneration++;
@@ -3128,6 +3191,10 @@ status_t AudioFlinger::PlaybackThread::createAudioPatch_l(const struct audio_pat
type |= patch->sinks[i].ext.device.type;
}
+#ifdef SRS_PROCESSING
+ POSTPRO_PATCH_OUTPROC_PLAY_ROUTE_BY_VALUE(this, type);
+#endif
+
#ifdef ADD_BATTERY_DATA
// when changing the audio output device, call addBatteryData to notify
// the change
@@ -3311,11 +3378,15 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud
}
if (initFastMixer) {
audio_format_t fastMixerFormat;
+#ifdef LEGACY_ALSA_AUDIO
+ fastMixerFormat = AUDIO_FORMAT_PCM_16_BIT;
+#else
if (mMixerBufferEnabled && mEffectBufferEnabled) {
fastMixerFormat = AUDIO_FORMAT_PCM_FLOAT;
} else {
fastMixerFormat = AUDIO_FORMAT_PCM_16_BIT;
}
+#endif
if (mFormat != fastMixerFormat) {
// change our Sink format to accept our intermediate precision
mFormat = fastMixerFormat;
@@ -4280,6 +4351,9 @@ bool AudioFlinger::MixerThread::checkForNewParameter_l(const String8& keyValuePa
AudioParameter param = AudioParameter(keyValuePair);
int value;
+#ifdef SRS_PROCESSING
+ POSTPRO_PATCH_OUTPROC_PLAY_ROUTE(this, param, value);
+#endif
if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
reconfig = true;
}
@@ -4823,6 +4897,7 @@ bool AudioFlinger::DirectOutputThread::checkForNewParameter_l(const String8& key
AudioParameter param = AudioParameter(keyValuePair);
int value;
+
if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
// forward device change to effects that have requested to be
// aware of attached audio device.
@@ -5312,6 +5387,8 @@ void AudioFlinger::DuplicatingThread::threadLoop_mix()
} else {
if (mMixerBufferValid) {
memset(mMixerBuffer, 0, mMixerBufferSize);
+ } else if (mEffectBufferValid) {
+ memset(mEffectBuffer, 0, mEffectBufferSize);
} else {
memset(mSinkBuffer, 0, mSinkBufferSize);
}
@@ -5333,7 +5410,11 @@ void AudioFlinger::DuplicatingThread::threadLoop_sleepTime()
} else if (mBytesWritten != 0) {
if (mMixerStatus == MIXER_TRACKS_ENABLED) {
writeFrames = mNormalFrameCount;
- memset(mSinkBuffer, 0, mSinkBufferSize);
+ if (mMixerBufferValid) {
+ memset(mMixerBuffer, 0, mMixerBufferSize);
+ } else {
+ memset(mSinkBuffer, 0, mSinkBufferSize);
+ }
} else {
// flush remaining overflow buffers in output tracks
writeFrames = 0;
@@ -6573,7 +6654,11 @@ size_t AudioFlinger::RecordThread::RecordBufferConverter::convert(void *dst,
break;
}
// format convert to destination buffer
+#ifdef LEGACY_ALSA_AUDIO
+ convert(dst, buffer.raw, buffer.frameCount);
+#else
convertNoResampler(dst, buffer.raw, buffer.frameCount);
+#endif
dst = (int8_t*)dst + buffer.frameCount * mDstFrameSize;
i -= buffer.frameCount;
@@ -6593,7 +6678,11 @@ size_t AudioFlinger::RecordThread::RecordBufferConverter::convert(void *dst,
memset(mBuf, 0, frames * mBufFrameSize);
frames = mResampler->resample((int32_t*)mBuf, frames, provider);
// format convert to destination buffer
+#ifdef LEGACY_ALSA_AUDIO
+ convert(dst, mBuf, frames);
+#else
convertResampler(dst, mBuf, frames);
+#endif
}
return frames;
}
@@ -6694,6 +6783,56 @@ status_t AudioFlinger::RecordThread::RecordBufferConverter::updateParameters(
return NO_ERROR;
}
+#ifdef LEGACY_ALSA_AUDIO
+void AudioFlinger::RecordThread::RecordBufferConverter::convert(
+ void *dst, /*const*/ void *src, size_t frames)
+{
+ // check if a memcpy will do
+ if (mResampler == NULL
+ && mSrcChannelCount == mDstChannelCount
+ && mSrcFormat == mDstFormat) {
+ memcpy(dst, src,
+ frames * mDstChannelCount * audio_bytes_per_sample(mDstFormat));
+ return;
+ }
+ // reallocate buffer if needed
+ if (mBufFrameSize != 0 && mBufFrames < frames) {
+ free(mBuf);
+ mBufFrames = frames;
+ (void)posix_memalign(&mBuf, 32, mBufFrames * mBufFrameSize);
+ }
+ // do processing
+ if (mResampler != NULL) {
+ // src channel count is always >= 2.
+ void *dstBuf = mBuf != NULL ? mBuf : dst;
+ // ditherAndClamp() works as long as all buffers returned by
+ // activeTrack->getNextBuffer() are 32 bit aligned which should be always true.
+ if (mDstChannelCount == 1) {
+ // the resampler always outputs stereo samples.
+ // FIXME: this rewrites back into src
+ ditherAndClamp((int32_t *)src, (const int32_t *)src, frames);
+ downmix_to_mono_i16_from_stereo_i16((int16_t *)dstBuf,
+ (const int16_t *)src, frames);
+ } else {
+ ditherAndClamp((int32_t *)dstBuf, (const int32_t *)src, frames);
+ }
+ } else if (mSrcChannelCount != mDstChannelCount) {
+ void *dstBuf = mBuf != NULL ? mBuf : dst;
+ if (mSrcChannelCount == 1) {
+ upmix_to_stereo_i16_from_mono_i16((int16_t *)dstBuf, (const int16_t *)src,
+ frames);
+ } else {
+ downmix_to_mono_i16_from_stereo_i16((int16_t *)dstBuf,
+ (const int16_t *)src, frames);
+ }
+ }
+ if (mSrcFormat != mDstFormat) {
+ void *srcBuf = mBuf != NULL ? mBuf : src;
+ memcpy_by_audio_format(dst, mDstFormat, srcBuf, mSrcFormat,
+ frames * mDstChannelCount);
+ }
+}
+#else
void AudioFlinger::RecordThread::RecordBufferConverter::convertNoResampler(
void *dst, const void *src, size_t frames)
{
@@ -6767,6 +6906,7 @@ void AudioFlinger::RecordThread::RecordBufferConverter::convertResampler(
memcpy_by_audio_format(dst, mDstFormat, src, AUDIO_FORMAT_PCM_FLOAT,
frames * mDstChannelCount);
}
+#endif
bool AudioFlinger::RecordThread::checkForNewParameter_l(const String8& keyValuePair,
status_t& status)