diff options
Diffstat (limited to 'services/audioflinger')
-rw-r--r-- | services/audioflinger/Android.mk | 54 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 72 | ||||
-rw-r--r-- | services/audioflinger/AudioMixer.cpp | 28 | ||||
-rw-r--r-- | services/audioflinger/AudioMixer.h | 1 | ||||
-rw-r--r-- | services/audioflinger/AudioResampler.cpp | 25 | ||||
-rw-r--r-- | services/audioflinger/AudioResampler.h | 3 | ||||
-rw-r--r-- | services/audioflinger/AudioResamplerQTI.cpp | 173 | ||||
-rw-r--r-- | services/audioflinger/AudioResamplerQTI.h | 52 | ||||
-rw-r--r-- | services/audioflinger/BufferProviders.cpp | 2 | ||||
-rw-r--r-- | services/audioflinger/Effects.cpp | 25 | ||||
-rw-r--r-- | services/audioflinger/FastCapture.cpp | 3 | ||||
-rw-r--r-- | services/audioflinger/FastCaptureDumpState.cpp | 2 | ||||
-rw-r--r-- | services/audioflinger/FastMixer.cpp | 18 | ||||
-rw-r--r-- | services/audioflinger/Threads.cpp | 217 | ||||
-rw-r--r-- | services/audioflinger/Threads.h | 26 | ||||
-rw-r--r-- | services/audioflinger/Tracks.cpp | 14 |
16 files changed, 655 insertions, 60 deletions
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk index 9b4ba79..8ea26d3 100644 --- a/services/audioflinger/Android.mk +++ b/services/audioflinger/Android.mk @@ -1,3 +1,23 @@ +# +# 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. +# + LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) @@ -60,6 +80,14 @@ LOCAL_STATIC_LIBRARIES := \ libcpustats \ libmedia_helper +#QTI Resampler +ifeq ($(call is-vendor-board-platform,QCOM), true) +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXTN_RESAMPLER)), true) +LOCAL_CFLAGS += -DQTI_RESAMPLER +endif +endif +#QTI Resampler + LOCAL_MODULE:= libaudioflinger LOCAL_32_BIT_ONLY := true @@ -78,6 +106,11 @@ LOCAL_SRC_FILES += \ LOCAL_CFLAGS += -DSTATE_QUEUE_INSTANTIATIONS='"StateQueueInstantiations.cpp"' LOCAL_CFLAGS += -fvisibility=hidden +ifeq ($(strip $(BOARD_USES_SRS_TRUEMEDIA)),true) +LOCAL_SHARED_LIBRARIES += libsrsprocessing +LOCAL_CFLAGS += -DSRS_PROCESSING +LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audio-effects +endif include $(BUILD_SHARED_LIBRARY) @@ -123,7 +156,26 @@ LOCAL_C_INCLUDES := \ LOCAL_SHARED_LIBRARIES := \ libcutils \ libdl \ - liblog + liblog \ + libaudioutils + +#QTI Resampler +ifeq ($(call is-vendor-board-platform,QCOM),true) +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXTN_RESAMPLER)),true) +ifdef TARGET_2ND_ARCH +LOCAL_SRC_FILES_$(TARGET_2ND_ARCH) += AudioResamplerQTI.cpp.arm +LOCAL_C_INCLUDES_$(TARGET_2ND_ARCH) += $(TARGET_OUT_HEADERS)/mm-audio/audio-src +LOCAL_SHARED_LIBRARIES_$(TARGET_2ND_ARCH) += libqct_resampler +LOCAL_CFLAGS_$(TARGET_2ND_ARCH) += -DQTI_RESAMPLER +else +LOCAL_SRC_FILES += AudioResamplerQTI.cpp.arm +LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audio-src +LOCAL_SHARED_LIBRARIES += libqct_resampler +LOCAL_CFLAGS += -DQTI_RESAMPLER +endif +endif +endif +#QTI Resampler LOCAL_MODULE := libaudioresampler diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index fab1ef5..23215dd 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.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. +** */ @@ -64,6 +83,9 @@ #include <media/nbaio/PipeReader.h> #include <media/AudioParameter.h> #include <private/android_filesystem_config.h> +#ifdef SRS_PROCESSING +#include "postpro_patch.h" +#endif // ---------------------------------------------------------------------------- @@ -131,6 +153,14 @@ const char *formatToString(audio_format_t format) { case AUDIO_FORMAT_OPUS: return "opus"; case AUDIO_FORMAT_AC3: return "ac-3"; case AUDIO_FORMAT_E_AC3: return "e-ac-3"; + case AUDIO_FORMAT_PCM_OFFLOAD: + switch (format) { + case AUDIO_FORMAT_PCM_16_BIT_OFFLOAD: return "pcm-16bit-offload"; + case AUDIO_FORMAT_PCM_24_BIT_OFFLOAD: return "pcm-24bit-offload"; + default: + break; + } + break; default: break; } @@ -1043,6 +1073,13 @@ status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& if (ioHandle == AUDIO_IO_HANDLE_NONE) { Mutex::Autolock _l(mLock); status_t final_result = NO_ERROR; +#ifdef SRS_PROCESSING + POSTPRO_PATCH_PARAMS_SET(keyValuePairs); + for (size_t i = 0; i < mPlaybackThreads.size(); i++) { + PlaybackThread *thread = mPlaybackThreads.valueAt(i).get(); + thread->setPostPro(); + } +#endif { AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_HW_SET_PARAMETER; @@ -1053,9 +1090,24 @@ status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& } mHardwareStatus = AUDIO_HW_IDLE; } - // disable AEC and NS if the device is a BT SCO headset supporting those pre processings + AudioParameter param = AudioParameter(keyValuePairs); - String8 value; + String8 value, key; + key = String8("SND_CARD_STATUS"); + if (param.get(key, value) == NO_ERROR) { + ALOGV("Set keySoundCardStatus:%s", value.string()); + if ((value.find("OFFLINE", 0) != -1) ) { + ALOGV("OFFLINE detected - call InvalidateTracks()"); + for (size_t i = 0; i < mPlaybackThreads.size(); i++) { + PlaybackThread *thread = mPlaybackThreads.valueAt(i).get(); + if( thread->getOutput()->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD ){ + thread->invalidateTracks(AUDIO_STREAM_MUSIC); + } + } + } + } + + // disable AEC and NS if the device is a BT SCO headset supporting those pre processings if (param.get(String8(AUDIO_PARAMETER_KEY_BT_NREC), value) == NO_ERROR) { bool btNrecIsOff = (value == AUDIO_PARAMETER_VALUE_OFF); if (mBtNrecIsOff != btNrecIsOff) { @@ -1122,6 +1174,9 @@ String8 AudioFlinger::getParameters(audio_io_handle_t ioHandle, const String8& k if (ioHandle == AUDIO_IO_HANDLE_NONE) { String8 out_s8; +#ifdef SRS_PROCESSING + POSTPRO_PATCH_PARAMS_GET(keys, out_s8); +#endif for (size_t i = 0; i < mAudioHwDevs.size(); i++) { char *s; @@ -1347,6 +1402,12 @@ sp<AudioFlinger::PlaybackThread> AudioFlinger::getEffectThread_l(int sessionId, +void AudioFlinger::PlaybackThread::setPostPro() +{ + Mutex::Autolock _l(mLock); + if (mType == OFFLOAD) + broadcast_l(); +} // ---------------------------------------------------------------------------- AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid) @@ -1822,7 +1883,11 @@ sp<AudioFlinger::PlaybackThread> AudioFlinger::openOutput_l(audio_module_handle_ || !isValidPcmSinkFormat(config->format) || !isValidPcmSinkChannelMask(config->channel_mask)) { thread = new DirectOutputThread(this, outputStream, *output, devices, mSystemReady); - ALOGV("openOutput_l() created direct output: ID %d thread %p", *output, thread); + ALOGV("openOutput_l() created direct output: ID %d thread %p ", *output, thread); + //Check if this is DirectPCM, if so + if (flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) { + thread->mIsDirectPcm = true; + } } else { thread = new MixerThread(this, outputStream, *output, devices, mSystemReady); ALOGV("openOutput_l() created mixer output: ID %d thread %p", *output, thread); @@ -2964,6 +3029,7 @@ void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_hand bool firstRead = true; #define TEE_SINK_READ 1024 // frames per I/O operation void *buffer = malloc(TEE_SINK_READ * frameSize); + ALOG_ASSERT(buffer != NULL); for (;;) { size_t count = TEE_SINK_READ; ssize_t actual = teeSource->read(buffer, count, diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp index 8a9a837..bb9d4e5 100644 --- a/services/audioflinger/AudioMixer.cpp +++ b/services/audioflinger/AudioMixer.cpp @@ -85,6 +85,9 @@ static const bool kUseFloat = true; // Set to default copy buffer size in frames for input processing. static const size_t kCopyBufferFrameCount = 256; +#ifdef QTI_RESAMPLER +#define QTI_RESAMPLER_MAX_SAMPLERATE 192000 +#endif namespace android { // ---------------------------------------------------------------------------- @@ -305,6 +308,11 @@ bool AudioMixer::setChannelMasks(int name, void AudioMixer::track_t::unprepareForDownmix() { ALOGV("AudioMixer::unprepareForDownmix(%p)", this); + if (mPostDownmixReformatBufferProvider != NULL) { + delete mPostDownmixReformatBufferProvider; + mPostDownmixReformatBufferProvider = NULL; + reconfigureBufferProviders(); + } mDownmixRequiresFormat = AUDIO_FORMAT_INVALID; if (downmixerBufferProvider != NULL) { // this track had previously been configured with a downmixer, delete it @@ -360,18 +368,9 @@ status_t AudioMixer::track_t::prepareForDownmix() void AudioMixer::track_t::unprepareForReformat() { ALOGV("AudioMixer::unprepareForReformat(%p)", this); - bool requiresReconfigure = false; if (mReformatBufferProvider != NULL) { delete mReformatBufferProvider; mReformatBufferProvider = NULL; - requiresReconfigure = true; - } - if (mPostDownmixReformatBufferProvider != NULL) { - delete mPostDownmixReformatBufferProvider; - mPostDownmixReformatBufferProvider = NULL; - requiresReconfigure = true; - } - if (requiresReconfigure) { reconfigureBufferProviders(); } } @@ -779,6 +778,14 @@ bool AudioMixer::track_t::setResampler(uint32_t trackSampleRate, uint32_t devSam // but if none exists, it is the channel count (1 for mono). const int resamplerChannelCount = downmixerBufferProvider != NULL ? mMixerChannelCount : channelCount; +#ifdef QTI_RESAMPLER + if ((trackSampleRate <= QTI_RESAMPLER_MAX_SAMPLERATE) && + (trackSampleRate > devSampleRate * 2) && + ((devSampleRate == 48000)||(devSampleRate == 44100)) && + (resamplerChannelCount <= 2)) { + quality = AudioResampler::QTI_QUALITY; + } +#endif ALOGVV("Creating resampler:" " format(%#x) channels(%d) devSampleRate(%u) quality(%d)\n", mMixerInFormat, resamplerChannelCount, devSampleRate, quality); @@ -1644,6 +1651,9 @@ void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, // Note: In case of later int16_t sink output, // conversion and clamping is done by memcpy_to_i16_from_float(). } while (--outFrames); + //assign fout to out, when no more frames are available, so that 0s + //can be filled at the right place + out = (int32_t *)fout; break; case AUDIO_FORMAT_PCM_16_BIT: if (CC_UNLIKELY(uint32_t(vl) > UNITY_GAIN_INT || uint32_t(vr) > UNITY_GAIN_INT)) { diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h index 7165c6c..f0ae4ec 100644 --- a/services/audioflinger/AudioMixer.h +++ b/services/audioflinger/AudioMixer.h @@ -137,6 +137,7 @@ public: case AUDIO_FORMAT_PCM_8_BIT: case AUDIO_FORMAT_PCM_16_BIT: case AUDIO_FORMAT_PCM_24_BIT_PACKED: + case AUDIO_FORMAT_PCM_8_24_BIT: case AUDIO_FORMAT_PCM_32_BIT: case AUDIO_FORMAT_PCM_FLOAT: return true; diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp index e49b7b1..ab3294a 100644 --- a/services/audioflinger/AudioResampler.cpp +++ b/services/audioflinger/AudioResampler.cpp @@ -28,6 +28,10 @@ #include "AudioResamplerCubic.h" #include "AudioResamplerDyn.h" +#ifdef QTI_RESAMPLER +#include "AudioResamplerQTI.h" +#endif + #ifdef __arm__ #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1 #endif @@ -90,6 +94,9 @@ bool AudioResampler::qualityIsSupported(src_quality quality) case DYN_LOW_QUALITY: case DYN_MED_QUALITY: case DYN_HIGH_QUALITY: +#ifdef QTI_RESAMPLER + case QTI_QUALITY: +#endif return true; default: return false; @@ -110,7 +117,11 @@ void AudioResampler::init_routine() if (*endptr == '\0') { defaultQuality = (src_quality) l; ALOGD("forcing AudioResampler quality to %d", defaultQuality); +#ifdef QTI_RESAMPLER + if (defaultQuality < DEFAULT_QUALITY || defaultQuality > QTI_QUALITY) { +#else if (defaultQuality < DEFAULT_QUALITY || defaultQuality > DYN_HIGH_QUALITY) { +#endif defaultQuality = DEFAULT_QUALITY; } } @@ -129,6 +140,9 @@ uint32_t AudioResampler::qualityMHz(src_quality quality) case HIGH_QUALITY: return 20; case VERY_HIGH_QUALITY: +#ifdef QTI_RESAMPLER + case QTI_QUALITY: //for QTI_QUALITY, currently assuming same as VHQ +#endif return 34; case DYN_LOW_QUALITY: return 4; @@ -204,6 +218,11 @@ AudioResampler* AudioResampler::create(audio_format_t format, int inChannelCount case DYN_HIGH_QUALITY: quality = DYN_MED_QUALITY; break; +#ifdef QTI_RESAMPLER + case QTI_QUALITY: + quality = DYN_HIGH_QUALITY; + break; +#endif } } pthread_mutex_unlock(&mutex); @@ -250,6 +269,12 @@ AudioResampler* AudioResampler::create(audio_format_t format, int inChannelCount } } break; +#ifdef QTI_RESAMPLER + case QTI_QUALITY: + ALOGV("Create QTI_QUALITY Resampler = %d",quality); + resampler = new AudioResamplerQTI(format, inChannelCount, sampleRate); + break; +#endif } // initialize resampler diff --git a/services/audioflinger/AudioResampler.h b/services/audioflinger/AudioResampler.h index a8e3e6f..6669a85 100644 --- a/services/audioflinger/AudioResampler.h +++ b/services/audioflinger/AudioResampler.h @@ -47,6 +47,9 @@ public: DYN_LOW_QUALITY=5, DYN_MED_QUALITY=6, DYN_HIGH_QUALITY=7, +#ifdef QTI_RESAMPLER + QTI_QUALITY=8, +#endif }; static const CONSTEXPR float UNITY_GAIN_FLOAT = 1.0f; diff --git a/services/audioflinger/AudioResamplerQTI.cpp b/services/audioflinger/AudioResamplerQTI.cpp new file mode 100644 index 0000000..0d57e09 --- /dev/null +++ b/services/audioflinger/AudioResamplerQTI.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2014, The Linux Foundation. All rights reserved. + * Not a Contribution. + * 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. + */ + +#include "AudioResamplerQTI.h" +#include "QCT_Resampler.h" +#include <sys/time.h> +#include <audio_utils/primitives.h> + +namespace android { +AudioResamplerQTI::AudioResamplerQTI(int format, + int inChannelCount, int32_t sampleRate) + :AudioResampler(inChannelCount, sampleRate, QTI_QUALITY), + mOutFrameCount(0), mTmpBuf(0), mResamplerOutBuf(0), mFrameIndex(0) +{ + stateSize = QCT_Resampler::MemAlloc(format, inChannelCount, sampleRate, sampleRate); + mState = new int16_t[stateSize]; + mVolume[0] = mVolume[1] = 0; + mBuffer.frameCount = 0; +} + +AudioResamplerQTI::~AudioResamplerQTI() +{ + if (mState) { + delete [] mState; + } + if (mTmpBuf) { + delete [] mTmpBuf; + } + if(mResamplerOutBuf) { + delete [] mResamplerOutBuf; + } +} + +size_t AudioResamplerQTI::resample(int32_t* out, size_t outFrameCount, + AudioBufferProvider* provider) +{ + int16_t vl = mVolume[0]; + int16_t vr = mVolume[1]; + int32_t *pBuf; + + int64_t tempL, tempR; + size_t inFrameRequest; + size_t inFrameCount = getNumInSample(outFrameCount); + size_t index = 0; + size_t frameIndex = mFrameIndex; + size_t out_count = outFrameCount * 2; + float *fout = reinterpret_cast<float *>(out); + + if (mChannelCount == 1) { + inFrameRequest = inFrameCount; + } else { + inFrameRequest = inFrameCount * 2; + } + + if (mOutFrameCount < outFrameCount) { + mOutFrameCount = outFrameCount; + if (mTmpBuf) { + delete [] mTmpBuf; + } + if(mResamplerOutBuf) { + delete [] mResamplerOutBuf; + } + mTmpBuf = new int32_t[inFrameRequest + 16]; + mResamplerOutBuf = new int32_t[out_count]; + } + + if (mChannelCount == 1) { + // buffer is empty, fetch a new one + while (index < inFrameCount) { + if (!mBuffer.frameCount) { + mBuffer.frameCount = inFrameCount; + provider->getNextBuffer(&mBuffer); + frameIndex = 0; + } + + if (mBuffer.raw == NULL) { + while (index < inFrameCount) { + mTmpBuf[index++] = 0; + } + QCT_Resampler::Resample90dB(mState, mTmpBuf, mResamplerOutBuf, inFrameCount, outFrameCount); + goto resample_exit; + } + + mTmpBuf[index++] = clampq4_27_from_float(*((float *)mBuffer.raw + frameIndex++)); + + if (frameIndex >= mBuffer.frameCount) { + provider->releaseBuffer(&mBuffer); + } + } + + QCT_Resampler::Resample90dB(mState, mTmpBuf, mResamplerOutBuf, inFrameCount, outFrameCount); + } else { + pBuf = &mTmpBuf[inFrameCount]; + // buffer is empty, fetch a new one + while (index < inFrameCount) { + if (!mBuffer.frameCount) { + mBuffer.frameCount = inFrameCount; + provider->getNextBuffer(&mBuffer); + frameIndex = 0; + } + if (mBuffer.raw == NULL) { + while (index < inFrameCount) { + mTmpBuf[index] = 0; + pBuf[index++] = 0; + } + QCT_Resampler::Resample90dB(mState, mTmpBuf, mResamplerOutBuf, inFrameCount, outFrameCount); + goto resample_exit; + } + + mTmpBuf[index] = clampq4_27_from_float(*((float *)mBuffer.raw + frameIndex++)); + pBuf[index++] = clampq4_27_from_float(*((float *)mBuffer.raw + frameIndex++)); + if (frameIndex >= mBuffer.frameCount * 2) { + provider->releaseBuffer(&mBuffer); + } + } + + QCT_Resampler::Resample90dB(mState, mTmpBuf, mResamplerOutBuf, inFrameCount, outFrameCount); + } + +resample_exit: + for (int i = 0; i < out_count; i += 2) { + // Multiplying q4.27 data with u4.12 gain could result in 39 fractional bit data(27+12) + // To get back the 27 fractional bit format output data, do right shift by 12 + tempL = (int64_t)mResamplerOutBuf[i] * vl; + tempR = (int64_t)mResamplerOutBuf[i+1] * vr; + fout[i] += float_from_q4_27((int32_t)(tempL>>12)); + fout[i+1] += float_from_q4_27((int32_t)(tempR>>12)); + } + + mFrameIndex = frameIndex; + return index; +} + +void AudioResamplerQTI::setSampleRate(int32_t inSampleRate) +{ + if (mInSampleRate != inSampleRate) { + mInSampleRate = inSampleRate; + init(); + } +} + +void AudioResamplerQTI::init() +{ + QCT_Resampler::Init(mState, mChannelCount, mInSampleRate, mSampleRate, 1/*32bit in*/); +} + +size_t AudioResamplerQTI::getNumInSample(size_t outFrameCount) +{ + size_t size = (size_t)QCT_Resampler::GetNumInSamp(mState, outFrameCount); + return size; +} + +void AudioResamplerQTI::reset() +{ + AudioResampler::reset(); +} + +}; // namespace android diff --git a/services/audioflinger/AudioResamplerQTI.h b/services/audioflinger/AudioResamplerQTI.h new file mode 100644 index 0000000..1cf93fc --- /dev/null +++ b/services/audioflinger/AudioResamplerQTI.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014, The Linux Foundation. All rights reserved. + * Not a Contribution. + * 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. + */ + +#include <stdint.h> +#include <sys/types.h> +#include <cutils/log.h> + +#include "AudioResampler.h" + +namespace android { +// ---------------------------------------------------------------------------- + +class AudioResamplerQTI : public AudioResampler { +public: + AudioResamplerQTI(int format, int inChannelCount, int32_t sampleRate); + ~AudioResamplerQTI(); + size_t resample(int32_t* out, size_t outFrameCount, + AudioBufferProvider* provider); + void setSampleRate(int32_t inSampleRate); + size_t getNumInSample(size_t outFrameCount); + + int16_t *mState; + int32_t *mTmpBuf; + int32_t *mResamplerOutBuf; + size_t mFrameIndex; + size_t stateSize; + size_t mOutFrameCount; + + static const int kNumTmpBufSize = 1024; + + void init(); + void reset(); +}; + +// ---------------------------------------------------------------------------- +}; // namespace android + diff --git a/services/audioflinger/BufferProviders.cpp b/services/audioflinger/BufferProviders.cpp index a8be206..434a514 100644 --- a/services/audioflinger/BufferProviders.cpp +++ b/services/audioflinger/BufferProviders.cpp @@ -24,6 +24,7 @@ #include <media/EffectsFactoryApi.h> #include <utils/Log.h> +#include <media/stagefright/foundation/ADebug.h> #include "Configuration.h" #include "BufferProviders.h" @@ -205,6 +206,7 @@ DownmixerBufferProvider::DownmixerBufferProvider( const int downmixParamSize = sizeof(effect_param_t) + psizePadded + sizeof(downmix_type_t); effect_param_t * const param = (effect_param_t *) malloc(downmixParamSize); + CHECK(param != NULL); param->psize = sizeof(downmix_params_t); const downmix_params_t downmixParam = DOWNMIX_PARAM_TYPE; memcpy(param->data, &downmixParam, param->psize); diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp index 949c91d..879b6c9 100644 --- a/services/audioflinger/Effects.cpp +++ b/services/audioflinger/Effects.cpp @@ -318,6 +318,7 @@ void AudioFlinger::EffectModule::reset_l() status_t AudioFlinger::EffectModule::configure() { status_t status; + status_t cmdStatus = 0; sp<ThreadBase> thread; uint32_t size; audio_channel_mask_t channelMask; @@ -383,7 +384,6 @@ status_t AudioFlinger::EffectModule::configure() ALOGV("configure() %p thread %p buffer %p framecount %d", this, thread.get(), mConfig.inputCfg.buffer.raw, mConfig.inputCfg.buffer.frameCount); - status_t cmdStatus; size = sizeof(int); status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_SET_CONFIG, @@ -434,7 +434,7 @@ status_t AudioFlinger::EffectModule::init() if (mEffectInterface == NULL) { return NO_INIT; } - status_t cmdStatus; + status_t cmdStatus = 0; uint32_t size = sizeof(status_t); status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_INIT, @@ -476,7 +476,7 @@ status_t AudioFlinger::EffectModule::start_l() if (mStatus != NO_ERROR) { return mStatus; } - status_t cmdStatus; + status_t cmdStatus = 0; uint32_t size = sizeof(status_t); status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_ENABLE, @@ -677,7 +677,7 @@ status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right, if (isProcessEnabled() && ((mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_CTRL || (mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_IND)) { - status_t cmdStatus; + status_t cmdStatus = 0; uint32_t volume[2]; uint32_t *pVolume = NULL; uint32_t size = sizeof(volume); @@ -712,7 +712,7 @@ status_t AudioFlinger::EffectModule::setDevice(audio_devices_t device) } status_t status = NO_ERROR; if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) { - status_t cmdStatus; + status_t cmdStatus = 0; uint32_t size = sizeof(status_t); uint32_t cmd = audio_is_output_devices(device) ? EFFECT_CMD_SET_DEVICE : EFFECT_CMD_SET_INPUT_DEVICE; @@ -734,7 +734,7 @@ status_t AudioFlinger::EffectModule::setMode(audio_mode_t mode) } status_t status = NO_ERROR; if ((mDescriptor.flags & EFFECT_FLAG_AUDIO_MODE_MASK) == EFFECT_FLAG_AUDIO_MODE_IND) { - status_t cmdStatus; + status_t cmdStatus = 0; uint32_t size = sizeof(status_t); status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_SET_AUDIO_MODE, @@ -1113,13 +1113,15 @@ status_t AudioFlinger::EffectHandle::enable() mEnabled = false; } else { if (thread != 0) { - if (thread->type() == ThreadBase::OFFLOAD) { + if ((thread->type() == ThreadBase::OFFLOAD) || + (thread->type() == ThreadBase::DIRECT && thread->mIsDirectPcm)) { PlaybackThread *t = (PlaybackThread *)thread.get(); Mutex::Autolock _l(t->mLock); t->broadcast_l(); } if (!mEffect->isOffloadable()) { - if (thread->type() == ThreadBase::OFFLOAD) { + if (thread->type() == ThreadBase::OFFLOAD || + (thread->type() == ThreadBase::DIRECT && thread->mIsDirectPcm)) { PlaybackThread *t = (PlaybackThread *)thread.get(); t->invalidateTracks(AUDIO_STREAM_MUSIC); } @@ -1156,7 +1158,8 @@ status_t AudioFlinger::EffectHandle::disable() sp<ThreadBase> thread = mEffect->thread().promote(); if (thread != 0) { thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId()); - if (thread->type() == ThreadBase::OFFLOAD) { + if ((thread->type() == ThreadBase::OFFLOAD) || + (thread->type() == ThreadBase::DIRECT && thread->mIsDirectPcm)){ PlaybackThread *t = (PlaybackThread *)thread.get(); Mutex::Autolock _l(t->mLock); t->broadcast_l(); @@ -1439,8 +1442,10 @@ void AudioFlinger::EffectChain::process_l() (mSessionId == AUDIO_SESSION_OUTPUT_STAGE); // never process effects when: // - on an OFFLOAD thread + // - on DIRECT thread with directPcm flag enabled // - no more tracks are on the session and the effect tail has been rendered - bool doProcess = (thread->type() != ThreadBase::OFFLOAD); + bool doProcess = ((thread->type() != ThreadBase::OFFLOAD) && + (!(thread->type() == ThreadBase::DIRECT && thread->mIsDirectPcm))); if (!isGlobalSession) { bool tracksOnSession = (trackCnt() != 0); diff --git a/services/audioflinger/FastCapture.cpp b/services/audioflinger/FastCapture.cpp index 1bba5f6..7c8a25f 100644 --- a/services/audioflinger/FastCapture.cpp +++ b/services/audioflinger/FastCapture.cpp @@ -25,6 +25,7 @@ #include <media/AudioBufferProvider.h> #include <utils/Log.h> #include <utils/Trace.h> +#include "AudioFlinger.h" #include "FastCapture.h" namespace android { @@ -105,7 +106,7 @@ void FastCapture::onStateChange() mFormat = mInputSource->format(); mSampleRate = Format_sampleRate(mFormat); unsigned channelCount = Format_channelCount(mFormat); - ALOG_ASSERT(channelCount >= 1 && channelCount <= FCC_8); + ALOG_ASSERT(channelCount >= 1 && channelCount <= 8); } dumpState->mSampleRate = mSampleRate; eitherChanged = true; diff --git a/services/audioflinger/FastCaptureDumpState.cpp b/services/audioflinger/FastCaptureDumpState.cpp index 53eeba5..de4a6db 100644 --- a/services/audioflinger/FastCaptureDumpState.cpp +++ b/services/audioflinger/FastCaptureDumpState.cpp @@ -15,7 +15,7 @@ */ #define LOG_TAG "FastCaptureDumpState" -//define LOG_NDEBUG 0 +//#define LOG_NDEBUG 0 #include "Configuration.h" #include <utils/Log.h> diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp index 45c68b5..2bc8066 100644 --- a/services/audioflinger/FastMixer.cpp +++ b/services/audioflinger/FastMixer.cpp @@ -334,6 +334,11 @@ void FastMixer::onWork() if ((command & FastMixerState::MIX) && (mMixer != NULL) && mIsWarm) { ALOG_ASSERT(mMixerBuffer != NULL); + + // AudioMixer::mState.enabledTracks is undefined if mState.hook == process__validate, + // so we keep a side copy of enabledTracks + bool anyEnabledTracks = false; + // for each track, update volume and check for underrun unsigned currentTrackMask = current->mTrackMask; while (currentTrackMask != 0) { @@ -392,11 +397,13 @@ void FastMixer::onWork() underruns.mBitFields.mPartial++; underruns.mBitFields.mMostRecent = UNDERRUN_PARTIAL; mMixer->enable(name); + anyEnabledTracks = true; } } else { underruns.mBitFields.mFull++; underruns.mBitFields.mMostRecent = UNDERRUN_FULL; mMixer->enable(name); + anyEnabledTracks = true; } ftDump->mUnderruns = underruns; ftDump->mFramesReady = framesReady; @@ -407,9 +414,14 @@ void FastMixer::onWork() pts = AudioBufferProvider::kInvalidPTS; } - // process() is CPU-bound - mMixer->process(pts); - mMixerBufferState = MIXED; + if (anyEnabledTracks) { + // process() is CPU-bound + mMixer->process(pts); + mMixerBufferState = MIXED; + } else if (mMixerBufferState != ZEROED) { + mMixerBufferState = UNDEFINED; + } + } else if (mMixerBufferState == MIXED) { mMixerBufferState = UNDEFINED; } diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 71fc498..e1e4980 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) { @@ -1589,6 +1630,7 @@ void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& dprintf(fd, " Mixer buffer: %p\n", mMixerBuffer); dprintf(fd, " Effect buffer: %p\n", mEffectBuffer); dprintf(fd, " Fast track availMask=%#x\n", mFastTrackAvailMask); + dprintf(fd, " Standby delay ns=%lld\n", (long long)mStandbyDelayNs); AudioStreamOut *output = mOutput; audio_output_flags_t flags = output != NULL ? output->flags : AUDIO_OUTPUT_FLAG_NONE; String8 flagsAsString = outputFlagsToString(flags); @@ -2166,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; @@ -2181,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; @@ -2513,7 +2543,8 @@ The derived values that are cached: - mSinkBufferSize from frame count * frame size - mActiveSleepTimeUs from activeSleepTimeUs() - mIdleSleepTimeUs from idleSleepTimeUs() - - mStandbyDelayNs from mActiveSleepTimeUs (DIRECT only) + - mStandbyDelayNs from mActiveSleepTimeUs (DIRECT only) or forced to at least + kDefaultStandbyTimeInNsecs when connected to an A2DP device. - maxPeriod from frame count and sample rate (MIXER only) The parameters that affect these derived values are: @@ -2532,6 +2563,15 @@ void AudioFlinger::PlaybackThread::cacheParameters_l() mSinkBufferSize = mNormalFrameCount * mFrameSize; mActiveSleepTimeUs = activeSleepTimeUs(); mIdleSleepTimeUs = idleSleepTimeUs(); + + // make sure standby delay is not too short when connected to an A2DP sink to avoid + // truncating audio when going to standby. + mStandbyDelayNs = AudioFlinger::mStandbyTimeInNsecs; + if ((mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != 0) { + if (mStandbyDelayNs < kDefaultStandbyTimeInNsecs) { + mStandbyDelayNs = kDefaultStandbyTimeInNsecs; + } + } } void AudioFlinger::PlaybackThread::invalidateTracks(audio_stream_type_t streamType) @@ -2720,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, @@ -2895,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(); } @@ -2905,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. @@ -2928,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) { @@ -2971,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, @@ -3023,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++; @@ -3117,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 @@ -3300,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; @@ -4248,6 +4330,7 @@ bool AudioFlinger::MixerThread::checkForNewParameter_l(const String8& keyValuePa status_t& status) { bool reconfig = false; + bool a2dpDeviceChanged = false; status = NO_ERROR; @@ -4268,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; } @@ -4324,6 +4410,8 @@ bool AudioFlinger::MixerThread::checkForNewParameter_l(const String8& keyValuePa // forward device change to effects that have requested to be // aware of attached audio device. if (value != AUDIO_DEVICE_NONE) { + a2dpDeviceChanged = + (mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != (value & AUDIO_DEVICE_OUT_ALL_A2DP); mOutDevice = value; for (size_t i = 0; i < mEffectChains.size(); i++) { mEffectChains[i]->setDevice_l(mOutDevice); @@ -4367,7 +4455,7 @@ bool AudioFlinger::MixerThread::checkForNewParameter_l(const String8& keyValuePa sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED); } - return reconfig; + return reconfig || a2dpDeviceChanged; } @@ -4775,6 +4863,10 @@ bool AudioFlinger::DirectOutputThread::shouldStandby_l() bool trackPaused = false; bool trackStopped = false; + if ((mType == DIRECT) && audio_is_linear_pcm(mFormat) && !usesHwAvSync()) { + return !mStandby; + } + // do not put the HAL in standby when paused. AwesomePlayer clear the offloaded AudioTrack // after a timeout and we will enter standby then. if (mTracks.size() > 0) { @@ -4803,15 +4895,19 @@ bool AudioFlinger::DirectOutputThread::checkForNewParameter_l(const String8& key status_t& status) { bool reconfig = false; + bool a2dpDeviceChanged = false; status = NO_ERROR; 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. if (value != AUDIO_DEVICE_NONE) { + a2dpDeviceChanged = + (mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != (value & AUDIO_DEVICE_OUT_ALL_A2DP); mOutDevice = value; for (size_t i = 0; i < mEffectChains.size(); i++) { mEffectChains[i]->setDevice_l(mOutDevice); @@ -4844,7 +4940,7 @@ bool AudioFlinger::DirectOutputThread::checkForNewParameter_l(const String8& key } } - return reconfig; + return reconfig || a2dpDeviceChanged; } uint32_t AudioFlinger::DirectOutputThread::activeSleepTimeUs() const @@ -4891,6 +4987,8 @@ void AudioFlinger::DirectOutputThread::cacheParameters_l() mStandbyDelayNs = 0; } else if ((mType == OFFLOAD) && !audio_is_linear_pcm(mFormat)) { mStandbyDelayNs = kOffloadStandbyDelayNs; + } else if (mType == DIRECT && mIsDirectPcm) { + mStandbyDelayNs = kOffloadStandbyDelayNs; } else { mStandbyDelayNs = microseconds(mActiveSleepTimeUs*2); } @@ -5295,6 +5393,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); } @@ -5316,7 +5416,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; @@ -6556,7 +6660,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; @@ -6576,7 +6684,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; } @@ -6677,6 +6789,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) { @@ -6750,6 +6912,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) diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index 46ac300..48ff77d 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -13,6 +13,24 @@ ** 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. */ #ifndef INCLUDING_FROM_AUDIOFLINGER_H @@ -457,6 +475,7 @@ protected: static const size_t kLogSize = 4 * 1024; sp<NBLog::Writer> mNBLogWriter; bool mSystemReady; + bool mIsDirectPcm; // flag to indicate unique Direct thread }; // --- PlaybackThread --- @@ -536,7 +555,7 @@ public: void setMasterVolume(float value); void setMasterMute(bool muted); - + void setPostPro(); void setStreamVolume(audio_stream_type_t stream, float value); void setStreamMute(audio_stream_type_t stream, bool muted); @@ -1159,11 +1178,16 @@ public: } private: +#ifdef LEGACY_ALSA_AUDIO + // internal convert function for format and channel mask. + void convert(void *dst, /*const*/ void *src, size_t frames); +#else // format conversion when not using resampler void convertNoResampler(void *dst, const void *src, size_t frames); // format conversion when using resampler; modifies src in-place void convertResampler(void *dst, /*not-a-const*/ void *src, size_t frames); +#endif // user provided information audio_channel_mask_t mSrcChannelMask; diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index 0e24b52..f3b5375 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -24,6 +24,7 @@ #include <math.h> #include <sys/syscall.h> #include <utils/Log.h> +#include <media/stagefright/foundation/ADebug.h> #include <private/media/AudioTrackShared.h> @@ -706,10 +707,11 @@ status_t AudioFlinger::PlaybackThread::Track::start(AudioSystem::sync_event_t ev mState = state; } } - // track was already in the active list, not a problem - if (status == ALREADY_EXISTS) { - status = NO_ERROR; - } else { + // If track was already in the active list, not a problem unless + // track is fast and sharedBuffer is used and frameReady has already become 0. + // In such case we need to call obtainbuffer() to refresh the framesReady value. + if ((status != ALREADY_EXISTS) || + (isFastTrack() && (mSharedBuffer != 0) && (framesReady() == 0))) { // Acknowledge any pending flush(), so that subsequent new data isn't discarded. // It is usually unsafe to access the server proxy from a binder thread. // But in this case we know the mixer thread (whether normal mixer or fast mixer) @@ -720,6 +722,9 @@ status_t AudioFlinger::PlaybackThread::Track::start(AudioSystem::sync_event_t ev buffer.mFrameCount = 1; (void) mAudioTrackServerProxy->obtainBuffer(&buffer, true /*ackFlush*/); } + + if (status == ALREADY_EXISTS) + status = NO_ERROR; } else { status = BAD_VALUE; } @@ -1775,6 +1780,7 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t frame if (mBufferQueue.size() < kMaxOverFlowBuffers) { pInBuffer = new Buffer; pInBuffer->mBuffer = malloc(inBuffer.frameCount * mFrameSize); + CHECK(pInBuffer->mBuffer != NULL); pInBuffer->frameCount = inBuffer.frameCount; pInBuffer->raw = pInBuffer->mBuffer; memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * mFrameSize); |