diff options
Diffstat (limited to 'services')
49 files changed, 1330 insertions, 136 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 eb52dee..e57aab1 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, @@ -683,7 +683,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); @@ -718,7 +718,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; @@ -740,7 +740,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, @@ -1119,13 +1119,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); } @@ -1162,7 +1164,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(); @@ -1445,8 +1448,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/ServiceUtilities.cpp b/services/audioflinger/ServiceUtilities.cpp index 2e68dad..031ff05 100644 --- a/services/audioflinger/ServiceUtilities.cpp +++ b/services/audioflinger/ServiceUtilities.cpp @@ -106,6 +106,14 @@ bool captureAudioOutputAllowed() { return ok; } +bool accessFmRadioAllowed() { + static const String16 sAccessFmRadio("android.permission.ACCESS_FM_RADIO"); + // IMPORTANT: Use PermissionCache - not a runtime permission and may not change. + bool ok = PermissionCache::checkCallingPermission(sAccessFmRadio); + if (!ok) ALOGE("Request requires android.permission.ACCESS_FM_RADIO"); + return ok; +} + bool captureHotwordAllowed() { static const String16 sCaptureHotwordAllowed("android.permission.CAPTURE_AUDIO_HOTWORD"); // IMPORTANT: Use PermissionCache - not a runtime permission and may not change. diff --git a/services/audioflinger/ServiceUtilities.h b/services/audioflinger/ServiceUtilities.h index fba6dce..dffb114 100644 --- a/services/audioflinger/ServiceUtilities.h +++ b/services/audioflinger/ServiceUtilities.h @@ -21,6 +21,7 @@ namespace android { extern pid_t getpid_cached; bool recordingAllowed(const String16& opPackageName); +bool accessFmRadioAllowed(); bool captureAudioOutputAllowed(); bool captureHotwordAllowed(); bool settingsAllowed(); 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); diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk index 5b38e1c..69fc0e8 100644 --- a/services/audiopolicy/Android.mk +++ b/services/audiopolicy/Android.mk @@ -40,6 +40,10 @@ LOCAL_SHARED_LIBRARIES += \ libaudiopolicymanager endif +ifeq ($(BOARD_HAVE_PRE_KITKAT_AUDIO_POLICY_BLOB),true) + LOCAL_CFLAGS += -DHAVE_PRE_KITKAT_AUDIO_POLICY_BLOB +endif + LOCAL_STATIC_LIBRARIES := \ libmedia_helper \ libaudiopolicycomponents diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h index c1e7bc0..93e6266 100644 --- a/services/audiopolicy/AudioPolicyInterface.h +++ b/services/audiopolicy/AudioPolicyInterface.h @@ -331,6 +331,9 @@ public: virtual audio_unique_id_t newAudioUniqueId() = 0; virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state) = 0; + + virtual void onOutputSessionEffectsUpdate(sp<AudioSessionInfo>& streamInfo, bool added) = 0; + }; extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface); diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk index 8728ff3..5ef9b38 100644 --- a/services/audiopolicy/common/managerdefinitions/Android.mk +++ b/services/audiopolicy/common/managerdefinitions/Android.mk @@ -31,6 +31,25 @@ LOCAL_C_INCLUDES += \ LOCAL_EXPORT_C_INCLUDE_DIRS := \ $(LOCAL_PATH)/include +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_FLAC_OFFLOAD)),true) +LOCAL_CFLAGS += -DFLAC_OFFLOAD_ENABLED +endif +ifneq ($(strip $(AUDIO_FEATURE_ENABLED_PROXY_DEVICE)),false) +LOCAL_CFLAGS += -DAUDIO_EXTN_AFE_PROXY_ENABLED +endif +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_WMA_OFFLOAD)),true) +LOCAL_CFLAGS += -DWMA_OFFLOAD_ENABLED +endif +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_ALAC_OFFLOAD)),true) +LOCAL_CFLAGS += -DALAC_OFFLOAD_ENABLED +endif +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_APE_OFFLOAD)),true) +LOCAL_CFLAGS += -DAPE_OFFLOAD_ENABLED +endif +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_AAC_ADTS_OFFLOAD)),true) +LOCAL_CFLAGS += -DAAC_ADTS_OFFLOAD_ENABLED +endif + LOCAL_MODULE := libaudiopolicycomponents include $(BUILD_STATIC_LIBRARY) diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h index 50f622d..e1c2999 100644 --- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h +++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h @@ -72,6 +72,7 @@ public: sp<AudioPort> mPort; audio_devices_t mDevice; // current device this output is routed to audio_patch_handle_t mPatchHandle; + audio_io_handle_t mIoHandle; // output handle uint32_t mRefCount[AUDIO_STREAM_CNT]; // number of streams of each type using this output nsecs_t mStopTime[AUDIO_STREAM_CNT]; float mCurVolume[AUDIO_STREAM_CNT]; // current stream volume in dB @@ -116,7 +117,6 @@ public: virtual void toAudioPort(struct audio_port *port) const; const sp<IOProfile> mProfile; // I/O profile this output derives from - audio_io_handle_t mIoHandle; // output handle uint32_t mLatency; // audio_output_flags_t mFlags; // AudioMix *mPolicyMix; // non NULL when used by a dynamic policy diff --git a/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h index 78d2cdf..6f80435 100644 --- a/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h +++ b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h @@ -74,6 +74,9 @@ const StringToEnum sDeviceTypeToEnumTable[] = { STRING_TO_ENUM(AUDIO_DEVICE_OUT_FM), STRING_TO_ENUM(AUDIO_DEVICE_OUT_AUX_LINE), STRING_TO_ENUM(AUDIO_DEVICE_OUT_IP), +#ifdef AUDIO_EXTN_AFE_PROXY_ENABLED + STRING_TO_ENUM(AUDIO_DEVICE_OUT_PROXY), +#endif STRING_TO_ENUM(AUDIO_DEVICE_IN_AMBIENT), STRING_TO_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC), STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET), @@ -96,6 +99,9 @@ const StringToEnum sDeviceTypeToEnumTable[] = { STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_A2DP), STRING_TO_ENUM(AUDIO_DEVICE_IN_LOOPBACK), STRING_TO_ENUM(AUDIO_DEVICE_IN_IP), +#ifdef LEGACY_ALSA_AUDIO + STRING_TO_ENUM(AUDIO_DEVICE_IN_COMMUNICATION), +#endif }; const StringToEnum sDeviceNameToEnumTable[] = { @@ -153,6 +159,7 @@ const StringToEnum sDeviceNameToEnumTable[] = { const StringToEnum sOutputFlagNameToEnumTable[] = { STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT), + STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT_PCM), STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY), STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_FAST), STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER), @@ -162,6 +169,7 @@ const StringToEnum sOutputFlagNameToEnumTable[] = { STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_TTS), STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_RAW), STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_SYNC), + STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_VOIP_RX), }; const StringToEnum sInputFlagNameToEnumTable[] = { @@ -198,6 +206,33 @@ const StringToEnum sFormatNameToEnumTable[] = { STRING_TO_ENUM(AUDIO_FORMAT_E_AC3), STRING_TO_ENUM(AUDIO_FORMAT_DTS), STRING_TO_ENUM(AUDIO_FORMAT_DTS_HD), +#ifdef FLAC_OFFLOAD_ENABLED + STRING_TO_ENUM(AUDIO_FORMAT_FLAC), +#endif +#ifdef WMA_OFFLOAD_ENABLED + STRING_TO_ENUM(AUDIO_FORMAT_WMA), + STRING_TO_ENUM(AUDIO_FORMAT_WMA_PRO), +#endif + STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT_OFFLOAD), + STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_OFFLOAD), +#ifdef ALAC_OFFLOAD_ENABLED + STRING_TO_ENUM(AUDIO_FORMAT_ALAC), +#endif +#ifdef APE_OFFLOAD_ENABLED + STRING_TO_ENUM(AUDIO_FORMAT_APE), +#endif +#ifdef AAC_ADTS_OFFLOAD_ENABLED + STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_MAIN), + STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_LC), + STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_SSR), + STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_LTP), + STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_HE_V1), + STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_SCALABLE), + STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_ERLC), + STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_LD), + STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_HE_V2), + STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_ELD), +#endif }; const StringToEnum sOutChannelsNameToEnumTable[] = { @@ -206,12 +241,22 @@ const StringToEnum sOutChannelsNameToEnumTable[] = { STRING_TO_ENUM(AUDIO_CHANNEL_OUT_QUAD), STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1), STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1), + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_2POINT1), + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_SURROUND), + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_PENTA), + STRING_TO_ENUM(AUDIO_CHANNEL_OUT_6POINT1), }; const StringToEnum sInChannelsNameToEnumTable[] = { STRING_TO_ENUM(AUDIO_CHANNEL_IN_MONO), STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO), STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK), + STRING_TO_ENUM(AUDIO_CHANNEL_IN_5POINT1), +#ifdef LEGACY_ALSA_AUDIO + STRING_TO_ENUM(AUDIO_CHANNEL_IN_VOICE_CALL_MONO), + STRING_TO_ENUM(AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO), + STRING_TO_ENUM(AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO), +#endif }; const StringToEnum sIndexChannelsNameToEnumTable[] = { diff --git a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h index c9783a1..396541b 100644 --- a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h +++ b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h @@ -21,6 +21,7 @@ #include <utils/KeyedVector.h> #include <utils/RefBase.h> #include <utils/Errors.h> +#include <utils/Thread.h> namespace android { @@ -66,6 +67,8 @@ private: * Maximum memory allocated to audio effects in KB */ static const uint32_t MAX_EFFECTS_MEMORY = 512; + + Mutex mLock; }; }; // namespace android diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp index a278375..cefbe79 100644 --- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp @@ -33,7 +33,7 @@ namespace android { AudioOutputDescriptor::AudioOutputDescriptor(const sp<AudioPort>& port, AudioPolicyClientInterface *clientInterface) - : mPort(port), mDevice(AUDIO_DEVICE_NONE), + : mPort(port), mDevice(AUDIO_DEVICE_NONE), mIoHandle(0), mPatchHandle(0), mClientInterface(clientInterface), mId(0) { // clear usage count for all stream types @@ -223,7 +223,7 @@ void AudioOutputDescriptor::log(const char* indent) SwAudioOutputDescriptor::SwAudioOutputDescriptor( const sp<IOProfile>& profile, AudioPolicyClientInterface *clientInterface) : AudioOutputDescriptor(profile, clientInterface), - mProfile(profile), mIoHandle(0), mLatency(0), + mProfile(profile), mLatency(0), mFlags((audio_output_flags_t)0), mPolicyMix(NULL), mOutput1(0), mOutput2(0), mDirectOpenCount(0), mGlobalRefCount(0) { @@ -428,7 +428,11 @@ audio_io_handle_t SwAudioOutputCollection::getA2dpOutput() const return this->keyAt(i); } } +#ifdef LEGACY_ALSA_AUDIO + return 1; +#else return 0; +#endif } sp<SwAudioOutputDescriptor> SwAudioOutputCollection::getPrimaryOutput() const diff --git a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp index 33d838d..6a0d079 100644 --- a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp @@ -56,6 +56,7 @@ status_t EffectDescriptorCollection::registerEffect(const effect_descriptor_t *d int session, int id) { + Mutex::Autolock _l(mLock); if (mTotalEffectsMemory + desc->memoryUsage > getMaxEffectsMemory()) { ALOGW("registerEffect() memory limit exceeded for Fx %s, Memory %d KB", desc->name, desc->memoryUsage); @@ -80,6 +81,7 @@ status_t EffectDescriptorCollection::registerEffect(const effect_descriptor_t *d status_t EffectDescriptorCollection::unregisterEffect(int id) { + Mutex::Autolock _l(mLock); ssize_t index = indexOfKey(id); if (index < 0) { ALOGW("unregisterEffect() unknown effect ID %d", id); @@ -106,6 +108,7 @@ status_t EffectDescriptorCollection::unregisterEffect(int id) status_t EffectDescriptorCollection::setEffectEnabled(int id, bool enabled) { + Mutex::Autolock _l(mLock); ssize_t index = indexOfKey(id); if (index < 0) { ALOGW("unregisterEffect() unknown effect ID %d", id); @@ -148,6 +151,7 @@ status_t EffectDescriptorCollection::setEffectEnabled(const sp<EffectDescriptor> bool EffectDescriptorCollection::isNonOffloadableEffectEnabled() { + Mutex::Autolock _l(mLock); for (size_t i = 0; i < size(); i++) { sp<EffectDescriptor> effectDesc = valueAt(i); if (effectDesc->mEnabled && (effectDesc->mStrategy == STRATEGY_MEDIA) && @@ -172,6 +176,7 @@ uint32_t EffectDescriptorCollection::getMaxEffectsMemory() const status_t EffectDescriptorCollection::dump(int fd) { + Mutex::Autolock _l(mLock); const size_t SIZE = 256; char buffer[SIZE]; diff --git a/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp index b682e2c..4ca27c2 100644 --- a/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp @@ -35,7 +35,10 @@ namespace android { StreamDescriptor::StreamDescriptor() : mIndexMin(0), mIndexMax(1), mCanBeMuted(true) { - mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT, 0); + // Initialize the current stream's index to mIndexMax so volume isn't 0 in + // cases where the Java layer doesn't call into the audio policy service to + // set the default volume. + mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT, mIndexMax); } int StreamDescriptor::getVolumeIndex(audio_devices_t device) const diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/Android.mk index c402fd5..be86231 100644 --- a/services/audiopolicy/engineconfigurable/parameter-framework/Android.mk +++ b/services/audiopolicy/engineconfigurable/parameter-framework/Android.mk @@ -4,4 +4,4 @@ LOCAL_PATH := $(call my-dir) # Recursive call sub-folder Android.mk ####################################################################### -include $(call all-makefiles-under,$(LOCAL_PATH)) +include $(LOCAL_PATH)/plugin/Android.mk diff --git a/services/audiopolicy/engineconfigurable/src/Stream.cpp b/services/audiopolicy/engineconfigurable/src/Stream.cpp index bea2c19..a929435 100755 --- a/services/audiopolicy/engineconfigurable/src/Stream.cpp +++ b/services/audiopolicy/engineconfigurable/src/Stream.cpp @@ -98,13 +98,13 @@ float Element<audio_stream_type_t>::volIndexToDb(Volume::device_category deviceC if (it == mVolumeProfiles.end()) { ALOGE("%s: device category %d not found for stream %s", __FUNCTION__, deviceCategory, getName().c_str()); - return 1.0f; + return 0.0f; } const VolumeCurvePoints curve = mVolumeProfiles[deviceCategory]; if (curve.size() != Volume::VOLCNT) { ALOGE("%s: invalid profile for category %d and for stream %s", __FUNCTION__, deviceCategory, getName().c_str()); - return 1.0f; + return 0.0f; } // the volume index in the UI is relative to the min and max volume indices for this stream type @@ -113,7 +113,7 @@ float Element<audio_stream_type_t>::volIndexToDb(Volume::device_category deviceC if (mIndexMax - mIndexMin == 0) { ALOGE("%s: Invalid volume indexes Min=Max=%d", __FUNCTION__, mIndexMin); - return 1.0f; + return 0.0f; } int volIdx = (nbSteps * (indexInUi - mIndexMin)) / (mIndexMax - mIndexMin); @@ -121,7 +121,7 @@ float Element<audio_stream_type_t>::volIndexToDb(Volume::device_category deviceC // find what part of the curve this index volume belongs to, or if it's out of bounds int segment = 0; if (volIdx < curve[Volume::VOLMIN].mIndex) { // out of bounds - return 0.0f; + return VOLUME_MIN_DB; } else if (volIdx < curve[Volume::VOLKNEE1].mIndex) { segment = 0; } else if (volIdx < curve[Volume::VOLKNEE2].mIndex) { @@ -129,7 +129,7 @@ float Element<audio_stream_type_t>::volIndexToDb(Volume::device_category deviceC } else if (volIdx <= curve[Volume::VOLMAX].mIndex) { segment = 2; } else { // out of bounds - return 1.0f; + return 0.0f; } // linear interpolation in the attenuation table in dB diff --git a/services/audiopolicy/enginedefault/Android.mk b/services/audiopolicy/enginedefault/Android.mk index 8d43b89..f6ffa2a 100755 --- a/services/audiopolicy/enginedefault/Android.mk +++ b/services/audiopolicy/enginedefault/Android.mk @@ -31,6 +31,11 @@ LOCAL_C_INCLUDES := \ $(call include-path-for, bionic) \ $(TOPDIR)frameworks/av/services/audiopolicy/common/include +ifeq ($(call is-vendor-board-platform,QCOM),true) +ifneq ($(strip $(AUDIO_FEATURE_ENABLED_PROXY_DEVICE)),false) +LOCAL_CFLAGS += -DAUDIO_EXTN_AFE_PROXY_ENABLED +endif +endif LOCAL_MODULE := libaudiopolicyenginedefault LOCAL_MODULE_TAGS := optional diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp index 0686414..627e1d3 100755 --- a/services/audiopolicy/enginedefault/src/Engine.cpp +++ b/services/audiopolicy/enginedefault/src/Engine.cpp @@ -355,7 +355,11 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const // - cannot route from voice call RX OR // - audio HAL version is < 3.0 and TX device is on the primary HW module if (getPhoneState() == AUDIO_MODE_IN_CALL) { +#ifdef LEGACY_ALSA_AUDIO + audio_devices_t txDevice = getDeviceForInputSource(AUDIO_SOURCE_VOICE_CALL); +#else audio_devices_t txDevice = getDeviceForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION); +#endif sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput(); audio_devices_t availPrimaryInputDevices = availableInputDevices.getDevicesFromHwModule(primaryOutput->getModuleHandle()); @@ -408,9 +412,10 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const if (device) break; device = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL; if (device) break; - device = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; - if (device) break; } + // Allow voice call on USB ANLG DOCK headset + device = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; + if (device) break; device = availableOutputDevicesType & AUDIO_DEVICE_OUT_EARPIECE; if (device) break; device = mApmObserver->getDefaultOutputDevice()->type(); @@ -450,6 +455,13 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const } break; } + + if (isInCall() && (device == AUDIO_DEVICE_NONE)) { + // when in call, get the device for Phone strategy + device = getDeviceForStrategy(STRATEGY_PHONE); + break; + } + break; case STRATEGY_SONIFICATION: @@ -498,6 +510,13 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const case STRATEGY_REROUTING: case STRATEGY_MEDIA: { uint32_t device2 = AUDIO_DEVICE_NONE; + + if (isInCall() && (device == AUDIO_DEVICE_NONE)) { + // when in call, get the device for Phone strategy + device = getDeviceForStrategy(STRATEGY_PHONE); + break; + } + if (strategy != STRATEGY_SONIFICATION) { // no sonification on remote submix (e.g. WFD) if (availableOutputDevices.getDevice(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, String8("0")) != 0) { @@ -541,14 +560,23 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const if (device2 == AUDIO_DEVICE_NONE) { device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; } - if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) { + if ((strategy != STRATEGY_SONIFICATION) && (device == AUDIO_DEVICE_NONE) + && (device2 == AUDIO_DEVICE_NONE)) { // no sonification on aux digital (e.g. HDMI) device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL; } if ((device2 == AUDIO_DEVICE_NONE) && - (mForceUse[AUDIO_POLICY_FORCE_FOR_DOCK] == AUDIO_POLICY_FORCE_ANALOG_DOCK)) { + (mForceUse[AUDIO_POLICY_FORCE_FOR_DOCK] == AUDIO_POLICY_FORCE_ANALOG_DOCK) + && (strategy != STRATEGY_SONIFICATION)) { device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; } +#ifdef AUDIO_EXTN_AFE_PROXY_ENABLED + if ((strategy != STRATEGY_SONIFICATION) && (device == AUDIO_DEVICE_NONE) + && (device2 == AUDIO_DEVICE_NONE)) { + // no sonification on WFD sink + device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_PROXY; + } +#endif if (device2 == AUDIO_DEVICE_NONE) { device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER; } @@ -591,9 +619,11 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const audio_devices_t Engine::getDeviceForInputSource(audio_source_t inputSource) const { - const DeviceVector &availableOutputDevices = mApmObserver->getAvailableOutputDevices(); const DeviceVector &availableInputDevices = mApmObserver->getAvailableInputDevices(); +#ifndef LEGACY_ALSA_AUDIO + const DeviceVector &availableOutputDevices = mApmObserver->getAvailableOutputDevices(); const SwAudioOutputCollection &outputs = mApmObserver->getOutputs(); +#endif audio_devices_t availableDeviceTypes = availableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN; uint32_t device = AUDIO_DEVICE_NONE; @@ -623,6 +653,9 @@ audio_devices_t Engine::getDeviceForInputSource(audio_source_t inputSource) cons break; case AUDIO_SOURCE_VOICE_COMMUNICATION: +#ifdef LEGACY_ALSA_AUDIO + device = AUDIO_DEVICE_IN_COMMUNICATION; +#else // Allow only use of devices on primary input if in call and HAL does not support routing // to voice call path. if ((getPhoneState() == AUDIO_MODE_IN_CALL) && @@ -660,6 +693,7 @@ audio_devices_t Engine::getDeviceForInputSource(audio_source_t inputSource) cons } break; } +#endif break; case AUDIO_SOURCE_VOICE_RECOGNITION: @@ -671,6 +705,8 @@ audio_devices_t Engine::getDeviceForInputSource(audio_source_t inputSource) cons device = AUDIO_DEVICE_IN_WIRED_HEADSET; } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) { device = AUDIO_DEVICE_IN_USB_DEVICE; + } else if (availableDeviceTypes & AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET) { + device = AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET; } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) { device = AUDIO_DEVICE_IN_BUILTIN_MIC; } diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index 5ff1c0b..13499ae 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -351,6 +351,14 @@ void AudioPolicyManager::updateCallRouting(audio_devices_t rxDevice, int delayMs AUDIO_OUTPUT_FLAG_NONE, AUDIO_FORMAT_INVALID); if (output != AUDIO_IO_HANDLE_NONE) { + // close active input (if any) before opening new input + audio_io_handle_t activeInput = mInputs.getActiveInput(); + if (activeInput != 0) { + ALOGV("updateCallRouting() close active input before opening new input"); + sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput); + stopInput(activeInput, activeDesc->mSessions.itemAt(0)); + releaseInput(activeInput, activeDesc->mSessions.itemAt(0)); + } sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output); ALOG_ASSERT(!outputDesc->isDuplicated(), "updateCallRouting() RX device output is duplicated"); @@ -608,7 +616,8 @@ sp<IOProfile> AudioPolicyManager::getProfileForDirectOutput( // only retain flags that will drive the direct output profile selection // if explicitly requested static const uint32_t kRelevantFlags = - (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD); + (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | + AUDIO_OUTPUT_FLAG_VOIP_RX); flags = (audio_output_flags_t)((flags & kRelevantFlags) | AUDIO_OUTPUT_FLAG_DIRECT); @@ -1356,6 +1365,12 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, ALOGW("getInputForAttr() could not find device for source %d", inputSource); return BAD_VALUE; } + // block request to open input on USB during voice call + if((AUDIO_MODE_IN_CALL == mEngine->getPhoneState()) && + (device == AUDIO_DEVICE_IN_USB_DEVICE)) { + ALOGV("getInputForAttr(): blocking the request to open input on USB device"); + return BAD_VALUE; + } if (policyMix != NULL) { address = policyMix->mRegistrationId; if (policyMix->mMixType == MIX_TYPE_RECORDERS) { @@ -1376,20 +1391,6 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, } else { *inputType = API_INPUT_LEGACY; } - // adapt channel selection to input source - switch (inputSource) { - case AUDIO_SOURCE_VOICE_UPLINK: - channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK; - break; - case AUDIO_SOURCE_VOICE_DOWNLINK: - channelMask = AUDIO_CHANNEL_IN_VOICE_DNLINK; - break; - case AUDIO_SOURCE_VOICE_CALL: - channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK | AUDIO_CHANNEL_IN_VOICE_DNLINK; - break; - default: - break; - } if (inputSource == AUDIO_SOURCE_HOTWORD) { ssize_t index = mSoundTriggerSessions.indexOfKey(session); if (index >= 0) { @@ -1802,6 +1803,7 @@ audio_io_handle_t AudioPolicyManager::selectOutputForEffects( audio_io_handle_t outputOffloaded = 0; audio_io_handle_t outputDeepBuffer = 0; + audio_io_handle_t outputDirectPcm = 0; for (size_t i = 0; i < outputs.size(); i++) { sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(outputs[i]); @@ -1809,6 +1811,9 @@ audio_io_handle_t AudioPolicyManager::selectOutputForEffects( if ((desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) { outputOffloaded = outputs[i]; } + if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) != 0) { + outputDirectPcm = outputs[i]; + } if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) != 0) { outputDeepBuffer = outputs[i]; } @@ -1819,6 +1824,9 @@ audio_io_handle_t AudioPolicyManager::selectOutputForEffects( if (outputOffloaded != 0) { return outputOffloaded; } + if (outputDirectPcm != 0) { + return outputDirectPcm; + } if (outputDeepBuffer != 0) { return outputDeepBuffer; } @@ -3810,7 +3818,7 @@ void AudioPolicyManager::checkOutputForStrategy(routing_strategy strategy) { audio_devices_t oldDevice = getDeviceForStrategy(strategy, true /*fromCache*/); audio_devices_t newDevice = getDeviceForStrategy(strategy, false /*fromCache*/); - SortedVector<audio_io_handle_t> srcOutputs = getOutputsForDevice(oldDevice, mPreviousOutputs); + SortedVector<audio_io_handle_t> srcOutputs = getOutputsForDevice(oldDevice, mOutputs); SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevice(newDevice, mOutputs); // also take into account external policy-related changes: add all outputs which are diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h index bbdf396..c40a435 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.h +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h @@ -350,7 +350,7 @@ protected: // handle special cases for sonification strategy while in call: mute streams or replace by // a special tone in the device used for communication - void handleIncallSonification(audio_stream_type_t stream, bool starting, bool stateChange); + virtual void handleIncallSonification(audio_stream_type_t stream, bool starting, bool stateChange); audio_mode_t getPhoneState(); @@ -397,7 +397,7 @@ protected: // must be called every time a condition that affects the device choice for a given output is // changed: connected device, phone state, force use, output start, output stop.. // see getDeviceForStrategy() for the use of fromCache parameter - audio_devices_t getNewOutputDevice(const sp<AudioOutputDescriptor>& outputDesc, + virtual audio_devices_t getNewOutputDevice(const sp<AudioOutputDescriptor>& outputDesc, bool fromCache); // updates cache of device used by all strategies (mDeviceForStrategy[]) @@ -484,11 +484,11 @@ protected: // if argument "device" is different from AUDIO_DEVICE_NONE, startSource() will force // the re-evaluation of the output device. - status_t startSource(sp<AudioOutputDescriptor> outputDesc, + virtual status_t startSource(sp<AudioOutputDescriptor> outputDesc, audio_stream_type_t stream, audio_devices_t device, uint32_t *delayMs); - status_t stopSource(sp<AudioOutputDescriptor> outputDesc, + virtual status_t stopSource(sp<AudioOutputDescriptor> outputDesc, audio_stream_type_t stream, bool forceDeviceUpdate); @@ -571,7 +571,7 @@ protected: // Audio Policy Engine Interface. AudioPolicyManagerInterface *mEngine; -private: +protected: // updates device caching and output for streams that can influence the // routing of notifications void handleNotificationRoutingForStream(audio_stream_type_t stream); @@ -586,7 +586,7 @@ private: SortedVector<audio_io_handle_t>& outputs /*out*/); uint32_t curAudioPortGeneration() const { return mAudioPortGeneration; } // internal method to return the output handle for the given device and format - audio_io_handle_t getOutputForDevice( + virtual audio_io_handle_t getOutputForDevice( audio_devices_t device, audio_session_t session, audio_stream_type_t stream, @@ -610,7 +610,7 @@ private: AudioMix **policyMix = NULL); // Called by setDeviceConnectionState(). - status_t setDeviceConnectionStateInt(audio_devices_t device, + virtual status_t setDeviceConnectionStateInt(audio_devices_t device, audio_policy_dev_state_t state, const char *device_address, const char *device_name); diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp index 489a9be..82720f4 100644 --- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp @@ -219,6 +219,12 @@ void AudioPolicyService::AudioPolicyClient::onDynamicPolicyMixStateUpdate( mAudioPolicyService->onDynamicPolicyMixStateUpdate(regId, state); } +void AudioPolicyService::AudioPolicyClient::onOutputSessionEffectsUpdate( + sp<AudioSessionInfo>& info, bool added) +{ + mAudioPolicyService->onOutputSessionEffectsUpdate(info, added); +} + audio_unique_id_t AudioPolicyService::AudioPolicyClient::newAudioUniqueId() { return AudioSystem::newAudioUniqueId(); diff --git a/services/audiopolicy/service/AudioPolicyClientImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyClientImplLegacy.cpp index a79f8ae..36c85f1 100644 --- a/services/audiopolicy/service/AudioPolicyClientImplLegacy.cpp +++ b/services/audiopolicy/service/AudioPolicyClientImplLegacy.cpp @@ -125,8 +125,13 @@ audio_io_handle_t aps_open_output_on_module(void *service __unused, audio_output_flags_t flags, const audio_offload_info_t *offloadInfo) { +#ifdef HAVE_PRE_KITKAT_AUDIO_POLICY_BLOB + return open_output(module, pDevices, pSamplingRate, pFormat, pChannelMask, + pLatencyMs, flags, NULL); +#else return open_output(module, pDevices, pSamplingRate, pFormat, pChannelMask, pLatencyMs, flags, offloadInfo); +#endif } audio_io_handle_t aps_open_dup_output(void *service __unused, diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp index 282ddeb..d6fabfe 100644 --- a/services/audiopolicy/service/AudioPolicyEffects.cpp +++ b/services/audiopolicy/service/AudioPolicyEffects.cpp @@ -28,6 +28,7 @@ #include <utils/Vector.h> #include <utils/SortedVector.h> #include <cutils/config_utils.h> +#include "AudioPolicyService.h" #include "AudioPolicyEffects.h" #include "ServiceUtilities.h" @@ -37,10 +38,13 @@ namespace android { // AudioPolicyEffects Implementation // ---------------------------------------------------------------------------- -AudioPolicyEffects::AudioPolicyEffects() +AudioPolicyEffects::AudioPolicyEffects(AudioPolicyService *audioPolicyService) : + mAudioPolicyService(audioPolicyService) { // load automatic audio effect modules - if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) { + if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE2, R_OK) == 0) { + loadAudioEffectConfig(AUDIO_EFFECT_VENDOR_CONFIG_FILE2); + } else if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) { loadAudioEffectConfig(AUDIO_EFFECT_VENDOR_CONFIG_FILE); } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) { loadAudioEffectConfig(AUDIO_EFFECT_DEFAULT_CONFIG_FILE); @@ -224,6 +228,8 @@ status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output, { status_t status = NO_ERROR; + ALOGV("addOutputSessionEffects %d", audioSession); + Mutex::Autolock _l(mLock); // create audio processors according to stream // FIXME: should we have specific post processing settings for internal streams? @@ -231,6 +237,22 @@ status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output, if (stream >= AUDIO_STREAM_PUBLIC_CNT) { stream = AUDIO_STREAM_MUSIC; } + + // send the streaminfo notification only once + ssize_t sidx = mOutputAudioSessionInfo.indexOfKey(audioSession); + if (sidx >= 0) { + // AudioSessionInfo is existing and we just need to increase ref count + sp<AudioSessionInfo> info = mOutputAudioSessionInfo.valueAt(sidx); + info->mRefCount++; + + if (info->mRefCount == 1) { + mAudioPolicyService->onOutputSessionEffectsUpdate(info, true); + } + ALOGV("addOutputSessionEffects(): session info %d refCount=%d", audioSession, info->mRefCount); + } else { + ALOGV("addOutputSessionEffects(): no output stream info found for stream"); + } + ssize_t index = mOutputStreams.indexOfKey(stream); if (index < 0) { ALOGV("addOutputSessionEffects(): no output processing needed for this stream"); @@ -273,6 +295,86 @@ status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output, return status; } +status_t AudioPolicyEffects::releaseOutputAudioSessionInfo(audio_io_handle_t /* output */, + audio_stream_type_t stream, + int session) +{ + if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + return BAD_VALUE; + } + + Mutex::Autolock _l(mLock); + + ssize_t idx = mOutputAudioSessionInfo.indexOfKey(session); + if (idx >= 0) { + sp<AudioSessionInfo> info = mOutputAudioSessionInfo.valueAt(idx); + if (info->mRefCount == 0) { + mOutputAudioSessionInfo.removeItemsAt(idx); + } + ALOGV("releaseOutputAudioSessionInfo() sessionId=%d refcount=%d", + session, info->mRefCount); + } else { + ALOGV("releaseOutputAudioSessionInfo() no session info found"); + } + return NO_ERROR; +} + +status_t AudioPolicyEffects::updateOutputAudioSessionInfo(audio_io_handle_t /* output */, + audio_stream_type_t stream, + int session, + audio_output_flags_t flags, + audio_channel_mask_t channelMask, uid_t uid) +{ + if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + return BAD_VALUE; + } + + Mutex::Autolock _l(mLock); + + // TODO: Handle other stream types based on client registration + if (stream != AUDIO_STREAM_MUSIC) { + return NO_ERROR; + } + + // update AudioSessionInfo. This is used in the stream open/close path + // to notify userspace applications about session creation and + // teardown, allowing the app to make decisions about effects for + // a particular stream. This is independent of the current + // output_session_processing feature which forcibly attaches a + // static list of effects to a stream. + ssize_t idx = mOutputAudioSessionInfo.indexOfKey(session); + sp<AudioSessionInfo> info; + if (idx < 0) { + info = new AudioSessionInfo(session, stream, flags, channelMask, uid); + mOutputAudioSessionInfo.add(session, info); + } else { + // the streaminfo may actually change + info = mOutputAudioSessionInfo.valueAt(idx); + info->mFlags = flags; + info->mChannelMask = channelMask; + } + + ALOGV("updateOutputAudioSessionInfo() sessionId=%d, flags=0x%x, channelMask=0x%x uid=%d refCount=%d", + info->mSessionId, info->mFlags, info->mChannelMask, info->mUid, info->mRefCount); + + return NO_ERROR; +} + +status_t AudioPolicyEffects::listAudioSessions(audio_stream_type_t streams, + Vector< sp<AudioSessionInfo>> &sessions) +{ + ALOGV("listAudioSessions() streams %d", streams); + + for (unsigned int i = 0; i < mOutputAudioSessionInfo.size(); i++) { + sp<AudioSessionInfo> info = mOutputAudioSessionInfo.valueAt(i); + if (streams == -1 || info->mStream == streams) { + sessions.push_back(info); + } + } + + return NO_ERROR; +} + status_t AudioPolicyEffects::releaseOutputSessionEffects(audio_io_handle_t output, audio_stream_type_t stream, int audioSession) @@ -282,7 +384,19 @@ status_t AudioPolicyEffects::releaseOutputSessionEffects(audio_io_handle_t outpu (void) stream; // argument not used for now Mutex::Autolock _l(mLock); - ssize_t index = mOutputSessions.indexOfKey(audioSession); + ssize_t index = mOutputAudioSessionInfo.indexOfKey(audioSession); + if (index >= 0) { + sp<AudioSessionInfo> info = mOutputAudioSessionInfo.valueAt(index); + info->mRefCount--; + if (info->mRefCount == 0) { + mAudioPolicyService->onOutputSessionEffectsUpdate(info, false); + } + ALOGV("releaseOutputSessionEffects(): session=%d refCount=%d", info->mSessionId, info->mRefCount); + } else { + ALOGV("releaseOutputSessionEffects: no stream info was attached to this stream"); + } + + index = mOutputSessions.indexOfKey(audioSession); if (index < 0) { ALOGV("releaseOutputSessionEffects: no output processing was attached to this stream"); return NO_ERROR; @@ -442,6 +556,7 @@ effect_param_t *AudioPolicyEffects::loadEffectParameter(cnode *root) size_t curSize = sizeof(effect_param_t); size_t totSize = sizeof(effect_param_t) + 2 * sizeof(int); effect_param_t *fx_param = (effect_param_t *)malloc(totSize); + CHECK(fx_param != NULL); param = config_find(root, PARAM_TAG); value = config_find(root, VALUE_TAG); diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h index 3dec437..a95d49f 100644 --- a/services/audiopolicy/service/AudioPolicyEffects.h +++ b/services/audiopolicy/service/AudioPolicyEffects.h @@ -27,8 +27,12 @@ #include <utils/Vector.h> #include <utils/SortedVector.h> +#include <media/stagefright/foundation/ADebug.h> + namespace android { +class AudioPolicyService; + // ---------------------------------------------------------------------------- // AudioPolicyEffects class @@ -42,7 +46,7 @@ public: // The constructor will parse audio_effects.conf // First it will look whether vendor specific file exists, // otherwise it will parse the system default file. - AudioPolicyEffects(); + AudioPolicyEffects(AudioPolicyService *audioPolicyService); virtual ~AudioPolicyEffects(); // NOTE: methods on AudioPolicyEffects should never be called with the AudioPolicyService @@ -82,6 +86,19 @@ public: audio_stream_type_t stream, int audioSession); + status_t updateOutputAudioSessionInfo(audio_io_handle_t output, + audio_stream_type_t stream, + int audioSession, + audio_output_flags_t flags, + audio_channel_mask_t channelMask, uid_t uid); + + status_t releaseOutputAudioSessionInfo(audio_io_handle_t output, + audio_stream_type_t stream, + int audioSession); + + status_t listAudioSessions(audio_stream_type_t streams, + Vector< sp<AudioSessionInfo>> &sessions); + private: // class to store the description of an effects and its parameters @@ -102,6 +119,7 @@ private: ((origParam->psize + 3) & ~3) + ((origParam->vsize + 3) & ~3); effect_param_t *dupParam = (effect_param_t *) malloc(origSize); + CHECK(dupParam != NULL); memcpy(dupParam, origParam, origSize); // This works because the param buffer allocation is also done by // multiples of 4 bytes originally. In theory we should memcpy only @@ -189,6 +207,10 @@ private: KeyedVector< audio_stream_type_t, EffectDescVector* > mOutputStreams; // Automatic output effects are unique for audiosession ID KeyedVector< int32_t, EffectVector* > mOutputSessions; + // Stream info for session events + KeyedVector< int32_t, sp<AudioSessionInfo> > mOutputAudioSessionInfo; + + AudioPolicyService *mAudioPolicyService; }; }; // namespace android diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp index ca365a5..b23c35e 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp @@ -161,19 +161,32 @@ status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr, if (mAudioPolicyManager == NULL) { return NO_INIT; } - ALOGV("getOutput()"); - Mutex::Autolock _l(mLock); + ALOGV("getOutputForAttr()"); + status_t status = NO_ERROR; + sp<AudioPolicyEffects> audioPolicyEffects; + { + Mutex::Autolock _l(mLock); - // if the caller is us, trust the specified uid - if (IPCThreadState::self()->getCallingPid() != getpid_cached || uid == (uid_t)-1) { - uid_t newclientUid = IPCThreadState::self()->getCallingUid(); - if (uid != (uid_t)-1 && uid != newclientUid) { - ALOGW("%s uid %d tried to pass itself off as %d", __FUNCTION__, newclientUid, uid); + // if the caller is us, trust the specified uid + if (IPCThreadState::self()->getCallingPid() != getpid_cached || uid == (uid_t)-1) { + uid_t newclientUid = IPCThreadState::self()->getCallingUid(); + if (uid != (uid_t)-1 && uid != newclientUid) { + ALOGW("%s uid %d tried to pass itself off as %d", __FUNCTION__, newclientUid, uid); + } + uid = newclientUid; } - uid = newclientUid; + status = mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid, samplingRate, + format, channelMask, flags, selectedDeviceId, offloadInfo); + + audioPolicyEffects = mAudioPolicyEffects; } - return mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid, samplingRate, - format, channelMask, flags, selectedDeviceId, offloadInfo); + + if (status == NO_ERROR && audioPolicyEffects != 0) { + audioPolicyEffects->updateOutputAudioSessionInfo(*output, + *stream, session, flags, channelMask, uid); + } + + return status; } status_t AudioPolicyService::startOutput(audio_io_handle_t output, @@ -187,6 +200,20 @@ status_t AudioPolicyService::startOutput(audio_io_handle_t output, return NO_INIT; } ALOGV("startOutput()"); + return mOutputCommandThread->startOutputCommand(output, stream, session); +} + +status_t AudioPolicyService::doStartOutput(audio_io_handle_t output, + audio_stream_type_t stream, + audio_session_t session) +{ + if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + return BAD_VALUE; + } + if (mAudioPolicyManager == NULL) { + return NO_INIT; + } + ALOGV("doStartOutput()"); sp<AudioPolicyEffects>audioPolicyEffects; { Mutex::Autolock _l(mLock); @@ -255,8 +282,16 @@ void AudioPolicyService::doReleaseOutput(audio_io_handle_t output, audio_session_t session) { ALOGV("doReleaseOutput from tid %d", gettid()); - Mutex::Autolock _l(mLock); - mAudioPolicyManager->releaseOutput(output, stream, session); + sp<AudioPolicyEffects>audioPolicyEffects; + { + Mutex::Autolock _l(mLock); + audioPolicyEffects = mAudioPolicyEffects; + mAudioPolicyManager->releaseOutput(output, stream, session); + } + if (audioPolicyEffects != 0) { + audioPolicyEffects->releaseOutputAudioSessionInfo(output, + stream, session); + } } status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr, @@ -281,6 +316,11 @@ status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr, if ((attr->source == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed()) { return BAD_VALUE; } + + if ((attr->source == AUDIO_SOURCE_FM_TUNER) && !accessFmRadioAllowed()) { + return BAD_VALUE; + } + sp<AudioPolicyEffects>audioPolicyEffects; status_t status; AudioPolicyInterface::input_type_t inputType; @@ -463,6 +503,7 @@ audio_devices_t AudioPolicyService::getDevicesForStream(audio_stream_type_t stre if (mAudioPolicyManager == NULL) { return AUDIO_DEVICE_NONE; } + Mutex::Autolock _l(mLock); return mAudioPolicyManager->getDevicesForStream(stream); } @@ -702,4 +743,25 @@ status_t AudioPolicyService::stopAudioSource(audio_io_handle_t handle) return mAudioPolicyManager->stopAudioSource(handle); } +status_t AudioPolicyService::listAudioSessions(audio_stream_type_t streams, + Vector< sp<AudioSessionInfo>> &sessions) +{ + sp<AudioPolicyEffects> audioPolicyEffects; + { + Mutex::Autolock _l(mLock); + if (mAudioPolicyManager == NULL) { + return NO_INIT; + } + audioPolicyEffects = mAudioPolicyEffects; + } + + if (audioPolicyEffects != 0) { + return audioPolicyEffects->listAudioSessions(streams, sessions); + } + + // no errors here if effects are not available + return NO_ERROR; +} + + }; // namespace android diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp index 13af3ef..da7f45d 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp @@ -158,13 +158,27 @@ status_t AudioPolicyService::startOutput(audio_io_handle_t output, return NO_INIT; } ALOGV("startOutput()"); - // create audio processors according to stream + return mOutputCommandThread->startOutputCommand(output, stream, session); +} + +status_t AudioPolicyService::doStartOutput(audio_io_handle_t output, + audio_stream_type_t stream, + audio_session_t session) +{ + if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + return BAD_VALUE; + } + if (mpAudioPolicy == NULL) { + return NO_INIT; + } + ALOGV("doStartOutput()"); sp<AudioPolicyEffects>audioPolicyEffects; { Mutex::Autolock _l(mLock); audioPolicyEffects = mAudioPolicyEffects; } if (audioPolicyEffects != 0) { + // create audio processors according to stream status_t status = audioPolicyEffects->addOutputSessionEffects(output, stream, session); if (status != NO_ERROR && status != ALREADY_EXISTS) { ALOGW("Failed to add effects on session %d", session); @@ -261,6 +275,15 @@ status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr, return BAD_VALUE; } + if ((inputSource == AUDIO_SOURCE_FM_TUNER) && !accessFmRadioAllowed()) { + return BAD_VALUE; + } + +#ifdef HAVE_PRE_KITKAT_AUDIO_POLICY_BLOB + if (inputSource == AUDIO_SOURCE_HOTWORD) + inputSource = AUDIO_SOURCE_VOICE_RECOGNITION; +#endif + sp<AudioPolicyEffects>audioPolicyEffects; { Mutex::Autolock _l(mLock); @@ -510,6 +533,9 @@ status_t AudioPolicyService::queryDefaultPreProcessing(int audioSession, bool AudioPolicyService::isOffloadSupported(const audio_offload_info_t& info) { +#ifdef HAVE_PRE_KITKAT_AUDIO_POLICY_BLOB + return false; +#else if (mpAudioPolicy == NULL) { ALOGV("mpAudioPolicy == NULL"); return false; @@ -521,6 +547,7 @@ bool AudioPolicyService::isOffloadSupported(const audio_offload_info_t& info) } return mpAudioPolicy->is_offload_supported(mpAudioPolicy, &info); +#endif } status_t AudioPolicyService::listAudioPorts(audio_port_role_t role __unused, @@ -619,4 +646,9 @@ status_t AudioPolicyService::stopAudioSource(audio_io_handle_t handle) return INVALID_OPERATION; } +status_t AudioPolicyService::listAudioSessions(audio_stream_type_t streams, + Vector< sp<AudioSessionInfo>> &sessions) +{ + return INVALID_OPERATION; +} }; // namespace android diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp index c77cc45..79370f4 100644 --- a/services/audiopolicy/service/AudioPolicyService.cpp +++ b/services/audiopolicy/service/AudioPolicyService.cpp @@ -116,7 +116,7 @@ void AudioPolicyService::onFirstRef() #endif } // load audio processing modules - sp<AudioPolicyEffects>audioPolicyEffects = new AudioPolicyEffects(); + sp<AudioPolicyEffects>audioPolicyEffects = new AudioPolicyEffects(this); { Mutex::Autolock _l(mLock); mAudioPolicyEffects = audioPolicyEffects; @@ -254,6 +254,21 @@ status_t AudioPolicyService::clientSetAudioPortConfig(const struct audio_port_co return mAudioCommandThread->setAudioPortConfigCommand(config, delayMs); } +void AudioPolicyService::onOutputSessionEffectsUpdate(sp<AudioSessionInfo>& info, bool added) +{ + ALOGV("AudioPolicyService::onOutputSessionEffectsUpdate(%d, %d, %d)", + info->mStream, info->mSessionId, added); + mOutputCommandThread->effectSessionUpdateCommand(info, added); +} + +void AudioPolicyService::doOnOutputSessionEffectsUpdate(sp<AudioSessionInfo>& info, bool added) +{ + Mutex::Autolock _l(mNotificationClientsLock); + for (size_t i = 0; i < mNotificationClients.size(); i++) { + mNotificationClients.valueAt(i)->onOutputSessionEffectsUpdate(info, added); + } +} + AudioPolicyService::NotificationClient::NotificationClient(const sp<AudioPolicyService>& service, const sp<IAudioPolicyServiceClient>& client, uid_t uid) @@ -289,6 +304,14 @@ void AudioPolicyService::NotificationClient::onAudioPatchListUpdate() } } +void AudioPolicyService::NotificationClient::onOutputSessionEffectsUpdate( + sp<AudioSessionInfo>& info, bool added) +{ + if (mAudioPolicyServiceClient != 0) { + mAudioPolicyServiceClient->onOutputSessionEffectsUpdate(info, added); + } +} + void AudioPolicyService::NotificationClient::onDynamicPolicyMixStateUpdate( String8 regId, int32_t state) { @@ -478,6 +501,19 @@ bool AudioPolicyService::AudioCommandThread::threadLoop() data->mVolume); command->mStatus = AudioSystem::setVoiceVolume(data->mVolume); }break; + case START_OUTPUT: { + StartOutputData *data = (StartOutputData *)command->mParam.get(); + ALOGV("AudioCommandThread() processing start output %d", + data->mIO); + svc = mService.promote(); + if (svc == 0) { + command->mStatus = UNKNOWN_ERROR; + break; + } + mLock.unlock(); + command->mStatus = svc->doStartOutput(data->mIO, data->mStream, data->mSession); + mLock.lock(); + }break; case STOP_OUTPUT: { StopOutputData *data = (StopOutputData *)command->mParam.get(); ALOGV("AudioCommandThread() processing stop output %d", @@ -566,6 +602,21 @@ bool AudioPolicyService::AudioCommandThread::threadLoop() svc->doOnDynamicPolicyMixStateUpdate(data->mRegId, data->mState); mLock.lock(); } break; + case EFFECT_SESSION_UPDATE: { + EffectSessionUpdateData *data = + (EffectSessionUpdateData *)command->mParam.get(); + ALOGV("AudioCommandThread() processing effect session update %d %d %d", + data->mAudioSessionInfo->mStream, data->mAudioSessionInfo->mSessionId, + data->mAdded); + svc = mService.promote(); + if (svc == 0) { + break; + } + mLock.unlock(); + svc->doOnOutputSessionEffectsUpdate(data->mAudioSessionInfo, data->mAdded); + mLock.lock(); + } break; + default: ALOGW("AudioCommandThread() unknown command %d", command->mCommand); } @@ -714,6 +765,22 @@ status_t AudioPolicyService::AudioCommandThread::voiceVolumeCommand(float volume return sendCommand(command, delayMs); } +status_t AudioPolicyService::AudioCommandThread::startOutputCommand(audio_io_handle_t output, + audio_stream_type_t stream, + audio_session_t session) +{ + sp<AudioCommand> command = new AudioCommand(); + command->mCommand = START_OUTPUT; + sp<StartOutputData> data = new StartOutputData(); + data->mIO = output; + data->mStream = stream; + data->mSession = session; + command->mParam = data; + command->mWaitStatus = true; + ALOGV("AudioCommandThread() adding start output %d", output); + return sendCommand(command); +} + void AudioPolicyService::AudioCommandThread::stopOutputCommand(audio_io_handle_t output, audio_stream_type_t stream, audio_session_t session) @@ -822,6 +889,20 @@ void AudioPolicyService::AudioCommandThread::dynamicPolicyMixStateUpdateCommand( sendCommand(command); } +void AudioPolicyService::AudioCommandThread::effectSessionUpdateCommand( + sp<AudioSessionInfo>& streamInfo, bool added) +{ + sp<AudioCommand> command = new AudioCommand(); + command->mCommand = EFFECT_SESSION_UPDATE; + EffectSessionUpdateData *data = new EffectSessionUpdateData(); + data->mAudioSessionInfo = streamInfo; + data->mAdded = added; + command->mParam = data; + ALOGV("AudioCommandThread() sending effect session update (id=%d) for stream %d (added=%d)", + streamInfo->mStream, streamInfo->mSessionId, added); + sendCommand(command); +} + status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs) { { @@ -899,10 +980,12 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(sp<AudioCommand>& c } else { data2->mKeyValuePairs = param2.toString(); } - command->mTime = command2->mTime; - // force delayMs to non 0 so that code below does not request to wait for - // command status as the command is now delayed - delayMs = 1; + if (!data2->mKeyValuePairs.compare(data->mKeyValuePairs)) { + command->mTime = command2->mTime; + // force delayMs to non 0 so that code below does not request to wait for + // command status as the command is now delayed + delayMs = 1; + } } break; case SET_VOLUME: { diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h index a0d5aa2..b7f55ae 100644 --- a/services/audiopolicy/service/AudioPolicyService.h +++ b/services/audiopolicy/service/AudioPolicyService.h @@ -202,6 +202,12 @@ public: audio_io_handle_t *handle); virtual status_t stopAudioSource(audio_io_handle_t handle); + virtual status_t listAudioSessions(audio_stream_type_t stream, + Vector< sp<AudioSessionInfo>>& sessions); + + status_t doStartOutput(audio_io_handle_t output, + audio_stream_type_t stream, + audio_session_t session); status_t doStopOutput(audio_io_handle_t output, audio_stream_type_t stream, audio_session_t session); @@ -226,6 +232,9 @@ public: void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state); void doOnDynamicPolicyMixStateUpdate(String8 regId, int32_t state); + void onOutputSessionEffectsUpdate(sp<AudioSessionInfo>& info, bool added); + void doOnOutputSessionEffectsUpdate(sp<AudioSessionInfo>& info, bool added); + private: AudioPolicyService() ANDROID_API; virtual ~AudioPolicyService(); @@ -249,6 +258,7 @@ private: SET_VOLUME, SET_PARAMETERS, SET_VOICE_VOLUME, + START_OUTPUT, STOP_OUTPUT, RELEASE_OUTPUT, CREATE_AUDIO_PATCH, @@ -256,7 +266,8 @@ private: UPDATE_AUDIOPORT_LIST, UPDATE_AUDIOPATCH_LIST, SET_AUDIOPORT_CONFIG, - DYN_POLICY_MIX_STATE_UPDATE + DYN_POLICY_MIX_STATE_UPDATE, + EFFECT_SESSION_UPDATE, }; AudioCommandThread (String8 name, const wp<AudioPolicyService>& service); @@ -277,6 +288,9 @@ private: status_t parametersCommand(audio_io_handle_t ioHandle, const char *keyValuePairs, int delayMs = 0); status_t voiceVolumeCommand(float volume, int delayMs = 0); + status_t startOutputCommand(audio_io_handle_t output, + audio_stream_type_t stream, + audio_session_t session); void stopOutputCommand(audio_io_handle_t output, audio_stream_type_t stream, audio_session_t session); @@ -296,6 +310,7 @@ private: int delayMs); void dynamicPolicyMixStateUpdateCommand(String8 regId, int32_t state); void insertCommand_l(AudioCommand *command, int delayMs = 0); + void effectSessionUpdateCommand(sp<AudioSessionInfo>& info, bool added); private: class AudioCommandData; @@ -349,6 +364,13 @@ private: float mVolume; }; + class StartOutputData : public AudioCommandData { + public: + audio_io_handle_t mIO; + audio_stream_type_t mStream; + audio_session_t mSession; + }; + class StopOutputData : public AudioCommandData { public: audio_io_handle_t mIO; @@ -385,6 +407,12 @@ private: int32_t mState; }; + class EffectSessionUpdateData : public AudioCommandData { + public: + sp<AudioSessionInfo> mAudioSessionInfo; + bool mAdded; + }; + Mutex mLock; Condition mWaitWorkCV; Vector < sp<AudioCommand> > mAudioCommands; // list of pending commands @@ -494,6 +522,9 @@ private: virtual audio_unique_id_t newAudioUniqueId(); + virtual void onOutputSessionEffectsUpdate(sp<AudioSessionInfo>& info, bool added); + + private: AudioPolicyService *mAudioPolicyService; }; @@ -510,7 +541,8 @@ private: void onAudioPatchListUpdate(); void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state); void setAudioPortCallbacksEnabled(bool enabled); - + void onOutputSessionEffectsUpdate(sp<AudioSessionInfo>& info, + bool added); // IBinder::DeathRecipient virtual void binderDied(const wp<IBinder>& who); diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk index 45900c4..ab09cb3 100644 --- a/services/camera/libcameraservice/Android.mk +++ b/services/camera/libcameraservice/Android.mk @@ -79,6 +79,14 @@ LOCAL_C_INCLUDES += \ LOCAL_CFLAGS += -Wall -Wextra +ifeq ($(BOARD_NEEDS_MEMORYHEAPION),true) + LOCAL_CFLAGS += -DUSE_MEMORY_HEAP_ION +endif + +ifneq ($(BOARD_NUMBER_OF_CAMERAS),) + LOCAL_CFLAGS += -DMAX_CAMERAS=$(BOARD_NUMBER_OF_CAMERAS) +endif + LOCAL_MODULE:= libcameraservice include $(BUILD_SHARED_LIBRARY) diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 7c4594f..3c9fd16 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -81,7 +81,7 @@ static void camera_device_status_change( sp<CameraService> cs = const_cast<CameraService*>( static_cast<const CameraService*>(callbacks)); - cs->onDeviceStatusChanged(static_cast<camera_device_status_t>(camera_id), + cs->onDeviceStatusChanged(camera_id, static_cast<camera_device_status_t>(new_status)); } @@ -153,6 +153,7 @@ void CameraService::onFirstRef() ALOGE("Could not load camera HAL module: %d (%s)", err, strerror(-err)); logServiceError("Could not load camera HAL module", err); mNumberOfCameras = 0; + mNumberOfNormalCameras = 0; return; } @@ -276,7 +277,7 @@ CameraService::~CameraService() { gCameraService = nullptr; } -void CameraService::onDeviceStatusChanged(camera_device_status_t cameraId, +void CameraService::onDeviceStatusChanged(int cameraId, camera_device_status_t newStatus) { ALOGI("%s: Status changed for cameraId=%d, newStatus=%d", __FUNCTION__, cameraId, newStatus); diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index d2c1bd3..53233bd 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -49,6 +49,10 @@ #include <memory> #include <utility> +#ifndef MAX_CAMERAS +#define MAX_CAMERAS 2 +#endif + namespace android { extern volatile int32_t gLogLevel; @@ -98,7 +102,7 @@ public: ///////////////////////////////////////////////////////////////////// // HAL Callbacks - virtual void onDeviceStatusChanged(camera_device_status_t cameraId, + virtual void onDeviceStatusChanged(int cameraId, camera_device_status_t newStatus); virtual void onTorchStatusChanged(const String8& cameraId, ICameraServiceListener::TorchStatus diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp index fbd4034..96266ed 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.cpp +++ b/services/camera/libcameraservice/api1/Camera2Client.cpp @@ -1745,8 +1745,6 @@ void Camera2Client::notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCod err = CAMERA_ERROR_RELEASED; break; case ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE: - err = CAMERA_ERROR_UNKNOWN; - break; case ICameraDeviceCallbacks::ERROR_CAMERA_SERVICE: err = CAMERA_ERROR_SERVER_DIED; break; diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp index 6020e35..af46d63 100644 --- a/services/camera/libcameraservice/api1/CameraClient.cpp +++ b/services/camera/libcameraservice/api1/CameraClient.cpp @@ -56,6 +56,9 @@ CameraClient::CameraClient(const sp<CameraService>& cameraService, mOrientation = getOrientation(0, mCameraFacing == CAMERA_FACING_FRONT); mLegacyMode = legacyMode; mPlayShutterSound = true; + + mLongshotEnabled = false; + mBurstCnt = 0; LOG1("CameraClient::CameraClient X (pid %d, id %d)", callingPid, cameraId); } @@ -240,11 +243,6 @@ void CameraClient::disconnect() { return; } - if (mClientPid <= 0) { - LOG1("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid); - return; - } - // Make sure disconnect() is done once and once only, whether it is called // from the user directly, or called by the destructor. if (mHardware == 0) return; @@ -364,12 +362,14 @@ status_t CameraClient::setPreviewCallbackTarget( // start preview mode status_t CameraClient::startPreview() { + Mutex::Autolock lock(mLock); LOG1("startPreview (pid %d)", getCallingPid()); return startCameraMode(CAMERA_PREVIEW_MODE); } // start recording mode status_t CameraClient::startRecording() { + Mutex::Autolock lock(mLock); LOG1("startRecording (pid %d)", getCallingPid()); return startCameraMode(CAMERA_RECORDING_MODE); } @@ -377,7 +377,6 @@ status_t CameraClient::startRecording() { // start preview or recording status_t CameraClient::startCameraMode(camera_mode mode) { LOG1("startCameraMode(%d)", mode); - Mutex::Autolock lock(mLock); status_t result = checkPidAndHardware(); if (result != NO_ERROR) return result; @@ -557,6 +556,10 @@ status_t CameraClient::takePicture(int msgType) { CAMERA_MSG_COMPRESSED_IMAGE); enableMsgType(picMsgType); + mBurstCnt = mHardware->getParameters().getInt("num-snaps-per-shutter"); + if(mBurstCnt <= 0) + mBurstCnt = 1; + LOG1("mBurstCnt = %d", mBurstCnt); return mHardware->takePicture(); } @@ -659,6 +662,20 @@ status_t CameraClient::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) { } else if (cmd == CAMERA_CMD_PING) { // If mHardware is 0, checkPidAndHardware will return error. return OK; + } else if (cmd == CAMERA_CMD_HISTOGRAM_ON) { + enableMsgType(CAMERA_MSG_STATS_DATA); + } else if (cmd == CAMERA_CMD_HISTOGRAM_OFF) { + disableMsgType(CAMERA_MSG_STATS_DATA); + } else if (cmd == CAMERA_CMD_METADATA_ON) { + enableMsgType(CAMERA_MSG_META_DATA); + } else if (cmd == CAMERA_CMD_METADATA_OFF) { + disableMsgType(CAMERA_MSG_META_DATA); + } else if ( cmd == CAMERA_CMD_LONGSHOT_ON ) { + mLongshotEnabled = true; + } else if ( cmd == CAMERA_CMD_LONGSHOT_OFF ) { + mLongshotEnabled = false; + disableMsgType(CAMERA_MSG_SHUTTER); + disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE); } return mHardware->sendCommand(cmd, arg1, arg2); @@ -678,6 +695,9 @@ void CameraClient::disableMsgType(int32_t msgType) { #define CHECK_MESSAGE_INTERVAL 10 // 10ms bool CameraClient::lockIfMessageWanted(int32_t msgType) { +#ifdef MTK_HARDWARE + return true; +#endif int sleepCount = 0; while (mMsgEnabled & msgType) { if (mLock.tryLock() == NO_ERROR) { @@ -801,7 +821,9 @@ void CameraClient::handleShutter(void) { c->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0); if (!lockIfMessageWanted(CAMERA_MSG_SHUTTER)) return; } - disableMsgType(CAMERA_MSG_SHUTTER); + if ( !mLongshotEnabled ) { + disableMsgType(CAMERA_MSG_SHUTTER); + } // Shutters only happen in response to takePicture, so mark device as // idle now, until preview is restarted @@ -886,7 +908,13 @@ void CameraClient::handleRawPicture(const sp<IMemory>& mem) { // picture callback - compressed picture ready void CameraClient::handleCompressedPicture(const sp<IMemory>& mem) { - disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE); + if (mBurstCnt) + mBurstCnt--; + + if (!mBurstCnt && !mLongshotEnabled) { + LOG1("handleCompressedPicture mBurstCnt = %d", mBurstCnt); + disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE); + } sp<ICameraClient> c = mRemoteCallback; mLock.unlock(); diff --git a/services/camera/libcameraservice/api1/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h index 17999a5..d2cb64a 100644 --- a/services/camera/libcameraservice/api1/CameraClient.h +++ b/services/camera/libcameraservice/api1/CameraClient.h @@ -164,6 +164,9 @@ private: // This function keeps trying to grab mLock, or give up if the message // is found to be disabled. It returns true if mLock is grabbed. bool lockIfMessageWanted(int32_t msgType); + + bool mLongshotEnabled; + int mBurstCnt; }; } diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.h b/services/camera/libcameraservice/device1/CameraHardwareInterface.h index 7f14cd4..35947a9 100644 --- a/services/camera/libcameraservice/device1/CameraHardwareInterface.h +++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.h @@ -25,7 +25,10 @@ #include <camera/Camera.h> #include <camera/CameraParameters.h> #include <system/window.h> -#include <hardware/camera.h> +#include "hardware/camera.h" +#ifdef USE_MEMORY_HEAP_ION +#include <binder/MemoryHeapIon.h> +#endif namespace android { @@ -322,6 +325,10 @@ public: void releaseRecordingFrame(const sp<IMemory>& mem) { ALOGV("%s(%s)", __FUNCTION__, mName.string()); + if (mem == NULL) { + ALOGE("%s: NULL memory reference", __FUNCTION__); + return; + } if (mDevice->ops->release_recording_frame) { ssize_t offset; size_t size; @@ -501,7 +508,11 @@ private: mBufSize(buf_size), mNumBufs(num_buffers) { +#ifdef USE_MEMORY_HEAP_ION + mHeap = new MemoryHeapIon(fd, buf_size * num_buffers); +#else mHeap = new MemoryHeapBase(fd, buf_size * num_buffers); +#endif commonInitialization(); } @@ -509,7 +520,11 @@ private: mBufSize(buf_size), mNumBufs(num_buffers) { +#ifdef USE_MEMORY_HEAP_ION + mHeap = new MemoryHeapIon(buf_size * num_buffers); +#else mHeap = new MemoryHeapBase(buf_size * num_buffers); +#endif commonInitialization(); } @@ -541,14 +556,24 @@ private: camera_memory_t handle; }; +#ifdef USE_MEMORY_HEAP_ION + static camera_memory_t* __get_memory(int fd, size_t buf_size, uint_t num_bufs, + void *ion_fd) + { +#else static camera_memory_t* __get_memory(int fd, size_t buf_size, uint_t num_bufs, void *user __attribute__((unused))) { +#endif CameraHeapMemory *mem; if (fd < 0) mem = new CameraHeapMemory(buf_size, num_bufs); else mem = new CameraHeapMemory(fd, buf_size, num_bufs); +#ifdef USE_MEMORY_HEAP_ION + if (ion_fd) + *((int *) ion_fd) = mem->mHeap->getHeapID(); +#endif mem->incStrong(mem); return &mem->handle; } diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp index 9de6fe2..371c81a 100644 --- a/services/soundtrigger/SoundTriggerHwService.cpp +++ b/services/soundtrigger/SoundTriggerHwService.cpp @@ -270,6 +270,37 @@ void SoundTriggerHwService::sendRecognitionEvent(struct sound_trigger_recognitio if (module == NULL) { return; } + if (event-> type == SOUND_MODEL_TYPE_KEYPHRASE && event->data_size != 0 + && event->data_offset != sizeof(struct sound_trigger_phrase_recognition_event)) { + // set some defaults for the phrase if the recognition event won't be parsed properly + // TODO: read defaults from the config + + struct sound_trigger_phrase_recognition_event newEvent; + memset(&newEvent, 0, sizeof(struct sound_trigger_phrase_recognition_event)); + + sp<Model> model = module->getModel(event->model); + + newEvent.num_phrases = 1; + newEvent.phrase_extras[0].id = 100; + newEvent.phrase_extras[0].recognition_modes = RECOGNITION_MODE_VOICE_TRIGGER; + newEvent.phrase_extras[0].confidence_level = 100; + newEvent.phrase_extras[0].num_levels = 1; + newEvent.phrase_extras[0].levels[0].level = 100; + newEvent.phrase_extras[0].levels[0].user_id = 100; + newEvent.common.status = event->status; + newEvent.common.type = event->type; + newEvent.common.model = event->model; + newEvent.common.capture_available = event->capture_available; + newEvent.common.capture_session = event->capture_session; + newEvent.common.capture_delay_ms = event->capture_delay_ms; + newEvent.common.capture_preamble_ms = event->capture_preamble_ms; + newEvent.common.trigger_in_data = event->trigger_in_data; + newEvent.common.audio_config = event->audio_config; + newEvent.common.data_size = event->data_size; + newEvent.common.data_offset = sizeof(struct sound_trigger_phrase_recognition_event); + + event = &newEvent.common; + } sp<IMemory> eventMemory = prepareRecognitionEvent_l(event); if (eventMemory == 0) { return; |