diff options
author | Mathias Agopian <mathias@google.com> | 2010-07-14 17:59:35 -0700 |
---|---|---|
committer | Mathias Agopian <mathias@google.com> | 2010-07-14 17:59:35 -0700 |
commit | 81bac09fa6b01dd1495644d9c825c3666762fced (patch) | |
tree | 346e826932eef1b4402dfa98796075e63d3c90e8 /libs | |
parent | e1ea0811de760256cee3b1ffca227251e1cf52c5 (diff) | |
download | frameworks_native-81bac09fa6b01dd1495644d9c825c3666762fced.zip frameworks_native-81bac09fa6b01dd1495644d9c825c3666762fced.tar.gz frameworks_native-81bac09fa6b01dd1495644d9c825c3666762fced.tar.bz2 |
move native services under services/
moved surfaceflinger, audioflinger, cameraservice
all native services should now reside in this location.
Change-Id: Iee42b83dd2a94c3bf5107ab0895fe2dfcd5337a8
Diffstat (limited to 'libs')
60 files changed, 0 insertions, 24657 deletions
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp deleted file mode 100644 index 995e31c..0000000 --- a/libs/audioflinger/A2dpAudioInterface.cpp +++ /dev/null @@ -1,466 +0,0 @@ -/* - * Copyright (C) 2008 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 <math.h> - -//#define LOG_NDEBUG 0 -#define LOG_TAG "A2dpAudioInterface" -#include <utils/Log.h> -#include <utils/String8.h> - -#include "A2dpAudioInterface.h" -#include "audio/liba2dp.h" - - -namespace android { - -// ---------------------------------------------------------------------------- - -//AudioHardwareInterface* A2dpAudioInterface::createA2dpInterface() -//{ -// AudioHardwareInterface* hw = 0; -// -// hw = AudioHardwareInterface::create(); -// LOGD("new A2dpAudioInterface(hw: %p)", hw); -// hw = new A2dpAudioInterface(hw); -// return hw; -//} - -A2dpAudioInterface::A2dpAudioInterface(AudioHardwareInterface* hw) : - mOutput(0), mHardwareInterface(hw), mBluetoothEnabled(true), mSuspended(false) -{ -} - -A2dpAudioInterface::~A2dpAudioInterface() -{ - closeOutputStream((AudioStreamOut *)mOutput); - delete mHardwareInterface; -} - -status_t A2dpAudioInterface::initCheck() -{ - if (mHardwareInterface == 0) return NO_INIT; - return mHardwareInterface->initCheck(); -} - -AudioStreamOut* A2dpAudioInterface::openOutputStream( - uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status) -{ - if (!AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices)) { - LOGV("A2dpAudioInterface::openOutputStream() open HW device: %x", devices); - return mHardwareInterface->openOutputStream(devices, format, channels, sampleRate, status); - } - - status_t err = 0; - - // only one output stream allowed - if (mOutput) { - if (status) - *status = -1; - return NULL; - } - - // create new output stream - A2dpAudioStreamOut* out = new A2dpAudioStreamOut(); - if ((err = out->set(devices, format, channels, sampleRate)) == NO_ERROR) { - mOutput = out; - mOutput->setBluetoothEnabled(mBluetoothEnabled); - mOutput->setSuspended(mSuspended); - } else { - delete out; - } - - if (status) - *status = err; - return mOutput; -} - -void A2dpAudioInterface::closeOutputStream(AudioStreamOut* out) { - if (mOutput == 0 || mOutput != out) { - mHardwareInterface->closeOutputStream(out); - } - else { - delete mOutput; - mOutput = 0; - } -} - - -AudioStreamIn* A2dpAudioInterface::openInputStream( - uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status, - AudioSystem::audio_in_acoustics acoustics) -{ - return mHardwareInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics); -} - -void A2dpAudioInterface::closeInputStream(AudioStreamIn* in) -{ - return mHardwareInterface->closeInputStream(in); -} - -status_t A2dpAudioInterface::setMode(int mode) -{ - return mHardwareInterface->setMode(mode); -} - -status_t A2dpAudioInterface::setMicMute(bool state) -{ - return mHardwareInterface->setMicMute(state); -} - -status_t A2dpAudioInterface::getMicMute(bool* state) -{ - return mHardwareInterface->getMicMute(state); -} - -status_t A2dpAudioInterface::setParameters(const String8& keyValuePairs) -{ - AudioParameter param = AudioParameter(keyValuePairs); - String8 value; - String8 key; - status_t status = NO_ERROR; - - LOGV("setParameters() %s", keyValuePairs.string()); - - key = "bluetooth_enabled"; - if (param.get(key, value) == NO_ERROR) { - mBluetoothEnabled = (value == "true"); - if (mOutput) { - mOutput->setBluetoothEnabled(mBluetoothEnabled); - } - param.remove(key); - } - key = String8("A2dpSuspended"); - if (param.get(key, value) == NO_ERROR) { - mSuspended = (value == "true"); - if (mOutput) { - mOutput->setSuspended(mSuspended); - } - param.remove(key); - } - - if (param.size()) { - status_t hwStatus = mHardwareInterface->setParameters(param.toString()); - if (status == NO_ERROR) { - status = hwStatus; - } - } - - return status; -} - -String8 A2dpAudioInterface::getParameters(const String8& keys) -{ - AudioParameter param = AudioParameter(keys); - AudioParameter a2dpParam = AudioParameter(); - String8 value; - String8 key; - - key = "bluetooth_enabled"; - if (param.get(key, value) == NO_ERROR) { - value = mBluetoothEnabled ? "true" : "false"; - a2dpParam.add(key, value); - param.remove(key); - } - key = "A2dpSuspended"; - if (param.get(key, value) == NO_ERROR) { - value = mSuspended ? "true" : "false"; - a2dpParam.add(key, value); - param.remove(key); - } - - String8 keyValuePairs = a2dpParam.toString(); - - if (param.size()) { - if (keyValuePairs != "") { - keyValuePairs += ";"; - } - keyValuePairs += mHardwareInterface->getParameters(param.toString()); - } - - LOGV("getParameters() %s", keyValuePairs.string()); - return keyValuePairs; -} - -size_t A2dpAudioInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount) -{ - return mHardwareInterface->getInputBufferSize(sampleRate, format, channelCount); -} - -status_t A2dpAudioInterface::setVoiceVolume(float v) -{ - return mHardwareInterface->setVoiceVolume(v); -} - -status_t A2dpAudioInterface::setMasterVolume(float v) -{ - return mHardwareInterface->setMasterVolume(v); -} - -status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args) -{ - return mHardwareInterface->dumpState(fd, args); -} - -// ---------------------------------------------------------------------------- - -A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() : - mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL), - // assume BT enabled to start, this is safe because its only the - // enabled->disabled transition we are worried about - mBluetoothEnabled(true), mDevice(0), mClosing(false), mSuspended(false) -{ - // use any address by default - strcpy(mA2dpAddress, "00:00:00:00:00:00"); - init(); -} - -status_t A2dpAudioInterface::A2dpAudioStreamOut::set( - uint32_t device, int *pFormat, uint32_t *pChannels, uint32_t *pRate) -{ - int lFormat = pFormat ? *pFormat : 0; - uint32_t lChannels = pChannels ? *pChannels : 0; - uint32_t lRate = pRate ? *pRate : 0; - - LOGD("A2dpAudioStreamOut::set %x, %d, %d, %d\n", device, lFormat, lChannels, lRate); - - // fix up defaults - if (lFormat == 0) lFormat = format(); - if (lChannels == 0) lChannels = channels(); - if (lRate == 0) lRate = sampleRate(); - - // check values - if ((lFormat != format()) || - (lChannels != channels()) || - (lRate != sampleRate())){ - if (pFormat) *pFormat = format(); - if (pChannels) *pChannels = channels(); - if (pRate) *pRate = sampleRate(); - return BAD_VALUE; - } - - if (pFormat) *pFormat = lFormat; - if (pChannels) *pChannels = lChannels; - if (pRate) *pRate = lRate; - - mDevice = device; - return NO_ERROR; -} - -A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut() -{ - LOGV("A2dpAudioStreamOut destructor"); - standby(); - close(); - LOGV("A2dpAudioStreamOut destructor returning from close()"); -} - -ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes) -{ - Mutex::Autolock lock(mLock); - - size_t remaining = bytes; - status_t status = -1; - - if (!mBluetoothEnabled || mClosing || mSuspended) { - LOGV("A2dpAudioStreamOut::write(), but bluetooth disabled \ - mBluetoothEnabled %d, mClosing %d, mSuspended %d", - mBluetoothEnabled, mClosing, mSuspended); - goto Error; - } - - status = init(); - if (status < 0) - goto Error; - - while (remaining > 0) { - status = a2dp_write(mData, buffer, remaining); - if (status <= 0) { - LOGE("a2dp_write failed err: %d\n", status); - goto Error; - } - remaining -= status; - buffer = ((char *)buffer) + status; - } - - mStandby = false; - - return bytes; - -Error: - // Simulate audio output timing in case of error - usleep(((bytes * 1000 )/ frameSize() / sampleRate()) * 1000); - - return status; -} - -status_t A2dpAudioInterface::A2dpAudioStreamOut::init() -{ - if (!mData) { - status_t status = a2dp_init(44100, 2, &mData); - if (status < 0) { - LOGE("a2dp_init failed err: %d\n", status); - mData = NULL; - return status; - } - a2dp_set_sink(mData, mA2dpAddress); - } - - return 0; -} - -status_t A2dpAudioInterface::A2dpAudioStreamOut::standby() -{ - int result = 0; - - if (mClosing) { - LOGV("Ignore standby, closing"); - return result; - } - - Mutex::Autolock lock(mLock); - - if (!mStandby) { - result = a2dp_stop(mData); - if (result == 0) - mStandby = true; - } - - return result; -} - -status_t A2dpAudioInterface::A2dpAudioStreamOut::setParameters(const String8& keyValuePairs) -{ - AudioParameter param = AudioParameter(keyValuePairs); - String8 value; - String8 key = String8("a2dp_sink_address"); - status_t status = NO_ERROR; - int device; - LOGV("A2dpAudioStreamOut::setParameters() %s", keyValuePairs.string()); - - if (param.get(key, value) == NO_ERROR) { - if (value.length() != strlen("00:00:00:00:00:00")) { - status = BAD_VALUE; - } else { - setAddress(value.string()); - } - param.remove(key); - } - key = String8("closing"); - if (param.get(key, value) == NO_ERROR) { - mClosing = (value == "true"); - param.remove(key); - } - key = AudioParameter::keyRouting; - if (param.getInt(key, device) == NO_ERROR) { - if (AudioSystem::isA2dpDevice((AudioSystem::audio_devices)device)) { - mDevice = device; - status = NO_ERROR; - } else { - status = BAD_VALUE; - } - param.remove(key); - } - - if (param.size()) { - status = BAD_VALUE; - } - return status; -} - -String8 A2dpAudioInterface::A2dpAudioStreamOut::getParameters(const String8& keys) -{ - AudioParameter param = AudioParameter(keys); - String8 value; - String8 key = String8("a2dp_sink_address"); - - if (param.get(key, value) == NO_ERROR) { - value = mA2dpAddress; - param.add(key, value); - } - key = AudioParameter::keyRouting; - if (param.get(key, value) == NO_ERROR) { - param.addInt(key, (int)mDevice); - } - - LOGV("A2dpAudioStreamOut::getParameters() %s", param.toString().string()); - return param.toString(); -} - -status_t A2dpAudioInterface::A2dpAudioStreamOut::setAddress(const char* address) -{ - Mutex::Autolock lock(mLock); - - if (strlen(address) != strlen("00:00:00:00:00:00")) - return -EINVAL; - - strcpy(mA2dpAddress, address); - if (mData) - a2dp_set_sink(mData, mA2dpAddress); - - return NO_ERROR; -} - -status_t A2dpAudioInterface::A2dpAudioStreamOut::setBluetoothEnabled(bool enabled) -{ - LOGD("setBluetoothEnabled %d", enabled); - - Mutex::Autolock lock(mLock); - - mBluetoothEnabled = enabled; - if (!enabled) { - return close_l(); - } - return NO_ERROR; -} - -status_t A2dpAudioInterface::A2dpAudioStreamOut::setSuspended(bool onOff) -{ - LOGV("setSuspended %d", onOff); - mSuspended = onOff; - standby(); - return NO_ERROR; -} - -status_t A2dpAudioInterface::A2dpAudioStreamOut::close() -{ - Mutex::Autolock lock(mLock); - LOGV("A2dpAudioStreamOut::close() calling close_l()"); - return close_l(); -} - -status_t A2dpAudioInterface::A2dpAudioStreamOut::close_l() -{ - if (mData) { - LOGV("A2dpAudioStreamOut::close_l() calling a2dp_cleanup(mData)"); - a2dp_cleanup(mData); - mData = NULL; - } - return NO_ERROR; -} - -status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector<String16>& args) -{ - return NO_ERROR; -} - -status_t A2dpAudioInterface::A2dpAudioStreamOut::getRenderPosition(uint32_t *driverFrames) -{ - //TODO: enable when supported by driver - return INVALID_OPERATION; -} - -}; // namespace android diff --git a/libs/audioflinger/A2dpAudioInterface.h b/libs/audioflinger/A2dpAudioInterface.h deleted file mode 100644 index 48154f9..0000000 --- a/libs/audioflinger/A2dpAudioInterface.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ - -#ifndef A2DP_AUDIO_HARDWARE_H -#define A2DP_AUDIO_HARDWARE_H - -#include <stdint.h> -#include <sys/types.h> - -#include <utils/threads.h> - -#include <hardware_legacy/AudioHardwareBase.h> - - -namespace android { - -class A2dpAudioInterface : public AudioHardwareBase -{ - class A2dpAudioStreamOut; - -public: - A2dpAudioInterface(AudioHardwareInterface* hw); - virtual ~A2dpAudioInterface(); - virtual status_t initCheck(); - - virtual status_t setVoiceVolume(float volume); - virtual status_t setMasterVolume(float volume); - - virtual status_t setMode(int mode); - - // mic mute - virtual status_t setMicMute(bool state); - virtual status_t getMicMute(bool* state); - - virtual status_t setParameters(const String8& keyValuePairs); - virtual String8 getParameters(const String8& keys); - - virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount); - - // create I/O streams - virtual AudioStreamOut* openOutputStream( - uint32_t devices, - int *format=0, - uint32_t *channels=0, - uint32_t *sampleRate=0, - status_t *status=0); - virtual void closeOutputStream(AudioStreamOut* out); - - virtual AudioStreamIn* openInputStream( - uint32_t devices, - int *format, - uint32_t *channels, - uint32_t *sampleRate, - status_t *status, - AudioSystem::audio_in_acoustics acoustics); - virtual void closeInputStream(AudioStreamIn* in); -// static AudioHardwareInterface* createA2dpInterface(); - -protected: - virtual status_t dump(int fd, const Vector<String16>& args); - -private: - class A2dpAudioStreamOut : public AudioStreamOut { - public: - A2dpAudioStreamOut(); - virtual ~A2dpAudioStreamOut(); - status_t set(uint32_t device, - int *pFormat, - uint32_t *pChannels, - uint32_t *pRate); - virtual uint32_t sampleRate() const { return 44100; } - // SBC codec wants a multiple of 512 - virtual size_t bufferSize() const { return 512 * 20; } - virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; } - virtual int format() const { return AudioSystem::PCM_16_BIT; } - virtual uint32_t latency() const { return ((1000*bufferSize())/frameSize())/sampleRate() + 200; } - virtual status_t setVolume(float left, float right) { return INVALID_OPERATION; } - virtual ssize_t write(const void* buffer, size_t bytes); - status_t standby(); - virtual status_t dump(int fd, const Vector<String16>& args); - virtual status_t setParameters(const String8& keyValuePairs); - virtual String8 getParameters(const String8& keys); - virtual status_t getRenderPosition(uint32_t *dspFrames); - - private: - friend class A2dpAudioInterface; - status_t init(); - status_t close(); - status_t close_l(); - status_t setAddress(const char* address); - status_t setBluetoothEnabled(bool enabled); - status_t setSuspended(bool onOff); - - private: - int mFd; - bool mStandby; - int mStartCount; - int mRetryCount; - char mA2dpAddress[20]; - void* mData; - Mutex mLock; - bool mBluetoothEnabled; - uint32_t mDevice; - bool mClosing; - bool mSuspended; - }; - - friend class A2dpAudioStreamOut; - - A2dpAudioStreamOut* mOutput; - AudioHardwareInterface *mHardwareInterface; - char mA2dpAddress[20]; - bool mBluetoothEnabled; - bool mSuspended; -}; - - -// ---------------------------------------------------------------------------- - -}; // namespace android - -#endif // A2DP_AUDIO_HARDWARE_H diff --git a/libs/audioflinger/Android.mk b/libs/audioflinger/Android.mk deleted file mode 100644 index 22ecc54..0000000 --- a/libs/audioflinger/Android.mk +++ /dev/null @@ -1,131 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -#AUDIO_POLICY_TEST := true -#ENABLE_AUDIO_DUMP := true - -include $(CLEAR_VARS) - - -ifeq ($(AUDIO_POLICY_TEST),true) - ENABLE_AUDIO_DUMP := true -endif - - -LOCAL_SRC_FILES:= \ - AudioHardwareGeneric.cpp \ - AudioHardwareStub.cpp \ - AudioHardwareInterface.cpp - -ifeq ($(ENABLE_AUDIO_DUMP),true) - LOCAL_SRC_FILES += AudioDumpInterface.cpp - LOCAL_CFLAGS += -DENABLE_AUDIO_DUMP -endif - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - libbinder \ - libmedia \ - libhardware_legacy - -ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true) - LOCAL_CFLAGS += -DGENERIC_AUDIO -endif - -LOCAL_MODULE:= libaudiointerface - -ifeq ($(BOARD_HAVE_BLUETOOTH),true) - LOCAL_SRC_FILES += A2dpAudioInterface.cpp - LOCAL_SHARED_LIBRARIES += liba2dp - LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP - LOCAL_C_INCLUDES += $(call include-path-for, bluez) -endif - -include $(BUILD_STATIC_LIBRARY) - - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - AudioPolicyManagerBase.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - libmedia - -ifeq ($(TARGET_SIMULATOR),true) - LOCAL_LDLIBS += -ldl -else - LOCAL_SHARED_LIBRARIES += libdl -endif - -LOCAL_MODULE:= libaudiopolicybase - -ifeq ($(BOARD_HAVE_BLUETOOTH),true) - LOCAL_CFLAGS += -DWITH_A2DP -endif - -ifeq ($(AUDIO_POLICY_TEST),true) - LOCAL_CFLAGS += -DAUDIO_POLICY_TEST -endif - -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - AudioFlinger.cpp \ - AudioMixer.cpp.arm \ - AudioResampler.cpp.arm \ - AudioResamplerSinc.cpp.arm \ - AudioResamplerCubic.cpp.arm \ - AudioPolicyService.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - libbinder \ - libmedia \ - libhardware_legacy \ - libeffects - -ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true) - LOCAL_STATIC_LIBRARIES += libaudiointerface libaudiopolicybase - LOCAL_CFLAGS += -DGENERIC_AUDIO -else - LOCAL_SHARED_LIBRARIES += libaudio libaudiopolicy -endif - -ifeq ($(TARGET_SIMULATOR),true) - LOCAL_LDLIBS += -ldl -else - LOCAL_SHARED_LIBRARIES += libdl -endif - -LOCAL_MODULE:= libaudioflinger - -ifeq ($(BOARD_HAVE_BLUETOOTH),true) - LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP - LOCAL_SHARED_LIBRARIES += liba2dp -endif - -ifeq ($(AUDIO_POLICY_TEST),true) - LOCAL_CFLAGS += -DAUDIO_POLICY_TEST -endif - -ifeq ($(TARGET_SIMULATOR),true) - ifeq ($(HOST_OS),linux) - LOCAL_LDLIBS += -lrt -lpthread - endif -endif - -ifeq ($(BOARD_USE_LVMX),true) - LOCAL_CFLAGS += -DLVMX - LOCAL_C_INCLUDES += vendor/nxp - LOCAL_STATIC_LIBRARIES += liblifevibes - LOCAL_SHARED_LIBRARIES += liblvmxservice -# LOCAL_SHARED_LIBRARIES += liblvmxipc -endif - -include $(BUILD_SHARED_LIBRARY) diff --git a/libs/audioflinger/AudioBufferProvider.h b/libs/audioflinger/AudioBufferProvider.h deleted file mode 100644 index 81c5c39..0000000 --- a/libs/audioflinger/AudioBufferProvider.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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. - */ - -#ifndef ANDROID_AUDIO_BUFFER_PROVIDER_H -#define ANDROID_AUDIO_BUFFER_PROVIDER_H - -#include <stdint.h> -#include <sys/types.h> -#include <utils/Errors.h> - -namespace android { -// ---------------------------------------------------------------------------- - -class AudioBufferProvider -{ -public: - - struct Buffer { - union { - void* raw; - short* i16; - int8_t* i8; - }; - size_t frameCount; - }; - - virtual ~AudioBufferProvider() {} - - virtual status_t getNextBuffer(Buffer* buffer) = 0; - virtual void releaseBuffer(Buffer* buffer) = 0; -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_AUDIO_BUFFER_PROVIDER_H diff --git a/libs/audioflinger/AudioDumpInterface.cpp b/libs/audioflinger/AudioDumpInterface.cpp deleted file mode 100644 index 6c11114..0000000 --- a/libs/audioflinger/AudioDumpInterface.cpp +++ /dev/null @@ -1,573 +0,0 @@ -/* //device/servers/AudioFlinger/AudioDumpInterface.cpp -** -** Copyright 2008, 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. -*/ - -#define LOG_TAG "AudioFlingerDump" -//#define LOG_NDEBUG 0 - -#include <stdint.h> -#include <sys/types.h> -#include <utils/Log.h> - -#include <stdlib.h> -#include <unistd.h> - -#include "AudioDumpInterface.h" - -namespace android { - -// ---------------------------------------------------------------------------- - -AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw) - : mPolicyCommands(String8("")), mFileName(String8("")) -{ - if(hw == 0) { - LOGE("Dump construct hw = 0"); - } - mFinalInterface = hw; - LOGV("Constructor %p, mFinalInterface %p", this, mFinalInterface); -} - - -AudioDumpInterface::~AudioDumpInterface() -{ - for (size_t i = 0; i < mOutputs.size(); i++) { - closeOutputStream((AudioStreamOut *)mOutputs[i]); - } - - for (size_t i = 0; i < mInputs.size(); i++) { - closeInputStream((AudioStreamIn *)mInputs[i]); - } - - if(mFinalInterface) delete mFinalInterface; -} - - -AudioStreamOut* AudioDumpInterface::openOutputStream( - uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status) -{ - AudioStreamOut* outFinal = NULL; - int lFormat = AudioSystem::PCM_16_BIT; - uint32_t lChannels = AudioSystem::CHANNEL_OUT_STEREO; - uint32_t lRate = 44100; - - - outFinal = mFinalInterface->openOutputStream(devices, format, channels, sampleRate, status); - if (outFinal != 0) { - lFormat = outFinal->format(); - lChannels = outFinal->channels(); - lRate = outFinal->sampleRate(); - } else { - if (format != 0) { - if (*format != 0) { - lFormat = *format; - } else { - *format = lFormat; - } - } - if (channels != 0) { - if (*channels != 0) { - lChannels = *channels; - } else { - *channels = lChannels; - } - } - if (sampleRate != 0) { - if (*sampleRate != 0) { - lRate = *sampleRate; - } else { - *sampleRate = lRate; - } - } - if (status) *status = NO_ERROR; - } - LOGV("openOutputStream(), outFinal %p", outFinal); - - AudioStreamOutDump *dumOutput = new AudioStreamOutDump(this, mOutputs.size(), outFinal, - devices, lFormat, lChannels, lRate); - mOutputs.add(dumOutput); - - return dumOutput; -} - -void AudioDumpInterface::closeOutputStream(AudioStreamOut* out) -{ - AudioStreamOutDump *dumpOut = (AudioStreamOutDump *)out; - - if (mOutputs.indexOf(dumpOut) < 0) { - LOGW("Attempt to close invalid output stream"); - return; - } - - LOGV("closeOutputStream() output %p", out); - - dumpOut->standby(); - if (dumpOut->finalStream() != NULL) { - mFinalInterface->closeOutputStream(dumpOut->finalStream()); - } - - mOutputs.remove(dumpOut); - delete dumpOut; -} - -AudioStreamIn* AudioDumpInterface::openInputStream(uint32_t devices, int *format, uint32_t *channels, - uint32_t *sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics) -{ - AudioStreamIn* inFinal = NULL; - int lFormat = AudioSystem::PCM_16_BIT; - uint32_t lChannels = AudioSystem::CHANNEL_IN_MONO; - uint32_t lRate = 8000; - - inFinal = mFinalInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics); - if (inFinal != 0) { - lFormat = inFinal->format(); - lChannels = inFinal->channels(); - lRate = inFinal->sampleRate(); - } else { - if (format != 0) { - if (*format != 0) { - lFormat = *format; - } else { - *format = lFormat; - } - } - if (channels != 0) { - if (*channels != 0) { - lChannels = *channels; - } else { - *channels = lChannels; - } - } - if (sampleRate != 0) { - if (*sampleRate != 0) { - lRate = *sampleRate; - } else { - *sampleRate = lRate; - } - } - if (status) *status = NO_ERROR; - } - LOGV("openInputStream(), inFinal %p", inFinal); - - AudioStreamInDump *dumInput = new AudioStreamInDump(this, mInputs.size(), inFinal, - devices, lFormat, lChannels, lRate); - mInputs.add(dumInput); - - return dumInput; -} -void AudioDumpInterface::closeInputStream(AudioStreamIn* in) -{ - AudioStreamInDump *dumpIn = (AudioStreamInDump *)in; - - if (mInputs.indexOf(dumpIn) < 0) { - LOGW("Attempt to close invalid input stream"); - return; - } - dumpIn->standby(); - if (dumpIn->finalStream() != NULL) { - mFinalInterface->closeInputStream(dumpIn->finalStream()); - } - - mInputs.remove(dumpIn); - delete dumpIn; -} - - -status_t AudioDumpInterface::setParameters(const String8& keyValuePairs) -{ - AudioParameter param = AudioParameter(keyValuePairs); - String8 value; - int valueInt; - LOGV("setParameters %s", keyValuePairs.string()); - - if (param.get(String8("test_cmd_file_name"), value) == NO_ERROR) { - mFileName = value; - param.remove(String8("test_cmd_file_name")); - } - if (param.get(String8("test_cmd_policy"), value) == NO_ERROR) { - Mutex::Autolock _l(mLock); - param.remove(String8("test_cmd_policy")); - mPolicyCommands = param.toString(); - LOGV("test_cmd_policy command %s written", mPolicyCommands.string()); - return NO_ERROR; - } - - if (mFinalInterface != 0 ) return mFinalInterface->setParameters(keyValuePairs); - return NO_ERROR; -} - -String8 AudioDumpInterface::getParameters(const String8& keys) -{ - AudioParameter param = AudioParameter(keys); - AudioParameter response; - String8 value; - -// LOGV("getParameters %s", keys.string()); - if (param.get(String8("test_cmd_policy"), value) == NO_ERROR) { - Mutex::Autolock _l(mLock); - if (mPolicyCommands.length() != 0) { - response = AudioParameter(mPolicyCommands); - response.addInt(String8("test_cmd_policy"), 1); - } else { - response.addInt(String8("test_cmd_policy"), 0); - } - param.remove(String8("test_cmd_policy")); -// LOGV("test_cmd_policy command %s read", mPolicyCommands.string()); - } - - if (param.get(String8("test_cmd_file_name"), value) == NO_ERROR) { - response.add(String8("test_cmd_file_name"), mFileName); - param.remove(String8("test_cmd_file_name")); - } - - String8 keyValuePairs = response.toString(); - - if (param.size() && mFinalInterface != 0 ) { - keyValuePairs += ";"; - keyValuePairs += mFinalInterface->getParameters(param.toString()); - } - - return keyValuePairs; -} - -status_t AudioDumpInterface::setMode(int mode) -{ - return mFinalInterface->setMode(mode); -} - -size_t AudioDumpInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount) -{ - return mFinalInterface->getInputBufferSize(sampleRate, format, channelCount); -} - -// ---------------------------------------------------------------------------- - -AudioStreamOutDump::AudioStreamOutDump(AudioDumpInterface *interface, - int id, - AudioStreamOut* finalStream, - uint32_t devices, - int format, - uint32_t channels, - uint32_t sampleRate) - : mInterface(interface), mId(id), - mSampleRate(sampleRate), mFormat(format), mChannels(channels), mLatency(0), mDevice(devices), - mBufferSize(1024), mFinalStream(finalStream), mFile(0), mFileCount(0) -{ - LOGV("AudioStreamOutDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream); -} - - -AudioStreamOutDump::~AudioStreamOutDump() -{ - LOGV("AudioStreamOutDump destructor"); - Close(); -} - -ssize_t AudioStreamOutDump::write(const void* buffer, size_t bytes) -{ - ssize_t ret; - - if (mFinalStream) { - ret = mFinalStream->write(buffer, bytes); - } else { - usleep((((bytes * 1000) / frameSize()) / sampleRate()) * 1000); - ret = bytes; - } - if(!mFile) { - if (mInterface->fileName() != "") { - char name[255]; - sprintf(name, "%s_out_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount); - mFile = fopen(name, "wb"); - LOGV("Opening dump file %s, fh %p", name, mFile); - } - } - if (mFile) { - fwrite(buffer, bytes, 1, mFile); - } - return ret; -} - -status_t AudioStreamOutDump::standby() -{ - LOGV("AudioStreamOutDump standby(), mFile %p, mFinalStream %p", mFile, mFinalStream); - - Close(); - if (mFinalStream != 0 ) return mFinalStream->standby(); - return NO_ERROR; -} - -uint32_t AudioStreamOutDump::sampleRate() const -{ - if (mFinalStream != 0 ) return mFinalStream->sampleRate(); - return mSampleRate; -} - -size_t AudioStreamOutDump::bufferSize() const -{ - if (mFinalStream != 0 ) return mFinalStream->bufferSize(); - return mBufferSize; -} - -uint32_t AudioStreamOutDump::channels() const -{ - if (mFinalStream != 0 ) return mFinalStream->channels(); - return mChannels; -} -int AudioStreamOutDump::format() const -{ - if (mFinalStream != 0 ) return mFinalStream->format(); - return mFormat; -} -uint32_t AudioStreamOutDump::latency() const -{ - if (mFinalStream != 0 ) return mFinalStream->latency(); - return 0; -} -status_t AudioStreamOutDump::setVolume(float left, float right) -{ - if (mFinalStream != 0 ) return mFinalStream->setVolume(left, right); - return NO_ERROR; -} -status_t AudioStreamOutDump::setParameters(const String8& keyValuePairs) -{ - LOGV("AudioStreamOutDump::setParameters %s", keyValuePairs.string()); - - if (mFinalStream != 0 ) { - return mFinalStream->setParameters(keyValuePairs); - } - - AudioParameter param = AudioParameter(keyValuePairs); - String8 value; - int valueInt; - status_t status = NO_ERROR; - - if (param.getInt(String8("set_id"), valueInt) == NO_ERROR) { - mId = valueInt; - } - - if (param.getInt(String8("format"), valueInt) == NO_ERROR) { - if (mFile == 0) { - mFormat = valueInt; - } else { - status = INVALID_OPERATION; - } - } - if (param.getInt(String8("channels"), valueInt) == NO_ERROR) { - if (valueInt == AudioSystem::CHANNEL_OUT_STEREO || valueInt == AudioSystem::CHANNEL_OUT_MONO) { - mChannels = valueInt; - } else { - status = BAD_VALUE; - } - } - if (param.getInt(String8("sampling_rate"), valueInt) == NO_ERROR) { - if (valueInt > 0 && valueInt <= 48000) { - if (mFile == 0) { - mSampleRate = valueInt; - } else { - status = INVALID_OPERATION; - } - } else { - status = BAD_VALUE; - } - } - return status; -} - -String8 AudioStreamOutDump::getParameters(const String8& keys) -{ - if (mFinalStream != 0 ) return mFinalStream->getParameters(keys); - - AudioParameter param = AudioParameter(keys); - return param.toString(); -} - -status_t AudioStreamOutDump::dump(int fd, const Vector<String16>& args) -{ - if (mFinalStream != 0 ) return mFinalStream->dump(fd, args); - return NO_ERROR; -} - -void AudioStreamOutDump::Close() -{ - if(mFile) { - fclose(mFile); - mFile = 0; - } -} - -status_t AudioStreamOutDump::getRenderPosition(uint32_t *dspFrames) -{ - if (mFinalStream != 0 ) return mFinalStream->getRenderPosition(dspFrames); - return INVALID_OPERATION; -} - -// ---------------------------------------------------------------------------- - -AudioStreamInDump::AudioStreamInDump(AudioDumpInterface *interface, - int id, - AudioStreamIn* finalStream, - uint32_t devices, - int format, - uint32_t channels, - uint32_t sampleRate) - : mInterface(interface), mId(id), - mSampleRate(sampleRate), mFormat(format), mChannels(channels), mDevice(devices), - mBufferSize(1024), mFinalStream(finalStream), mFile(0), mFileCount(0) -{ - LOGV("AudioStreamInDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream); -} - - -AudioStreamInDump::~AudioStreamInDump() -{ - Close(); -} - -ssize_t AudioStreamInDump::read(void* buffer, ssize_t bytes) -{ - ssize_t ret; - - if (mFinalStream) { - ret = mFinalStream->read(buffer, bytes); - if(!mFile) { - if (mInterface->fileName() != "") { - char name[255]; - sprintf(name, "%s_in_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount); - mFile = fopen(name, "wb"); - LOGV("Opening input dump file %s, fh %p", name, mFile); - } - } - if (mFile) { - fwrite(buffer, bytes, 1, mFile); - } - } else { - usleep((((bytes * 1000) / frameSize()) / sampleRate()) * 1000); - ret = bytes; - if(!mFile) { - char name[255]; - strcpy(name, "/sdcard/music/sine440"); - if (channels() == AudioSystem::CHANNEL_IN_MONO) { - strcat(name, "_mo"); - } else { - strcat(name, "_st"); - } - if (format() == AudioSystem::PCM_16_BIT) { - strcat(name, "_16b"); - } else { - strcat(name, "_8b"); - } - if (sampleRate() < 16000) { - strcat(name, "_8k"); - } else if (sampleRate() < 32000) { - strcat(name, "_22k"); - } else if (sampleRate() < 48000) { - strcat(name, "_44k"); - } else { - strcat(name, "_48k"); - } - strcat(name, ".wav"); - mFile = fopen(name, "rb"); - LOGV("Opening input read file %s, fh %p", name, mFile); - if (mFile) { - fseek(mFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET); - } - } - if (mFile) { - ssize_t bytesRead = fread(buffer, bytes, 1, mFile); - if (bytesRead >=0 && bytesRead < bytes) { - fseek(mFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET); - fread((uint8_t *)buffer+bytesRead, bytes-bytesRead, 1, mFile); - } - } - } - - return ret; -} - -status_t AudioStreamInDump::standby() -{ - LOGV("AudioStreamInDump standby(), mFile %p, mFinalStream %p", mFile, mFinalStream); - - Close(); - if (mFinalStream != 0 ) return mFinalStream->standby(); - return NO_ERROR; -} - -status_t AudioStreamInDump::setGain(float gain) -{ - if (mFinalStream != 0 ) return mFinalStream->setGain(gain); - return NO_ERROR; -} - -uint32_t AudioStreamInDump::sampleRate() const -{ - if (mFinalStream != 0 ) return mFinalStream->sampleRate(); - return mSampleRate; -} - -size_t AudioStreamInDump::bufferSize() const -{ - if (mFinalStream != 0 ) return mFinalStream->bufferSize(); - return mBufferSize; -} - -uint32_t AudioStreamInDump::channels() const -{ - if (mFinalStream != 0 ) return mFinalStream->channels(); - return mChannels; -} - -int AudioStreamInDump::format() const -{ - if (mFinalStream != 0 ) return mFinalStream->format(); - return mFormat; -} - -status_t AudioStreamInDump::setParameters(const String8& keyValuePairs) -{ - LOGV("AudioStreamInDump::setParameters()"); - if (mFinalStream != 0 ) return mFinalStream->setParameters(keyValuePairs); - return NO_ERROR; -} - -String8 AudioStreamInDump::getParameters(const String8& keys) -{ - if (mFinalStream != 0 ) return mFinalStream->getParameters(keys); - - AudioParameter param = AudioParameter(keys); - return param.toString(); -} - -unsigned int AudioStreamInDump::getInputFramesLost() const -{ - if (mFinalStream != 0 ) return mFinalStream->getInputFramesLost(); - return 0; -} - -status_t AudioStreamInDump::dump(int fd, const Vector<String16>& args) -{ - if (mFinalStream != 0 ) return mFinalStream->dump(fd, args); - return NO_ERROR; -} - -void AudioStreamInDump::Close() -{ - if(mFile) { - fclose(mFile); - mFile = 0; - } -} -}; // namespace android diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h deleted file mode 100644 index 814ce5f..0000000 --- a/libs/audioflinger/AudioDumpInterface.h +++ /dev/null @@ -1,170 +0,0 @@ -/* //device/servers/AudioFlinger/AudioDumpInterface.h -** -** Copyright 2008, 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. -*/ - -#ifndef ANDROID_AUDIO_DUMP_INTERFACE_H -#define ANDROID_AUDIO_DUMP_INTERFACE_H - -#include <stdint.h> -#include <sys/types.h> -#include <utils/String8.h> -#include <utils/SortedVector.h> - -#include <hardware_legacy/AudioHardwareBase.h> - -namespace android { - -#define AUDIO_DUMP_WAVE_HDR_SIZE 44 - -class AudioDumpInterface; - -class AudioStreamOutDump : public AudioStreamOut { -public: - AudioStreamOutDump(AudioDumpInterface *interface, - int id, - AudioStreamOut* finalStream, - uint32_t devices, - int format, - uint32_t channels, - uint32_t sampleRate); - ~AudioStreamOutDump(); - - virtual ssize_t write(const void* buffer, size_t bytes); - virtual uint32_t sampleRate() const; - virtual size_t bufferSize() const; - virtual uint32_t channels() const; - virtual int format() const; - virtual uint32_t latency() const; - virtual status_t setVolume(float left, float right); - virtual status_t standby(); - virtual status_t setParameters(const String8& keyValuePairs); - virtual String8 getParameters(const String8& keys); - virtual status_t dump(int fd, const Vector<String16>& args); - void Close(void); - AudioStreamOut* finalStream() { return mFinalStream; } - uint32_t device() { return mDevice; } - int getId() { return mId; } - virtual status_t getRenderPosition(uint32_t *dspFrames); - -private: - AudioDumpInterface *mInterface; - int mId; - uint32_t mSampleRate; // - uint32_t mFormat; // - uint32_t mChannels; // output configuration - uint32_t mLatency; // - uint32_t mDevice; // current device this output is routed to - size_t mBufferSize; - AudioStreamOut *mFinalStream; - FILE *mFile; // output file - int mFileCount; -}; - -class AudioStreamInDump : public AudioStreamIn { -public: - AudioStreamInDump(AudioDumpInterface *interface, - int id, - AudioStreamIn* finalStream, - uint32_t devices, - int format, - uint32_t channels, - uint32_t sampleRate); - ~AudioStreamInDump(); - - virtual uint32_t sampleRate() const; - virtual size_t bufferSize() const; - virtual uint32_t channels() const; - virtual int format() const; - - virtual status_t setGain(float gain); - virtual ssize_t read(void* buffer, ssize_t bytes); - virtual status_t standby(); - virtual status_t setParameters(const String8& keyValuePairs); - virtual String8 getParameters(const String8& keys); - virtual unsigned int getInputFramesLost() const; - virtual status_t dump(int fd, const Vector<String16>& args); - void Close(void); - AudioStreamIn* finalStream() { return mFinalStream; } - uint32_t device() { return mDevice; } - -private: - AudioDumpInterface *mInterface; - int mId; - uint32_t mSampleRate; // - uint32_t mFormat; // - uint32_t mChannels; // output configuration - uint32_t mDevice; // current device this output is routed to - size_t mBufferSize; - AudioStreamIn *mFinalStream; - FILE *mFile; // output file - int mFileCount; -}; - -class AudioDumpInterface : public AudioHardwareBase -{ - -public: - AudioDumpInterface(AudioHardwareInterface* hw); - virtual AudioStreamOut* openOutputStream( - uint32_t devices, - int *format=0, - uint32_t *channels=0, - uint32_t *sampleRate=0, - status_t *status=0); - virtual void closeOutputStream(AudioStreamOut* out); - - virtual ~AudioDumpInterface(); - - virtual status_t initCheck() - {return mFinalInterface->initCheck();} - virtual status_t setVoiceVolume(float volume) - {return mFinalInterface->setVoiceVolume(volume);} - virtual status_t setMasterVolume(float volume) - {return mFinalInterface->setMasterVolume(volume);} - - virtual status_t setMode(int mode); - - // mic mute - virtual status_t setMicMute(bool state) - {return mFinalInterface->setMicMute(state);} - virtual status_t getMicMute(bool* state) - {return mFinalInterface->getMicMute(state);} - - virtual status_t setParameters(const String8& keyValuePairs); - virtual String8 getParameters(const String8& keys); - - virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount); - - virtual AudioStreamIn* openInputStream(uint32_t devices, int *format, uint32_t *channels, - uint32_t *sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics); - virtual void closeInputStream(AudioStreamIn* in); - - virtual status_t dump(int fd, const Vector<String16>& args) { return mFinalInterface->dumpState(fd, args); } - - String8 fileName() const { return mFileName; } -protected: - - AudioHardwareInterface *mFinalInterface; - SortedVector<AudioStreamOutDump *> mOutputs; - SortedVector<AudioStreamInDump *> mInputs; - Mutex mLock; - String8 mPolicyCommands; - String8 mFileName; -}; - -}; // namespace android - -#endif // ANDROID_AUDIO_DUMP_INTERFACE_H diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp deleted file mode 100644 index 97eb6c0..0000000 --- a/libs/audioflinger/AudioFlinger.cpp +++ /dev/null @@ -1,6078 +0,0 @@ -/* //device/include/server/AudioFlinger/AudioFlinger.cpp -** -** Copyright 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. -*/ - - -#define LOG_TAG "AudioFlinger" -//#define LOG_NDEBUG 0 - -#include <math.h> -#include <signal.h> -#include <sys/time.h> -#include <sys/resource.h> - -#include <binder/IServiceManager.h> -#include <utils/Log.h> -#include <binder/Parcel.h> -#include <binder/IPCThreadState.h> -#include <utils/String16.h> -#include <utils/threads.h> - -#include <cutils/properties.h> - -#include <media/AudioTrack.h> -#include <media/AudioRecord.h> - -#include <private/media/AudioTrackShared.h> -#include <private/media/AudioEffectShared.h> -#include <hardware_legacy/AudioHardwareInterface.h> - -#include "AudioMixer.h" -#include "AudioFlinger.h" - -#ifdef WITH_A2DP -#include "A2dpAudioInterface.h" -#endif - -#ifdef LVMX -#include "lifevibes.h" -#endif - -#include <media/EffectsFactoryApi.h> -#include <media/EffectVisualizerApi.h> - -// ---------------------------------------------------------------------------- -// the sim build doesn't have gettid - -#ifndef HAVE_GETTID -# define gettid getpid -#endif - -// ---------------------------------------------------------------------------- - -namespace android { - -static const char* kDeadlockedString = "AudioFlinger may be deadlocked\n"; -static const char* kHardwareLockedString = "Hardware lock is taken\n"; - -//static const nsecs_t kStandbyTimeInNsecs = seconds(3); -static const float MAX_GAIN = 4096.0f; -static const float MAX_GAIN_INT = 0x1000; - -// retry counts for buffer fill timeout -// 50 * ~20msecs = 1 second -static const int8_t kMaxTrackRetries = 50; -static const int8_t kMaxTrackStartupRetries = 50; -// allow less retry attempts on direct output thread. -// direct outputs can be a scarce resource in audio hardware and should -// be released as quickly as possible. -static const int8_t kMaxTrackRetriesDirect = 2; - -static const int kDumpLockRetries = 50; -static const int kDumpLockSleep = 20000; - -static const nsecs_t kWarningThrottle = seconds(5); - - -#define AUDIOFLINGER_SECURITY_ENABLED 1 - -// ---------------------------------------------------------------------------- - -static bool recordingAllowed() { -#ifndef HAVE_ANDROID_OS - return true; -#endif -#if AUDIOFLINGER_SECURITY_ENABLED - if (getpid() == IPCThreadState::self()->getCallingPid()) return true; - bool ok = checkCallingPermission(String16("android.permission.RECORD_AUDIO")); - if (!ok) LOGE("Request requires android.permission.RECORD_AUDIO"); - return ok; -#else - if (!checkCallingPermission(String16("android.permission.RECORD_AUDIO"))) - LOGW("WARNING: Need to add android.permission.RECORD_AUDIO to manifest"); - return true; -#endif -} - -static bool settingsAllowed() { -#ifndef HAVE_ANDROID_OS - return true; -#endif -#if AUDIOFLINGER_SECURITY_ENABLED - if (getpid() == IPCThreadState::self()->getCallingPid()) return true; - bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS")); - if (!ok) LOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS"); - return ok; -#else - if (!checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS"))) - LOGW("WARNING: Need to add android.permission.MODIFY_AUDIO_SETTINGS to manifest"); - return true; -#endif -} - -// ---------------------------------------------------------------------------- - -AudioFlinger::AudioFlinger() - : BnAudioFlinger(), - mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1), - mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0) -{ - mHardwareStatus = AUDIO_HW_IDLE; - - mAudioHardware = AudioHardwareInterface::create(); - - mHardwareStatus = AUDIO_HW_INIT; - if (mAudioHardware->initCheck() == NO_ERROR) { - // open 16-bit output stream for s/w mixer - mMode = AudioSystem::MODE_NORMAL; - setMode(mMode); - - setMasterVolume(1.0f); - setMasterMute(false); - } else { - LOGE("Couldn't even initialize the stubbed audio hardware!"); - } -#ifdef LVMX - LifeVibes::init(); - mLifeVibesClientPid = -1; -#endif -} - -AudioFlinger::~AudioFlinger() -{ - while (!mRecordThreads.isEmpty()) { - // closeInput() will remove first entry from mRecordThreads - closeInput(mRecordThreads.keyAt(0)); - } - while (!mPlaybackThreads.isEmpty()) { - // closeOutput() will remove first entry from mPlaybackThreads - closeOutput(mPlaybackThreads.keyAt(0)); - } - if (mAudioHardware) { - delete mAudioHardware; - } -} - - - -status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - - result.append("Clients:\n"); - for (size_t i = 0; i < mClients.size(); ++i) { - wp<Client> wClient = mClients.valueAt(i); - if (wClient != 0) { - sp<Client> client = wClient.promote(); - if (client != 0) { - snprintf(buffer, SIZE, " pid: %d\n", client->pid()); - result.append(buffer); - } - } - } - write(fd, result.string(), result.size()); - return NO_ERROR; -} - - -status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - int hardwareStatus = mHardwareStatus; - - snprintf(buffer, SIZE, "Hardware status: %d\n", hardwareStatus); - result.append(buffer); - write(fd, result.string(), result.size()); - return NO_ERROR; -} - -status_t AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - snprintf(buffer, SIZE, "Permission Denial: " - "can't dump AudioFlinger from pid=%d, uid=%d\n", - IPCThreadState::self()->getCallingPid(), - IPCThreadState::self()->getCallingUid()); - result.append(buffer); - write(fd, result.string(), result.size()); - return NO_ERROR; -} - -static bool tryLock(Mutex& mutex) -{ - bool locked = false; - for (int i = 0; i < kDumpLockRetries; ++i) { - if (mutex.tryLock() == NO_ERROR) { - locked = true; - break; - } - usleep(kDumpLockSleep); - } - return locked; -} - -status_t AudioFlinger::dump(int fd, const Vector<String16>& args) -{ - if (checkCallingPermission(String16("android.permission.DUMP")) == false) { - dumpPermissionDenial(fd, args); - } else { - // get state of hardware lock - bool hardwareLocked = tryLock(mHardwareLock); - if (!hardwareLocked) { - String8 result(kHardwareLockedString); - write(fd, result.string(), result.size()); - } else { - mHardwareLock.unlock(); - } - - bool locked = tryLock(mLock); - - // failed to lock - AudioFlinger is probably deadlocked - if (!locked) { - String8 result(kDeadlockedString); - write(fd, result.string(), result.size()); - } - - dumpClients(fd, args); - dumpInternals(fd, args); - - // dump playback threads - for (size_t i = 0; i < mPlaybackThreads.size(); i++) { - mPlaybackThreads.valueAt(i)->dump(fd, args); - } - - // dump record threads - for (size_t i = 0; i < mRecordThreads.size(); i++) { - mRecordThreads.valueAt(i)->dump(fd, args); - } - - if (mAudioHardware) { - mAudioHardware->dumpState(fd, args); - } - if (locked) mLock.unlock(); - } - return NO_ERROR; -} - - -// IAudioFlinger interface - - -sp<IAudioTrack> AudioFlinger::createTrack( - pid_t pid, - int streamType, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - uint32_t flags, - const sp<IMemory>& sharedBuffer, - int output, - int *sessionId, - status_t *status) -{ - sp<PlaybackThread::Track> track; - sp<TrackHandle> trackHandle; - sp<Client> client; - wp<Client> wclient; - status_t lStatus; - int lSessionId; - - if (streamType >= AudioSystem::NUM_STREAM_TYPES) { - LOGE("invalid stream type"); - lStatus = BAD_VALUE; - goto Exit; - } - - { - Mutex::Autolock _l(mLock); - PlaybackThread *thread = checkPlaybackThread_l(output); - if (thread == NULL) { - LOGE("unknown output thread"); - lStatus = BAD_VALUE; - goto Exit; - } - - wclient = mClients.valueFor(pid); - - if (wclient != NULL) { - client = wclient.promote(); - } else { - client = new Client(this, pid); - mClients.add(pid, client); - } - - // If no audio session id is provided, create one here - // TODO: enforce same stream type for all tracks in same audio session? - // TODO: prevent same audio session on different output threads - LOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId); - if (sessionId != NULL && *sessionId != 0) { - lSessionId = *sessionId; - } else { - lSessionId = nextUniqueId(); - if (sessionId != NULL) { - *sessionId = lSessionId; - } - } - LOGV("createTrack() lSessionId: %d", lSessionId); - - track = thread->createTrack_l(client, streamType, sampleRate, format, - channelCount, frameCount, sharedBuffer, lSessionId, &lStatus); - } - if (lStatus == NO_ERROR) { - trackHandle = new TrackHandle(track); - } else { - // remove local strong reference to Client before deleting the Track so that the Client - // destructor is called by the TrackBase destructor with mLock held - client.clear(); - track.clear(); - } - -Exit: - if(status) { - *status = lStatus; - } - return trackHandle; -} - -uint32_t AudioFlinger::sampleRate(int output) const -{ - Mutex::Autolock _l(mLock); - PlaybackThread *thread = checkPlaybackThread_l(output); - if (thread == NULL) { - LOGW("sampleRate() unknown thread %d", output); - return 0; - } - return thread->sampleRate(); -} - -int AudioFlinger::channelCount(int output) const -{ - Mutex::Autolock _l(mLock); - PlaybackThread *thread = checkPlaybackThread_l(output); - if (thread == NULL) { - LOGW("channelCount() unknown thread %d", output); - return 0; - } - return thread->channelCount(); -} - -int AudioFlinger::format(int output) const -{ - Mutex::Autolock _l(mLock); - PlaybackThread *thread = checkPlaybackThread_l(output); - if (thread == NULL) { - LOGW("format() unknown thread %d", output); - return 0; - } - return thread->format(); -} - -size_t AudioFlinger::frameCount(int output) const -{ - Mutex::Autolock _l(mLock); - PlaybackThread *thread = checkPlaybackThread_l(output); - if (thread == NULL) { - LOGW("frameCount() unknown thread %d", output); - return 0; - } - return thread->frameCount(); -} - -uint32_t AudioFlinger::latency(int output) const -{ - Mutex::Autolock _l(mLock); - PlaybackThread *thread = checkPlaybackThread_l(output); - if (thread == NULL) { - LOGW("latency() unknown thread %d", output); - return 0; - } - return thread->latency(); -} - -status_t AudioFlinger::setMasterVolume(float value) -{ - // check calling permissions - if (!settingsAllowed()) { - return PERMISSION_DENIED; - } - - // when hw supports master volume, don't scale in sw mixer - AutoMutex lock(mHardwareLock); - mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; - if (mAudioHardware->setMasterVolume(value) == NO_ERROR) { - value = 1.0f; - } - mHardwareStatus = AUDIO_HW_IDLE; - - mMasterVolume = value; - for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) - mPlaybackThreads.valueAt(i)->setMasterVolume(value); - - return NO_ERROR; -} - -status_t AudioFlinger::setMode(int mode) -{ - status_t ret; - - // check calling permissions - if (!settingsAllowed()) { - return PERMISSION_DENIED; - } - if ((mode < 0) || (mode >= AudioSystem::NUM_MODES)) { - LOGW("Illegal value: setMode(%d)", mode); - return BAD_VALUE; - } - - { // scope for the lock - AutoMutex lock(mHardwareLock); - mHardwareStatus = AUDIO_HW_SET_MODE; - ret = mAudioHardware->setMode(mode); - mHardwareStatus = AUDIO_HW_IDLE; - } - - if (NO_ERROR == ret) { - Mutex::Autolock _l(mLock); - mMode = mode; - for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) - mPlaybackThreads.valueAt(i)->setMode(mode); -#ifdef LVMX - LifeVibes::setMode(mode); -#endif - } - - return ret; -} - -status_t AudioFlinger::setMicMute(bool state) -{ - // check calling permissions - if (!settingsAllowed()) { - return PERMISSION_DENIED; - } - - AutoMutex lock(mHardwareLock); - mHardwareStatus = AUDIO_HW_SET_MIC_MUTE; - status_t ret = mAudioHardware->setMicMute(state); - mHardwareStatus = AUDIO_HW_IDLE; - return ret; -} - -bool AudioFlinger::getMicMute() const -{ - bool state = AudioSystem::MODE_INVALID; - mHardwareStatus = AUDIO_HW_GET_MIC_MUTE; - mAudioHardware->getMicMute(&state); - mHardwareStatus = AUDIO_HW_IDLE; - return state; -} - -status_t AudioFlinger::setMasterMute(bool muted) -{ - // check calling permissions - if (!settingsAllowed()) { - return PERMISSION_DENIED; - } - - mMasterMute = muted; - for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) - mPlaybackThreads.valueAt(i)->setMasterMute(muted); - - return NO_ERROR; -} - -float AudioFlinger::masterVolume() const -{ - return mMasterVolume; -} - -bool AudioFlinger::masterMute() const -{ - return mMasterMute; -} - -status_t AudioFlinger::setStreamVolume(int stream, float value, int output) -{ - // check calling permissions - if (!settingsAllowed()) { - return PERMISSION_DENIED; - } - - if (stream < 0 || uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) { - return BAD_VALUE; - } - - AutoMutex lock(mLock); - PlaybackThread *thread = NULL; - if (output) { - thread = checkPlaybackThread_l(output); - if (thread == NULL) { - return BAD_VALUE; - } - } - - mStreamTypes[stream].volume = value; - - if (thread == NULL) { - for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) { - mPlaybackThreads.valueAt(i)->setStreamVolume(stream, value); - } - } else { - thread->setStreamVolume(stream, value); - } - - return NO_ERROR; -} - -status_t AudioFlinger::setStreamMute(int stream, bool muted) -{ - // check calling permissions - if (!settingsAllowed()) { - return PERMISSION_DENIED; - } - - if (stream < 0 || uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES || - uint32_t(stream) == AudioSystem::ENFORCED_AUDIBLE) { - return BAD_VALUE; - } - - mStreamTypes[stream].mute = muted; - for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) - mPlaybackThreads.valueAt(i)->setStreamMute(stream, muted); - - return NO_ERROR; -} - -float AudioFlinger::streamVolume(int stream, int output) const -{ - if (stream < 0 || uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) { - return 0.0f; - } - - AutoMutex lock(mLock); - float volume; - if (output) { - PlaybackThread *thread = checkPlaybackThread_l(output); - if (thread == NULL) { - return 0.0f; - } - volume = thread->streamVolume(stream); - } else { - volume = mStreamTypes[stream].volume; - } - - return volume; -} - -bool AudioFlinger::streamMute(int stream) const -{ - if (stream < 0 || stream >= (int)AudioSystem::NUM_STREAM_TYPES) { - return true; - } - - return mStreamTypes[stream].mute; -} - -bool AudioFlinger::isStreamActive(int stream) const -{ - Mutex::Autolock _l(mLock); - for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) { - if (mPlaybackThreads.valueAt(i)->isStreamActive(stream)) { - return true; - } - } - return false; -} - -status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs) -{ - status_t result; - - LOGV("setParameters(): io %d, keyvalue %s, tid %d, calling tid %d", - ioHandle, keyValuePairs.string(), gettid(), IPCThreadState::self()->getCallingPid()); - // check calling permissions - if (!settingsAllowed()) { - return PERMISSION_DENIED; - } - -#ifdef LVMX - AudioParameter param = AudioParameter(keyValuePairs); - LifeVibes::setParameters(ioHandle,keyValuePairs); - String8 key = String8(AudioParameter::keyRouting); - int device; - if (NO_ERROR != param.getInt(key, device)) { - device = -1; - } - - key = String8(LifevibesTag); - String8 value; - int musicEnabled = -1; - if (NO_ERROR == param.get(key, value)) { - if (value == LifevibesEnable) { - mLifeVibesClientPid = IPCThreadState::self()->getCallingPid(); - musicEnabled = 1; - } else if (value == LifevibesDisable) { - mLifeVibesClientPid = -1; - musicEnabled = 0; - } - } -#endif - - // ioHandle == 0 means the parameters are global to the audio hardware interface - if (ioHandle == 0) { - AutoMutex lock(mHardwareLock); - mHardwareStatus = AUDIO_SET_PARAMETER; - result = mAudioHardware->setParameters(keyValuePairs); -#ifdef LVMX - if (musicEnabled != -1) { - LifeVibes::enableMusic((bool) musicEnabled); - } -#endif - mHardwareStatus = AUDIO_HW_IDLE; - return result; - } - - // hold a strong ref on thread in case closeOutput() or closeInput() is called - // and the thread is exited once the lock is released - sp<ThreadBase> thread; - { - Mutex::Autolock _l(mLock); - thread = checkPlaybackThread_l(ioHandle); - if (thread == NULL) { - thread = checkRecordThread_l(ioHandle); - } - } - if (thread != NULL) { - result = thread->setParameters(keyValuePairs); -#ifdef LVMX - if ((NO_ERROR == result) && (device != -1)) { - LifeVibes::setDevice(LifeVibes::threadIdToAudioOutputType(thread->id()), device); - } -#endif - return result; - } - return BAD_VALUE; -} - -String8 AudioFlinger::getParameters(int ioHandle, const String8& keys) -{ -// LOGV("getParameters() io %d, keys %s, tid %d, calling tid %d", -// ioHandle, keys.string(), gettid(), IPCThreadState::self()->getCallingPid()); - - if (ioHandle == 0) { - return mAudioHardware->getParameters(keys); - } - - Mutex::Autolock _l(mLock); - - PlaybackThread *playbackThread = checkPlaybackThread_l(ioHandle); - if (playbackThread != NULL) { - return playbackThread->getParameters(keys); - } - RecordThread *recordThread = checkRecordThread_l(ioHandle); - if (recordThread != NULL) { - return recordThread->getParameters(keys); - } - return String8(""); -} - -size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int channelCount) -{ - return mAudioHardware->getInputBufferSize(sampleRate, format, channelCount); -} - -unsigned int AudioFlinger::getInputFramesLost(int ioHandle) -{ - if (ioHandle == 0) { - return 0; - } - - Mutex::Autolock _l(mLock); - - RecordThread *recordThread = checkRecordThread_l(ioHandle); - if (recordThread != NULL) { - return recordThread->getInputFramesLost(); - } - return 0; -} - -status_t AudioFlinger::setVoiceVolume(float value) -{ - // check calling permissions - if (!settingsAllowed()) { - return PERMISSION_DENIED; - } - - AutoMutex lock(mHardwareLock); - mHardwareStatus = AUDIO_SET_VOICE_VOLUME; - status_t ret = mAudioHardware->setVoiceVolume(value); - mHardwareStatus = AUDIO_HW_IDLE; - - return ret; -} - -status_t AudioFlinger::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output) -{ - status_t status; - - Mutex::Autolock _l(mLock); - - PlaybackThread *playbackThread = checkPlaybackThread_l(output); - if (playbackThread != NULL) { - return playbackThread->getRenderPosition(halFrames, dspFrames); - } - - return BAD_VALUE; -} - -void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client) -{ - - Mutex::Autolock _l(mLock); - - int pid = IPCThreadState::self()->getCallingPid(); - if (mNotificationClients.indexOfKey(pid) < 0) { - sp<NotificationClient> notificationClient = new NotificationClient(this, - client, - pid); - LOGV("registerClient() client %p, pid %d", notificationClient.get(), pid); - - mNotificationClients.add(pid, notificationClient); - - sp<IBinder> binder = client->asBinder(); - binder->linkToDeath(notificationClient); - - // the config change is always sent from playback or record threads to avoid deadlock - // with AudioSystem::gLock - for (size_t i = 0; i < mPlaybackThreads.size(); i++) { - mPlaybackThreads.valueAt(i)->sendConfigEvent(AudioSystem::OUTPUT_OPENED); - } - - for (size_t i = 0; i < mRecordThreads.size(); i++) { - mRecordThreads.valueAt(i)->sendConfigEvent(AudioSystem::INPUT_OPENED); - } - } -} - -void AudioFlinger::removeNotificationClient(pid_t pid) -{ - Mutex::Autolock _l(mLock); - - int index = mNotificationClients.indexOfKey(pid); - if (index >= 0) { - sp <NotificationClient> client = mNotificationClients.valueFor(pid); - LOGV("removeNotificationClient() %p, pid %d", client.get(), pid); -#ifdef LVMX - if (pid == mLifeVibesClientPid) { - LOGV("Disabling lifevibes"); - LifeVibes::enableMusic(false); - mLifeVibesClientPid = -1; - } -#endif - mNotificationClients.removeItem(pid); - } -} - -// audioConfigChanged_l() must be called with AudioFlinger::mLock held -void AudioFlinger::audioConfigChanged_l(int event, int ioHandle, void *param2) -{ - size_t size = mNotificationClients.size(); - for (size_t i = 0; i < size; i++) { - mNotificationClients.valueAt(i)->client()->ioConfigChanged(event, ioHandle, param2); - } -} - -// removeClient_l() must be called with AudioFlinger::mLock held -void AudioFlinger::removeClient_l(pid_t pid) -{ - LOGV("removeClient_l() pid %d, tid %d, calling tid %d", pid, gettid(), IPCThreadState::self()->getCallingPid()); - mClients.removeItem(pid); -} - - -// ---------------------------------------------------------------------------- - -AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, int id) - : Thread(false), - mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mChannelCount(0), - mFrameSize(1), mFormat(0), mStandby(false), mId(id), mExiting(false) -{ -} - -AudioFlinger::ThreadBase::~ThreadBase() -{ - mParamCond.broadcast(); - mNewParameters.clear(); -} - -void AudioFlinger::ThreadBase::exit() -{ - // keep a strong ref on ourself so that we wont get - // destroyed in the middle of requestExitAndWait() - sp <ThreadBase> strongMe = this; - - LOGV("ThreadBase::exit"); - { - AutoMutex lock(&mLock); - mExiting = true; - requestExit(); - mWaitWorkCV.signal(); - } - requestExitAndWait(); -} - -uint32_t AudioFlinger::ThreadBase::sampleRate() const -{ - return mSampleRate; -} - -int AudioFlinger::ThreadBase::channelCount() const -{ - return (int)mChannelCount; -} - -int AudioFlinger::ThreadBase::format() const -{ - return mFormat; -} - -size_t AudioFlinger::ThreadBase::frameCount() const -{ - return mFrameCount; -} - -status_t AudioFlinger::ThreadBase::setParameters(const String8& keyValuePairs) -{ - status_t status; - - LOGV("ThreadBase::setParameters() %s", keyValuePairs.string()); - Mutex::Autolock _l(mLock); - - mNewParameters.add(keyValuePairs); - mWaitWorkCV.signal(); - // wait condition with timeout in case the thread loop has exited - // before the request could be processed - if (mParamCond.waitRelative(mLock, seconds(2)) == NO_ERROR) { - status = mParamStatus; - mWaitWorkCV.signal(); - } else { - status = TIMED_OUT; - } - return status; -} - -void AudioFlinger::ThreadBase::sendConfigEvent(int event, int param) -{ - Mutex::Autolock _l(mLock); - sendConfigEvent_l(event, param); -} - -// sendConfigEvent_l() must be called with ThreadBase::mLock held -void AudioFlinger::ThreadBase::sendConfigEvent_l(int event, int param) -{ - ConfigEvent *configEvent = new ConfigEvent(); - configEvent->mEvent = event; - configEvent->mParam = param; - mConfigEvents.add(configEvent); - LOGV("sendConfigEvent() num events %d event %d, param %d", mConfigEvents.size(), event, param); - mWaitWorkCV.signal(); -} - -void AudioFlinger::ThreadBase::processConfigEvents() -{ - mLock.lock(); - while(!mConfigEvents.isEmpty()) { - LOGV("processConfigEvents() remaining events %d", mConfigEvents.size()); - ConfigEvent *configEvent = mConfigEvents[0]; - mConfigEvents.removeAt(0); - // release mLock before locking AudioFlinger mLock: lock order is always - // AudioFlinger then ThreadBase to avoid cross deadlock - mLock.unlock(); - mAudioFlinger->mLock.lock(); - audioConfigChanged_l(configEvent->mEvent, configEvent->mParam); - mAudioFlinger->mLock.unlock(); - delete configEvent; - mLock.lock(); - } - mLock.unlock(); -} - -status_t AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - - bool locked = tryLock(mLock); - if (!locked) { - snprintf(buffer, SIZE, "thread %p maybe dead locked\n", this); - write(fd, buffer, strlen(buffer)); - } - - snprintf(buffer, SIZE, "standby: %d\n", mStandby); - result.append(buffer); - snprintf(buffer, SIZE, "Sample rate: %d\n", mSampleRate); - result.append(buffer); - snprintf(buffer, SIZE, "Frame count: %d\n", mFrameCount); - result.append(buffer); - snprintf(buffer, SIZE, "Channel Count: %d\n", mChannelCount); - result.append(buffer); - snprintf(buffer, SIZE, "Format: %d\n", mFormat); - result.append(buffer); - snprintf(buffer, SIZE, "Frame size: %d\n", mFrameSize); - result.append(buffer); - - snprintf(buffer, SIZE, "\nPending setParameters commands: \n"); - result.append(buffer); - result.append(" Index Command"); - for (size_t i = 0; i < mNewParameters.size(); ++i) { - snprintf(buffer, SIZE, "\n %02d ", i); - result.append(buffer); - result.append(mNewParameters[i]); - } - - snprintf(buffer, SIZE, "\n\nPending config events: \n"); - result.append(buffer); - snprintf(buffer, SIZE, " Index event param\n"); - result.append(buffer); - for (size_t i = 0; i < mConfigEvents.size(); i++) { - snprintf(buffer, SIZE, " %02d %02d %d\n", i, mConfigEvents[i]->mEvent, mConfigEvents[i]->mParam); - result.append(buffer); - } - result.append("\n"); - - write(fd, result.string(), result.size()); - - if (locked) { - mLock.unlock(); - } - return NO_ERROR; -} - - -// ---------------------------------------------------------------------------- - -AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device) - : ThreadBase(audioFlinger, id), - mMixBuffer(0), mSuspended(0), mBytesWritten(0), mOutput(output), - mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false), - mDevice(device) -{ - readOutputParameters(); - - mMasterVolume = mAudioFlinger->masterVolume(); - mMasterMute = mAudioFlinger->masterMute(); - - for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { - mStreamTypes[stream].volume = mAudioFlinger->streamVolumeInternal(stream); - mStreamTypes[stream].mute = mAudioFlinger->streamMute(stream); - } -} - -AudioFlinger::PlaybackThread::~PlaybackThread() -{ - delete [] mMixBuffer; -} - -status_t AudioFlinger::PlaybackThread::dump(int fd, const Vector<String16>& args) -{ - dumpInternals(fd, args); - dumpTracks(fd, args); - dumpEffectChains(fd, args); - return NO_ERROR; -} - -status_t AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - - snprintf(buffer, SIZE, "Output thread %p tracks\n", this); - result.append(buffer); - result.append(" Name Clien Typ Fmt Chn Session Buf S M F SRate LeftV RighV Serv User Main buf Aux Buf\n"); - for (size_t i = 0; i < mTracks.size(); ++i) { - sp<Track> track = mTracks[i]; - if (track != 0) { - track->dump(buffer, SIZE); - result.append(buffer); - } - } - - snprintf(buffer, SIZE, "Output thread %p active tracks\n", this); - result.append(buffer); - result.append(" Name Clien Typ Fmt Chn Session Buf S M F SRate LeftV RighV Serv User Main buf Aux Buf\n"); - for (size_t i = 0; i < mActiveTracks.size(); ++i) { - wp<Track> wTrack = mActiveTracks[i]; - if (wTrack != 0) { - sp<Track> track = wTrack.promote(); - if (track != 0) { - track->dump(buffer, SIZE); - result.append(buffer); - } - } - } - write(fd, result.string(), result.size()); - return NO_ERROR; -} - -status_t AudioFlinger::PlaybackThread::dumpEffectChains(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - - snprintf(buffer, SIZE, "\n- %d Effect Chains:\n", mEffectChains.size()); - write(fd, buffer, strlen(buffer)); - - for (size_t i = 0; i < mEffectChains.size(); ++i) { - sp<EffectChain> chain = mEffectChains[i]; - if (chain != 0) { - chain->dump(fd, args); - } - } - return NO_ERROR; -} - -status_t AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - - snprintf(buffer, SIZE, "\nOutput thread %p internals\n", this); - result.append(buffer); - snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime)); - result.append(buffer); - snprintf(buffer, SIZE, "total writes: %d\n", mNumWrites); - result.append(buffer); - snprintf(buffer, SIZE, "delayed writes: %d\n", mNumDelayedWrites); - result.append(buffer); - snprintf(buffer, SIZE, "blocked in write: %d\n", mInWrite); - result.append(buffer); - snprintf(buffer, SIZE, "suspend count: %d\n", mSuspended); - result.append(buffer); - snprintf(buffer, SIZE, "mix buffer : %p\n", mMixBuffer); - result.append(buffer); - write(fd, result.string(), result.size()); - - dumpBase(fd, args); - - return NO_ERROR; -} - -// Thread virtuals -status_t AudioFlinger::PlaybackThread::readyToRun() -{ - if (mSampleRate == 0) { - LOGE("No working audio driver found."); - return NO_INIT; - } - LOGI("AudioFlinger's thread %p ready to run", this); - return NO_ERROR; -} - -void AudioFlinger::PlaybackThread::onFirstRef() -{ - const size_t SIZE = 256; - char buffer[SIZE]; - - snprintf(buffer, SIZE, "Playback Thread %p", this); - - run(buffer, ANDROID_PRIORITY_URGENT_AUDIO); -} - -// PlaybackThread::createTrack_l() must be called with AudioFlinger::mLock held -sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l( - const sp<AudioFlinger::Client>& client, - int streamType, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - const sp<IMemory>& sharedBuffer, - int sessionId, - status_t *status) -{ - sp<Track> track; - status_t lStatus; - - if (mType == DIRECT) { - if (sampleRate != mSampleRate || format != mFormat || channelCount != (int)mChannelCount) { - LOGE("createTrack_l() Bad parameter: sampleRate %d format %d, channelCount %d for output %p", - sampleRate, format, channelCount, mOutput); - lStatus = BAD_VALUE; - goto Exit; - } - } else { - // Resampler implementation limits input sampling rate to 2 x output sampling rate. - if (sampleRate > mSampleRate*2) { - LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate); - lStatus = BAD_VALUE; - goto Exit; - } - } - - if (mOutput == 0) { - LOGE("Audio driver not initialized."); - lStatus = NO_INIT; - goto Exit; - } - - { // scope for mLock - Mutex::Autolock _l(mLock); - track = new Track(this, client, streamType, sampleRate, format, - channelCount, frameCount, sharedBuffer, sessionId); - if (track->getCblk() == NULL || track->name() < 0) { - lStatus = NO_MEMORY; - goto Exit; - } - mTracks.add(track); - - sp<EffectChain> chain = getEffectChain_l(sessionId); - if (chain != 0) { - LOGV("createTrack_l() setting main buffer %p", chain->inBuffer()); - track->setMainBuffer(chain->inBuffer()); - } - } - lStatus = NO_ERROR; - -Exit: - if(status) { - *status = lStatus; - } - return track; -} - -uint32_t AudioFlinger::PlaybackThread::latency() const -{ - if (mOutput) { - return mOutput->latency(); - } - else { - return 0; - } -} - -status_t AudioFlinger::PlaybackThread::setMasterVolume(float value) -{ -#ifdef LVMX - int audioOutputType = LifeVibes::getMixerType(mId, mType); - if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { - LifeVibes::setMasterVolume(audioOutputType, value); - } -#endif - mMasterVolume = value; - return NO_ERROR; -} - -status_t AudioFlinger::PlaybackThread::setMasterMute(bool muted) -{ -#ifdef LVMX - int audioOutputType = LifeVibes::getMixerType(mId, mType); - if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { - LifeVibes::setMasterMute(audioOutputType, muted); - } -#endif - mMasterMute = muted; - return NO_ERROR; -} - -float AudioFlinger::PlaybackThread::masterVolume() const -{ - return mMasterVolume; -} - -bool AudioFlinger::PlaybackThread::masterMute() const -{ - return mMasterMute; -} - -status_t AudioFlinger::PlaybackThread::setStreamVolume(int stream, float value) -{ -#ifdef LVMX - int audioOutputType = LifeVibes::getMixerType(mId, mType); - if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { - LifeVibes::setStreamVolume(audioOutputType, stream, value); - } -#endif - mStreamTypes[stream].volume = value; - return NO_ERROR; -} - -status_t AudioFlinger::PlaybackThread::setStreamMute(int stream, bool muted) -{ -#ifdef LVMX - int audioOutputType = LifeVibes::getMixerType(mId, mType); - if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { - LifeVibes::setStreamMute(audioOutputType, stream, muted); - } -#endif - mStreamTypes[stream].mute = muted; - return NO_ERROR; -} - -float AudioFlinger::PlaybackThread::streamVolume(int stream) const -{ - return mStreamTypes[stream].volume; -} - -bool AudioFlinger::PlaybackThread::streamMute(int stream) const -{ - return mStreamTypes[stream].mute; -} - -bool AudioFlinger::PlaybackThread::isStreamActive(int stream) const -{ - Mutex::Autolock _l(mLock); - size_t count = mActiveTracks.size(); - for (size_t i = 0 ; i < count ; ++i) { - sp<Track> t = mActiveTracks[i].promote(); - if (t == 0) continue; - Track* const track = t.get(); - if (t->type() == stream) - return true; - } - return false; -} - -// addTrack_l() must be called with ThreadBase::mLock held -status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track) -{ - status_t status = ALREADY_EXISTS; - - // set retry count for buffer fill - track->mRetryCount = kMaxTrackStartupRetries; - if (mActiveTracks.indexOf(track) < 0) { - // the track is newly added, make sure it fills up all its - // buffers before playing. This is to ensure the client will - // effectively get the latency it requested. - track->mFillingUpStatus = Track::FS_FILLING; - track->mResetDone = false; - mActiveTracks.add(track); - if (track->mainBuffer() != mMixBuffer) { - sp<EffectChain> chain = getEffectChain_l(track->sessionId()); - if (chain != 0) { - LOGV("addTrack_l() starting track on chain %p for session %d", chain.get(), track->sessionId()); - chain->startTrack(); - } - } - - status = NO_ERROR; - } - - LOGV("mWaitWorkCV.broadcast"); - mWaitWorkCV.broadcast(); - - return status; -} - -// destroyTrack_l() must be called with ThreadBase::mLock held -void AudioFlinger::PlaybackThread::destroyTrack_l(const sp<Track>& track) -{ - track->mState = TrackBase::TERMINATED; - if (mActiveTracks.indexOf(track) < 0) { - mTracks.remove(track); - deleteTrackName_l(track->name()); - } -} - -String8 AudioFlinger::PlaybackThread::getParameters(const String8& keys) -{ - return mOutput->getParameters(keys); -} - -// destroyTrack_l() must be called with AudioFlinger::mLock held -void AudioFlinger::PlaybackThread::audioConfigChanged_l(int event, int param) { - AudioSystem::OutputDescriptor desc; - void *param2 = 0; - - LOGV("PlaybackThread::audioConfigChanged_l, thread %p, event %d, param %d", this, event, param); - - switch (event) { - case AudioSystem::OUTPUT_OPENED: - case AudioSystem::OUTPUT_CONFIG_CHANGED: - desc.channels = mChannels; - desc.samplingRate = mSampleRate; - desc.format = mFormat; - desc.frameCount = mFrameCount; - desc.latency = latency(); - param2 = &desc; - break; - - case AudioSystem::STREAM_CONFIG_CHANGED: - param2 = ¶m; - case AudioSystem::OUTPUT_CLOSED: - default: - break; - } - mAudioFlinger->audioConfigChanged_l(event, mId, param2); -} - -void AudioFlinger::PlaybackThread::readOutputParameters() -{ - mSampleRate = mOutput->sampleRate(); - mChannels = mOutput->channels(); - mChannelCount = (uint16_t)AudioSystem::popCount(mChannels); - mFormat = mOutput->format(); - mFrameSize = (uint16_t)mOutput->frameSize(); - mFrameCount = mOutput->bufferSize() / mFrameSize; - - // FIXME - Current mixer implementation only supports stereo output: Always - // Allocate a stereo buffer even if HW output is mono. - if (mMixBuffer != NULL) delete[] mMixBuffer; - mMixBuffer = new int16_t[mFrameCount * 2]; - memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t)); - - //TODO handle effects reconfig -} - -status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames) -{ - if (halFrames == 0 || dspFrames == 0) { - return BAD_VALUE; - } - if (mOutput == 0) { - return INVALID_OPERATION; - } - *halFrames = mBytesWritten/mOutput->frameSize(); - - return mOutput->getRenderPosition(dspFrames); -} - -bool AudioFlinger::PlaybackThread::hasAudioSession(int sessionId) -{ - Mutex::Autolock _l(mLock); - if (getEffectChain_l(sessionId) != 0) { - return true; - } - - for (size_t i = 0; i < mTracks.size(); ++i) { - sp<Track> track = mTracks[i]; - if (sessionId == track->sessionId()) { - return true; - } - } - - return false; -} - -sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain(int sessionId) -{ - Mutex::Autolock _l(mLock); - return getEffectChain_l(sessionId); -} - -sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain_l(int sessionId) -{ - sp<EffectChain> chain; - - size_t size = mEffectChains.size(); - for (size_t i = 0; i < size; i++) { - if (mEffectChains[i]->sessionId() == sessionId) { - chain = mEffectChains[i]; - break; - } - } - return chain; -} - -void AudioFlinger::PlaybackThread::setMode(uint32_t mode) -{ - Mutex::Autolock _l(mLock); - size_t size = mEffectChains.size(); - for (size_t i = 0; i < size; i++) { - mEffectChains[i]->setMode(mode); - } -} - -// ---------------------------------------------------------------------------- - -AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device) - : PlaybackThread(audioFlinger, output, id, device), - mAudioMixer(0) -{ - mType = PlaybackThread::MIXER; - mAudioMixer = new AudioMixer(mFrameCount, mSampleRate); - - // FIXME - Current mixer implementation only supports stereo output - if (mChannelCount == 1) { - LOGE("Invalid audio hardware channel count"); - } -} - -AudioFlinger::MixerThread::~MixerThread() -{ - delete mAudioMixer; -} - -bool AudioFlinger::MixerThread::threadLoop() -{ - Vector< sp<Track> > tracksToRemove; - uint32_t mixerStatus = MIXER_IDLE; - nsecs_t standbyTime = systemTime(); - size_t mixBufferSize = mFrameCount * mFrameSize; - // FIXME: Relaxed timing because of a certain device that can't meet latency - // Should be reduced to 2x after the vendor fixes the driver issue - nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 3; - nsecs_t lastWarning = 0; - bool longStandbyExit = false; - uint32_t activeSleepTime = activeSleepTimeUs(); - uint32_t idleSleepTime = idleSleepTimeUs(); - uint32_t sleepTime = idleSleepTime; - Vector< sp<EffectChain> > effectChains; - - while (!exitPending()) - { - processConfigEvents(); - - mixerStatus = MIXER_IDLE; - { // scope for mLock - - Mutex::Autolock _l(mLock); - - if (checkForNewParameters_l()) { - mixBufferSize = mFrameCount * mFrameSize; - // FIXME: Relaxed timing because of a certain device that can't meet latency - // Should be reduced to 2x after the vendor fixes the driver issue - maxPeriod = seconds(mFrameCount) / mSampleRate * 3; - activeSleepTime = activeSleepTimeUs(); - idleSleepTime = idleSleepTimeUs(); - } - - const SortedVector< wp<Track> >& activeTracks = mActiveTracks; - - // put audio hardware into standby after short delay - if UNLIKELY((!activeTracks.size() && systemTime() > standbyTime) || - mSuspended) { - if (!mStandby) { - LOGV("Audio hardware entering standby, mixer %p, mSuspended %d\n", this, mSuspended); - mOutput->standby(); - mStandby = true; - mBytesWritten = 0; - } - - if (!activeTracks.size() && mConfigEvents.isEmpty()) { - // we're about to wait, flush the binder command buffer - IPCThreadState::self()->flushCommands(); - - if (exitPending()) break; - - // wait until we have something to do... - LOGV("MixerThread %p TID %d going to sleep\n", this, gettid()); - mWaitWorkCV.wait(mLock); - LOGV("MixerThread %p TID %d waking up\n", this, gettid()); - - if (mMasterMute == false) { - char value[PROPERTY_VALUE_MAX]; - property_get("ro.audio.silent", value, "0"); - if (atoi(value)) { - LOGD("Silence is golden"); - setMasterMute(true); - } - } - - standbyTime = systemTime() + kStandbyTimeInNsecs; - sleepTime = idleSleepTime; - continue; - } - } - - mixerStatus = prepareTracks_l(activeTracks, &tracksToRemove); - - // prevent any changes in effect chain list and in each effect chain - // during mixing and effect process as the audio buffers could be deleted - // or modified if an effect is created or deleted - effectChains = mEffectChains; - lockEffectChains_l(); - } - - if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) { - // mix buffers... - mAudioMixer->process(); - sleepTime = 0; - standbyTime = systemTime() + kStandbyTimeInNsecs; - //TODO: delay standby when effects have a tail - } else { - // If no tracks are ready, sleep once for the duration of an output - // buffer size, then write 0s to the output - if (sleepTime == 0) { - if (mixerStatus == MIXER_TRACKS_ENABLED) { - sleepTime = activeSleepTime; - } else { - sleepTime = idleSleepTime; - } - } else if (mBytesWritten != 0 || - (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)) { - memset (mMixBuffer, 0, mixBufferSize); - sleepTime = 0; - LOGV_IF((mBytesWritten == 0 && (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)), "anticipated start"); - } - // TODO add standby time extension fct of effect tail - } - - if (mSuspended) { - sleepTime = idleSleepTime; - } - // sleepTime == 0 means we must write to audio hardware - if (sleepTime == 0) { - for (size_t i = 0; i < effectChains.size(); i ++) { - effectChains[i]->process_l(); - } - // enable changes in effect chain - unlockEffectChains(); -#ifdef LVMX - int audioOutputType = LifeVibes::getMixerType(mId, mType); - if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { - LifeVibes::process(audioOutputType, mMixBuffer, mixBufferSize); - } -#endif - mLastWriteTime = systemTime(); - mInWrite = true; - mBytesWritten += mixBufferSize; - - int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize); - if (bytesWritten < 0) mBytesWritten -= mixBufferSize; - mNumWrites++; - mInWrite = false; - nsecs_t now = systemTime(); - nsecs_t delta = now - mLastWriteTime; - if (delta > maxPeriod) { - mNumDelayedWrites++; - if ((now - lastWarning) > kWarningThrottle) { - LOGW("write blocked for %llu msecs, %d delayed writes, thread %p", - ns2ms(delta), mNumDelayedWrites, this); - lastWarning = now; - } - if (mStandby) { - longStandbyExit = true; - } - } - mStandby = false; - } else { - // enable changes in effect chain - unlockEffectChains(); - usleep(sleepTime); - } - - // finally let go of all our tracks, without the lock held - // since we can't guarantee the destructors won't acquire that - // same lock. - tracksToRemove.clear(); - - // Effect chains will be actually deleted here if they were removed from - // mEffectChains list during mixing or effects processing - effectChains.clear(); - } - - if (!mStandby) { - mOutput->standby(); - } - - LOGV("MixerThread %p exiting", this); - return false; -} - -// prepareTracks_l() must be called with ThreadBase::mLock held -uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove) -{ - - uint32_t mixerStatus = MIXER_IDLE; - // find out which tracks need to be processed - size_t count = activeTracks.size(); - size_t mixedTracks = 0; - size_t tracksWithEffect = 0; - - float masterVolume = mMasterVolume; - bool masterMute = mMasterMute; - -#ifdef LVMX - bool tracksConnectedChanged = false; - bool stateChanged = false; - - int audioOutputType = LifeVibes::getMixerType(mId, mType); - if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) - { - int activeTypes = 0; - for (size_t i=0 ; i<count ; i++) { - sp<Track> t = activeTracks[i].promote(); - if (t == 0) continue; - Track* const track = t.get(); - int iTracktype=track->type(); - activeTypes |= 1<<track->type(); - } - LifeVibes::computeVolumes(audioOutputType, activeTypes, tracksConnectedChanged, stateChanged, masterVolume, masterMute); - } -#endif - // Delegate master volume control to effect in output mix effect chain if needed - sp<EffectChain> chain = getEffectChain_l(0); - if (chain != 0) { - uint32_t v = (uint32_t)(masterVolume * (1 << 24)); - chain->setVolume(&v, &v); - masterVolume = (float)((v + (1 << 23)) >> 24); - chain.clear(); - } - - for (size_t i=0 ; i<count ; i++) { - sp<Track> t = activeTracks[i].promote(); - if (t == 0) continue; - - Track* const track = t.get(); - audio_track_cblk_t* cblk = track->cblk(); - - // The first time a track is added we wait - // for all its buffers to be filled before processing it - mAudioMixer->setActiveTrack(track->name()); - if (cblk->framesReady() && (track->isReady() || track->isStopped()) && - !track->isPaused() && !track->isTerminated()) - { - //LOGV("track %d u=%08x, s=%08x [OK] on thread %p", track->name(), cblk->user, cblk->server, this); - - mixedTracks++; - - // track->mainBuffer() != mMixBuffer means there is an effect chain - // connected to the track - chain.clear(); - if (track->mainBuffer() != mMixBuffer) { - chain = getEffectChain_l(track->sessionId()); - // Delegate volume control to effect in track effect chain if needed - if (chain != 0) { - tracksWithEffect++; - } else { - LOGW("prepareTracks_l(): track %08x attached to effect but no chain found on session %d", - track->name(), track->sessionId()); - } - } - - - int param = AudioMixer::VOLUME; - if (track->mFillingUpStatus == Track::FS_FILLED) { - // no ramp for the first volume setting - track->mFillingUpStatus = Track::FS_ACTIVE; - if (track->mState == TrackBase::RESUMING) { - track->mState = TrackBase::ACTIVE; - param = AudioMixer::RAMP_VOLUME; - } - } else if (cblk->server != 0) { - // If the track is stopped before the first frame was mixed, - // do not apply ramp - param = AudioMixer::RAMP_VOLUME; - } - - // compute volume for this track - int16_t left, right, aux; - if (track->isMuted() || masterMute || track->isPausing() || - mStreamTypes[track->type()].mute) { - left = right = aux = 0; - if (track->isPausing()) { - track->setPaused(); - } - } else { - // read original volumes with volume control - float typeVolume = mStreamTypes[track->type()].volume; -#ifdef LVMX - bool streamMute=false; - // read the volume from the LivesVibes audio engine. - if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) - { - LifeVibes::getStreamVolumes(audioOutputType, track->type(), &typeVolume, &streamMute); - if (streamMute) { - typeVolume = 0; - } - } -#endif - float v = masterVolume * typeVolume; - uint32_t vl = (uint32_t)(v * cblk->volume[0]) << 12; - uint32_t vr = (uint32_t)(v * cblk->volume[1]) << 12; - - // Delegate volume control to effect in track effect chain if needed - if (chain != 0 && chain->setVolume(&vl, &vr)) { - // Do not ramp volume is volume is controlled by effect - param = AudioMixer::VOLUME; - } - - // Convert volumes from 8.24 to 4.12 format - uint32_t v_clamped = (vl + (1 << 11)) >> 12; - if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT; - left = int16_t(v_clamped); - v_clamped = (vr + (1 << 11)) >> 12; - if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT; - right = int16_t(v_clamped); - - v_clamped = (uint32_t)(v * cblk->sendLevel); - if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT; - aux = int16_t(v_clamped); - } - -#ifdef LVMX - if ( tracksConnectedChanged || stateChanged ) - { - // only do the ramp when the volume is changed by the user / application - param = AudioMixer::VOLUME; - } -#endif - - // XXX: these things DON'T need to be done each time - mAudioMixer->setBufferProvider(track); - mAudioMixer->enable(AudioMixer::MIXING); - - mAudioMixer->setParameter(param, AudioMixer::VOLUME0, (void *)left); - mAudioMixer->setParameter(param, AudioMixer::VOLUME1, (void *)right); - mAudioMixer->setParameter(param, AudioMixer::AUXLEVEL, (void *)aux); - mAudioMixer->setParameter( - AudioMixer::TRACK, - AudioMixer::FORMAT, (void *)track->format()); - mAudioMixer->setParameter( - AudioMixer::TRACK, - AudioMixer::CHANNEL_COUNT, (void *)track->channelCount()); - mAudioMixer->setParameter( - AudioMixer::RESAMPLE, - AudioMixer::SAMPLE_RATE, - (void *)(cblk->sampleRate)); - mAudioMixer->setParameter( - AudioMixer::TRACK, - AudioMixer::MAIN_BUFFER, (void *)track->mainBuffer()); - mAudioMixer->setParameter( - AudioMixer::TRACK, - AudioMixer::AUX_BUFFER, (void *)track->auxBuffer()); - - // reset retry count - track->mRetryCount = kMaxTrackRetries; - mixerStatus = MIXER_TRACKS_READY; - } else { - //LOGV("track %d u=%08x, s=%08x [NOT READY] on thread %p", track->name(), cblk->user, cblk->server, this); - if (track->isStopped()) { - track->reset(); - } - if (track->isTerminated() || track->isStopped() || track->isPaused()) { - // We have consumed all the buffers of this track. - // Remove it from the list of active tracks. - tracksToRemove->add(track); - } else { - // No buffers for this track. Give it a few chances to - // fill a buffer, then remove it from active list. - if (--(track->mRetryCount) <= 0) { - LOGV("BUFFER TIMEOUT: remove(%d) from active list on thread %p", track->name(), this); - tracksToRemove->add(track); - } else if (mixerStatus != MIXER_TRACKS_READY) { - mixerStatus = MIXER_TRACKS_ENABLED; - } - } - mAudioMixer->disable(AudioMixer::MIXING); - } - } - - // remove all the tracks that need to be... - count = tracksToRemove->size(); - if (UNLIKELY(count)) { - for (size_t i=0 ; i<count ; i++) { - const sp<Track>& track = tracksToRemove->itemAt(i); - mActiveTracks.remove(track); - if (track->mainBuffer() != mMixBuffer) { - chain = getEffectChain_l(track->sessionId()); - if (chain != 0) { - LOGV("stopping track on chain %p for session Id: %d", chain.get(), track->sessionId()); - chain->stopTrack(); - } - } - if (track->isTerminated()) { - mTracks.remove(track); - deleteTrackName_l(track->mName); - } - } - } - - // mix buffer must be cleared if all tracks are connected to an - // effect chain as in this case the mixer will not write to - // mix buffer and track effects will accumulate into it - if (mixedTracks != 0 && mixedTracks == tracksWithEffect) { - memset(mMixBuffer, 0, mFrameCount * mChannelCount * sizeof(int16_t)); - } - - return mixerStatus; -} - -void AudioFlinger::MixerThread::invalidateTracks(int streamType) -{ - LOGV ("MixerThread::invalidateTracks() mixer %p, streamType %d, mTracks.size %d", this, streamType, mTracks.size()); - Mutex::Autolock _l(mLock); - size_t size = mTracks.size(); - for (size_t i = 0; i < size; i++) { - sp<Track> t = mTracks[i]; - if (t->type() == streamType) { - t->mCblk->lock.lock(); - t->mCblk->flags |= CBLK_INVALID_ON; - t->mCblk->cv.signal(); - t->mCblk->lock.unlock(); - } - } -} - - -// getTrackName_l() must be called with ThreadBase::mLock held -int AudioFlinger::MixerThread::getTrackName_l() -{ - return mAudioMixer->getTrackName(); -} - -// deleteTrackName_l() must be called with ThreadBase::mLock held -void AudioFlinger::MixerThread::deleteTrackName_l(int name) -{ - LOGV("remove track (%d) and delete from mixer", name); - mAudioMixer->deleteTrackName(name); -} - -// checkForNewParameters_l() must be called with ThreadBase::mLock held -bool AudioFlinger::MixerThread::checkForNewParameters_l() -{ - bool reconfig = false; - - while (!mNewParameters.isEmpty()) { - status_t status = NO_ERROR; - String8 keyValuePair = mNewParameters[0]; - AudioParameter param = AudioParameter(keyValuePair); - int value; - - if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) { - reconfig = true; - } - if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) { - if (value != AudioSystem::PCM_16_BIT) { - status = BAD_VALUE; - } else { - reconfig = true; - } - } - if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) { - if (value != AudioSystem::CHANNEL_OUT_STEREO) { - status = BAD_VALUE; - } else { - reconfig = true; - } - } - if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) { - // do not accept frame count changes if tracks are open as the track buffer - // size depends on frame count and correct behavior would not be garantied - // if frame count is changed after track creation - if (!mTracks.isEmpty()) { - status = INVALID_OPERATION; - } else { - reconfig = true; - } - } - if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) { - // forward device change to effects that have requested to be - // aware of attached audio device. - mDevice = (uint32_t)value; - for (size_t i = 0; i < mEffectChains.size(); i++) { - mEffectChains[i]->setDevice(mDevice); - } - } - - if (status == NO_ERROR) { - status = mOutput->setParameters(keyValuePair); - if (!mStandby && status == INVALID_OPERATION) { - mOutput->standby(); - mStandby = true; - mBytesWritten = 0; - status = mOutput->setParameters(keyValuePair); - } - if (status == NO_ERROR && reconfig) { - delete mAudioMixer; - readOutputParameters(); - mAudioMixer = new AudioMixer(mFrameCount, mSampleRate); - for (size_t i = 0; i < mTracks.size() ; i++) { - int name = getTrackName_l(); - if (name < 0) break; - mTracks[i]->mName = name; - // limit track sample rate to 2 x new output sample rate - if (mTracks[i]->mCblk->sampleRate > 2 * sampleRate()) { - mTracks[i]->mCblk->sampleRate = 2 * sampleRate(); - } - } - sendConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED); - } - } - - mNewParameters.removeAt(0); - - mParamStatus = status; - mParamCond.signal(); - mWaitWorkCV.wait(mLock); - } - return reconfig; -} - -status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - - PlaybackThread::dumpInternals(fd, args); - - snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", mAudioMixer->trackNames()); - result.append(buffer); - write(fd, result.string(), result.size()); - return NO_ERROR; -} - -uint32_t AudioFlinger::MixerThread::activeSleepTimeUs() -{ - return (uint32_t)(mOutput->latency() * 1000) / 2; -} - -uint32_t AudioFlinger::MixerThread::idleSleepTimeUs() -{ - return (uint32_t)((mFrameCount * 1000) / mSampleRate) * 1000; -} - -// ---------------------------------------------------------------------------- -AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device) - : PlaybackThread(audioFlinger, output, id, device) -{ - mType = PlaybackThread::DIRECT; -} - -AudioFlinger::DirectOutputThread::~DirectOutputThread() -{ -} - - -static inline int16_t clamp16(int32_t sample) -{ - if ((sample>>15) ^ (sample>>31)) - sample = 0x7FFF ^ (sample>>31); - return sample; -} - -static inline -int32_t mul(int16_t in, int16_t v) -{ -#if defined(__arm__) && !defined(__thumb__) - int32_t out; - asm( "smulbb %[out], %[in], %[v] \n" - : [out]"=r"(out) - : [in]"%r"(in), [v]"r"(v) - : ); - return out; -#else - return in * int32_t(v); -#endif -} - -void AudioFlinger::DirectOutputThread::applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp) -{ - // Do not apply volume on compressed audio - if (!AudioSystem::isLinearPCM(mFormat)) { - return; - } - - // convert to signed 16 bit before volume calculation - if (mFormat == AudioSystem::PCM_8_BIT) { - size_t count = mFrameCount * mChannelCount; - uint8_t *src = (uint8_t *)mMixBuffer + count-1; - int16_t *dst = mMixBuffer + count-1; - while(count--) { - *dst-- = (int16_t)(*src--^0x80) << 8; - } - } - - size_t frameCount = mFrameCount; - int16_t *out = mMixBuffer; - if (ramp) { - if (mChannelCount == 1) { - int32_t d = ((int32_t)leftVol - (int32_t)mLeftVolShort) << 16; - int32_t vlInc = d / (int32_t)frameCount; - int32_t vl = ((int32_t)mLeftVolShort << 16); - do { - out[0] = clamp16(mul(out[0], vl >> 16) >> 12); - out++; - vl += vlInc; - } while (--frameCount); - - } else { - int32_t d = ((int32_t)leftVol - (int32_t)mLeftVolShort) << 16; - int32_t vlInc = d / (int32_t)frameCount; - d = ((int32_t)rightVol - (int32_t)mRightVolShort) << 16; - int32_t vrInc = d / (int32_t)frameCount; - int32_t vl = ((int32_t)mLeftVolShort << 16); - int32_t vr = ((int32_t)mRightVolShort << 16); - do { - out[0] = clamp16(mul(out[0], vl >> 16) >> 12); - out[1] = clamp16(mul(out[1], vr >> 16) >> 12); - out += 2; - vl += vlInc; - vr += vrInc; - } while (--frameCount); - } - } else { - if (mChannelCount == 1) { - do { - out[0] = clamp16(mul(out[0], leftVol) >> 12); - out++; - } while (--frameCount); - } else { - do { - out[0] = clamp16(mul(out[0], leftVol) >> 12); - out[1] = clamp16(mul(out[1], rightVol) >> 12); - out += 2; - } while (--frameCount); - } - } - - // convert back to unsigned 8 bit after volume calculation - if (mFormat == AudioSystem::PCM_8_BIT) { - size_t count = mFrameCount * mChannelCount; - int16_t *src = mMixBuffer; - uint8_t *dst = (uint8_t *)mMixBuffer; - while(count--) { - *dst++ = (uint8_t)(((int32_t)*src++ + (1<<7)) >> 8)^0x80; - } - } - - mLeftVolShort = leftVol; - mRightVolShort = rightVol; -} - -bool AudioFlinger::DirectOutputThread::threadLoop() -{ - uint32_t mixerStatus = MIXER_IDLE; - sp<Track> trackToRemove; - sp<Track> activeTrack; - nsecs_t standbyTime = systemTime(); - int8_t *curBuf; - size_t mixBufferSize = mFrameCount*mFrameSize; - uint32_t activeSleepTime = activeSleepTimeUs(); - uint32_t idleSleepTime = idleSleepTimeUs(); - uint32_t sleepTime = idleSleepTime; - // use shorter standby delay as on normal output to release - // hardware resources as soon as possible - nsecs_t standbyDelay = microseconds(activeSleepTime*2); - - - while (!exitPending()) - { - bool rampVolume; - uint16_t leftVol; - uint16_t rightVol; - Vector< sp<EffectChain> > effectChains; - - processConfigEvents(); - - mixerStatus = MIXER_IDLE; - - { // scope for the mLock - - Mutex::Autolock _l(mLock); - - if (checkForNewParameters_l()) { - mixBufferSize = mFrameCount*mFrameSize; - activeSleepTime = activeSleepTimeUs(); - idleSleepTime = idleSleepTimeUs(); - standbyDelay = microseconds(activeSleepTime*2); - } - - // put audio hardware into standby after short delay - if UNLIKELY((!mActiveTracks.size() && systemTime() > standbyTime) || - mSuspended) { - // wait until we have something to do... - if (!mStandby) { - LOGV("Audio hardware entering standby, mixer %p\n", this); - mOutput->standby(); - mStandby = true; - mBytesWritten = 0; - } - - if (!mActiveTracks.size() && mConfigEvents.isEmpty()) { - // we're about to wait, flush the binder command buffer - IPCThreadState::self()->flushCommands(); - - if (exitPending()) break; - - LOGV("DirectOutputThread %p TID %d going to sleep\n", this, gettid()); - mWaitWorkCV.wait(mLock); - LOGV("DirectOutputThread %p TID %d waking up in active mode\n", this, gettid()); - - if (mMasterMute == false) { - char value[PROPERTY_VALUE_MAX]; - property_get("ro.audio.silent", value, "0"); - if (atoi(value)) { - LOGD("Silence is golden"); - setMasterMute(true); - } - } - - standbyTime = systemTime() + standbyDelay; - sleepTime = idleSleepTime; - continue; - } - } - - effectChains = mEffectChains; - - // find out which tracks need to be processed - if (mActiveTracks.size() != 0) { - sp<Track> t = mActiveTracks[0].promote(); - if (t == 0) continue; - - Track* const track = t.get(); - audio_track_cblk_t* cblk = track->cblk(); - - // The first time a track is added we wait - // for all its buffers to be filled before processing it - if (cblk->framesReady() && (track->isReady() || track->isStopped()) && - !track->isPaused() && !track->isTerminated()) - { - //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server); - - if (track->mFillingUpStatus == Track::FS_FILLED) { - track->mFillingUpStatus = Track::FS_ACTIVE; - mLeftVolFloat = mRightVolFloat = 0; - mLeftVolShort = mRightVolShort = 0; - if (track->mState == TrackBase::RESUMING) { - track->mState = TrackBase::ACTIVE; - rampVolume = true; - } - } else if (cblk->server != 0) { - // If the track is stopped before the first frame was mixed, - // do not apply ramp - rampVolume = true; - } - // compute volume for this track - float left, right; - if (track->isMuted() || mMasterMute || track->isPausing() || - mStreamTypes[track->type()].mute) { - left = right = 0; - if (track->isPausing()) { - track->setPaused(); - } - } else { - float typeVolume = mStreamTypes[track->type()].volume; - float v = mMasterVolume * typeVolume; - float v_clamped = v * cblk->volume[0]; - if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN; - left = v_clamped/MAX_GAIN; - v_clamped = v * cblk->volume[1]; - if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN; - right = v_clamped/MAX_GAIN; - } - - if (left != mLeftVolFloat || right != mRightVolFloat) { - mLeftVolFloat = left; - mRightVolFloat = right; - - // If audio HAL implements volume control, - // force software volume to nominal value - if (mOutput->setVolume(left, right) == NO_ERROR) { - left = 1.0f; - right = 1.0f; - } - - // Convert volumes from float to 8.24 - uint32_t vl = (uint32_t)(left * (1 << 24)); - uint32_t vr = (uint32_t)(right * (1 << 24)); - - // Delegate volume control to effect in track effect chain if needed - // only one effect chain can be present on DirectOutputThread, so if - // there is one, the track is connected to it - if (!effectChains.isEmpty()) { - // Do not ramp volume is volume is controlled by effect - if(effectChains[0]->setVolume(&vl, &vr)) { - rampVolume = false; - } - } - - // Convert volumes from 8.24 to 4.12 format - uint32_t v_clamped = (vl + (1 << 11)) >> 12; - if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT; - leftVol = (uint16_t)v_clamped; - v_clamped = (vr + (1 << 11)) >> 12; - if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT; - rightVol = (uint16_t)v_clamped; - } else { - leftVol = mLeftVolShort; - rightVol = mRightVolShort; - rampVolume = false; - } - - // reset retry count - track->mRetryCount = kMaxTrackRetriesDirect; - activeTrack = t; - mixerStatus = MIXER_TRACKS_READY; - } else { - //LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server); - if (track->isStopped()) { - track->reset(); - } - if (track->isTerminated() || track->isStopped() || track->isPaused()) { - // We have consumed all the buffers of this track. - // Remove it from the list of active tracks. - trackToRemove = track; - } else { - // No buffers for this track. Give it a few chances to - // fill a buffer, then remove it from active list. - if (--(track->mRetryCount) <= 0) { - LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name()); - trackToRemove = track; - } else { - mixerStatus = MIXER_TRACKS_ENABLED; - } - } - } - } - - // remove all the tracks that need to be... - if (UNLIKELY(trackToRemove != 0)) { - mActiveTracks.remove(trackToRemove); - if (!effectChains.isEmpty()) { - LOGV("stopping track on chain %p for session Id: %d", effectChains[0].get(), trackToRemove->sessionId()); - effectChains[0]->stopTrack(); - } - if (trackToRemove->isTerminated()) { - mTracks.remove(trackToRemove); - deleteTrackName_l(trackToRemove->mName); - } - } - - lockEffectChains_l(); - } - - if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) { - AudioBufferProvider::Buffer buffer; - size_t frameCount = mFrameCount; - curBuf = (int8_t *)mMixBuffer; - // output audio to hardware - while (frameCount) { - buffer.frameCount = frameCount; - activeTrack->getNextBuffer(&buffer); - if (UNLIKELY(buffer.raw == 0)) { - memset(curBuf, 0, frameCount * mFrameSize); - break; - } - memcpy(curBuf, buffer.raw, buffer.frameCount * mFrameSize); - frameCount -= buffer.frameCount; - curBuf += buffer.frameCount * mFrameSize; - activeTrack->releaseBuffer(&buffer); - } - sleepTime = 0; - standbyTime = systemTime() + standbyDelay; - } else { - if (sleepTime == 0) { - if (mixerStatus == MIXER_TRACKS_ENABLED) { - sleepTime = activeSleepTime; - } else { - sleepTime = idleSleepTime; - } - } else if (mBytesWritten != 0 && AudioSystem::isLinearPCM(mFormat)) { - memset (mMixBuffer, 0, mFrameCount * mFrameSize); - sleepTime = 0; - } - } - - if (mSuspended) { - sleepTime = idleSleepTime; - } - // sleepTime == 0 means we must write to audio hardware - if (sleepTime == 0) { - if (mixerStatus == MIXER_TRACKS_READY) { - applyVolume(leftVol, rightVol, rampVolume); - } - for (size_t i = 0; i < effectChains.size(); i ++) { - effectChains[i]->process_l(); - } - unlockEffectChains(); - - mLastWriteTime = systemTime(); - mInWrite = true; - mBytesWritten += mixBufferSize; - int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize); - if (bytesWritten < 0) mBytesWritten -= mixBufferSize; - mNumWrites++; - mInWrite = false; - mStandby = false; - } else { - unlockEffectChains(); - usleep(sleepTime); - } - - // finally let go of removed track, without the lock held - // since we can't guarantee the destructors won't acquire that - // same lock. - trackToRemove.clear(); - activeTrack.clear(); - - // Effect chains will be actually deleted here if they were removed from - // mEffectChains list during mixing or effects processing - effectChains.clear(); - } - - if (!mStandby) { - mOutput->standby(); - } - - LOGV("DirectOutputThread %p exiting", this); - return false; -} - -// getTrackName_l() must be called with ThreadBase::mLock held -int AudioFlinger::DirectOutputThread::getTrackName_l() -{ - return 0; -} - -// deleteTrackName_l() must be called with ThreadBase::mLock held -void AudioFlinger::DirectOutputThread::deleteTrackName_l(int name) -{ -} - -// checkForNewParameters_l() must be called with ThreadBase::mLock held -bool AudioFlinger::DirectOutputThread::checkForNewParameters_l() -{ - bool reconfig = false; - - while (!mNewParameters.isEmpty()) { - status_t status = NO_ERROR; - String8 keyValuePair = mNewParameters[0]; - AudioParameter param = AudioParameter(keyValuePair); - int value; - - if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) { - // do not accept frame count changes if tracks are open as the track buffer - // size depends on frame count and correct behavior would not be garantied - // if frame count is changed after track creation - if (!mTracks.isEmpty()) { - status = INVALID_OPERATION; - } else { - reconfig = true; - } - } - if (status == NO_ERROR) { - status = mOutput->setParameters(keyValuePair); - if (!mStandby && status == INVALID_OPERATION) { - mOutput->standby(); - mStandby = true; - mBytesWritten = 0; - status = mOutput->setParameters(keyValuePair); - } - if (status == NO_ERROR && reconfig) { - readOutputParameters(); - sendConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED); - } - } - - mNewParameters.removeAt(0); - - mParamStatus = status; - mParamCond.signal(); - mWaitWorkCV.wait(mLock); - } - return reconfig; -} - -uint32_t AudioFlinger::DirectOutputThread::activeSleepTimeUs() -{ - uint32_t time; - if (AudioSystem::isLinearPCM(mFormat)) { - time = (uint32_t)(mOutput->latency() * 1000) / 2; - } else { - time = 10000; - } - return time; -} - -uint32_t AudioFlinger::DirectOutputThread::idleSleepTimeUs() -{ - uint32_t time; - if (AudioSystem::isLinearPCM(mFormat)) { - time = (uint32_t)((mFrameCount * 1000) / mSampleRate) * 1000; - } else { - time = 10000; - } - return time; -} - -// ---------------------------------------------------------------------------- - -AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread, int id) - : MixerThread(audioFlinger, mainThread->getOutput(), id, mainThread->device()), mWaitTimeMs(UINT_MAX) -{ - mType = PlaybackThread::DUPLICATING; - addOutputTrack(mainThread); -} - -AudioFlinger::DuplicatingThread::~DuplicatingThread() -{ - for (size_t i = 0; i < mOutputTracks.size(); i++) { - mOutputTracks[i]->destroy(); - } - mOutputTracks.clear(); -} - -bool AudioFlinger::DuplicatingThread::threadLoop() -{ - Vector< sp<Track> > tracksToRemove; - uint32_t mixerStatus = MIXER_IDLE; - nsecs_t standbyTime = systemTime(); - size_t mixBufferSize = mFrameCount*mFrameSize; - SortedVector< sp<OutputTrack> > outputTracks; - uint32_t writeFrames = 0; - uint32_t activeSleepTime = activeSleepTimeUs(); - uint32_t idleSleepTime = idleSleepTimeUs(); - uint32_t sleepTime = idleSleepTime; - Vector< sp<EffectChain> > effectChains; - - while (!exitPending()) - { - processConfigEvents(); - - mixerStatus = MIXER_IDLE; - { // scope for the mLock - - Mutex::Autolock _l(mLock); - - if (checkForNewParameters_l()) { - mixBufferSize = mFrameCount*mFrameSize; - updateWaitTime(); - activeSleepTime = activeSleepTimeUs(); - idleSleepTime = idleSleepTimeUs(); - } - - const SortedVector< wp<Track> >& activeTracks = mActiveTracks; - - for (size_t i = 0; i < mOutputTracks.size(); i++) { - outputTracks.add(mOutputTracks[i]); - } - - // put audio hardware into standby after short delay - if UNLIKELY((!activeTracks.size() && systemTime() > standbyTime) || - mSuspended) { - if (!mStandby) { - for (size_t i = 0; i < outputTracks.size(); i++) { - outputTracks[i]->stop(); - } - mStandby = true; - mBytesWritten = 0; - } - - if (!activeTracks.size() && mConfigEvents.isEmpty()) { - // we're about to wait, flush the binder command buffer - IPCThreadState::self()->flushCommands(); - outputTracks.clear(); - - if (exitPending()) break; - - LOGV("DuplicatingThread %p TID %d going to sleep\n", this, gettid()); - mWaitWorkCV.wait(mLock); - LOGV("DuplicatingThread %p TID %d waking up\n", this, gettid()); - if (mMasterMute == false) { - char value[PROPERTY_VALUE_MAX]; - property_get("ro.audio.silent", value, "0"); - if (atoi(value)) { - LOGD("Silence is golden"); - setMasterMute(true); - } - } - - standbyTime = systemTime() + kStandbyTimeInNsecs; - sleepTime = idleSleepTime; - continue; - } - } - - mixerStatus = prepareTracks_l(activeTracks, &tracksToRemove); - - // prevent any changes in effect chain list and in each effect chain - // during mixing and effect process as the audio buffers could be deleted - // or modified if an effect is created or deleted - effectChains = mEffectChains; - lockEffectChains_l(); - } - - if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) { - // mix buffers... - if (outputsReady(outputTracks)) { - mAudioMixer->process(); - } else { - memset(mMixBuffer, 0, mixBufferSize); - } - sleepTime = 0; - writeFrames = mFrameCount; - } else { - if (sleepTime == 0) { - if (mixerStatus == MIXER_TRACKS_ENABLED) { - sleepTime = activeSleepTime; - } else { - sleepTime = idleSleepTime; - } - } else if (mBytesWritten != 0) { - // flush remaining overflow buffers in output tracks - for (size_t i = 0; i < outputTracks.size(); i++) { - if (outputTracks[i]->isActive()) { - sleepTime = 0; - writeFrames = 0; - memset(mMixBuffer, 0, mixBufferSize); - break; - } - } - } - } - - if (mSuspended) { - sleepTime = idleSleepTime; - } - // sleepTime == 0 means we must write to audio hardware - if (sleepTime == 0) { - for (size_t i = 0; i < effectChains.size(); i ++) { - effectChains[i]->process_l(); - } - // enable changes in effect chain - unlockEffectChains(); - - standbyTime = systemTime() + kStandbyTimeInNsecs; - for (size_t i = 0; i < outputTracks.size(); i++) { - outputTracks[i]->write(mMixBuffer, writeFrames); - } - mStandby = false; - mBytesWritten += mixBufferSize; - } else { - // enable changes in effect chain - unlockEffectChains(); - usleep(sleepTime); - } - - // finally let go of all our tracks, without the lock held - // since we can't guarantee the destructors won't acquire that - // same lock. - tracksToRemove.clear(); - outputTracks.clear(); - - // Effect chains will be actually deleted here if they were removed from - // mEffectChains list during mixing or effects processing - effectChains.clear(); - } - - return false; -} - -void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread) -{ - int frameCount = (3 * mFrameCount * mSampleRate) / thread->sampleRate(); - OutputTrack *outputTrack = new OutputTrack((ThreadBase *)thread, - this, - mSampleRate, - mFormat, - mChannelCount, - frameCount); - if (outputTrack->cblk() != NULL) { - thread->setStreamVolume(AudioSystem::NUM_STREAM_TYPES, 1.0f); - mOutputTracks.add(outputTrack); - LOGV("addOutputTrack() track %p, on thread %p", outputTrack, thread); - updateWaitTime(); - } -} - -void AudioFlinger::DuplicatingThread::removeOutputTrack(MixerThread *thread) -{ - Mutex::Autolock _l(mLock); - for (size_t i = 0; i < mOutputTracks.size(); i++) { - if (mOutputTracks[i]->thread() == (ThreadBase *)thread) { - mOutputTracks[i]->destroy(); - mOutputTracks.removeAt(i); - updateWaitTime(); - return; - } - } - LOGV("removeOutputTrack(): unkonwn thread: %p", thread); -} - -void AudioFlinger::DuplicatingThread::updateWaitTime() -{ - mWaitTimeMs = UINT_MAX; - for (size_t i = 0; i < mOutputTracks.size(); i++) { - sp<ThreadBase> strong = mOutputTracks[i]->thread().promote(); - if (strong != NULL) { - uint32_t waitTimeMs = (strong->frameCount() * 2 * 1000) / strong->sampleRate(); - if (waitTimeMs < mWaitTimeMs) { - mWaitTimeMs = waitTimeMs; - } - } - } -} - - -bool AudioFlinger::DuplicatingThread::outputsReady(SortedVector< sp<OutputTrack> > &outputTracks) -{ - for (size_t i = 0; i < outputTracks.size(); i++) { - sp <ThreadBase> thread = outputTracks[i]->thread().promote(); - if (thread == 0) { - LOGW("DuplicatingThread::outputsReady() could not promote thread on output track %p", outputTracks[i].get()); - return false; - } - PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); - if (playbackThread->standby() && !playbackThread->isSuspended()) { - LOGV("DuplicatingThread output track %p on thread %p Not Ready", outputTracks[i].get(), thread.get()); - return false; - } - } - return true; -} - -uint32_t AudioFlinger::DuplicatingThread::activeSleepTimeUs() -{ - return (mWaitTimeMs * 1000) / 2; -} - -// ---------------------------------------------------------------------------- - -// TrackBase constructor must be called with AudioFlinger::mLock held -AudioFlinger::ThreadBase::TrackBase::TrackBase( - const wp<ThreadBase>& thread, - const sp<Client>& client, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - uint32_t flags, - const sp<IMemory>& sharedBuffer, - int sessionId) - : RefBase(), - mThread(thread), - mClient(client), - mCblk(0), - mFrameCount(0), - mState(IDLE), - mClientTid(-1), - mFormat(format), - mFlags(flags & ~SYSTEM_FLAGS_MASK), - mSessionId(sessionId) -{ - LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size()); - - // LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize); - size_t size = sizeof(audio_track_cblk_t); - size_t bufferSize = frameCount*channelCount*sizeof(int16_t); - if (sharedBuffer == 0) { - size += bufferSize; - } - - if (client != NULL) { - mCblkMemory = client->heap()->allocate(size); - if (mCblkMemory != 0) { - mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer()); - if (mCblk) { // construct the shared structure in-place. - new(mCblk) audio_track_cblk_t(); - // clear all buffers - mCblk->frameCount = frameCount; - mCblk->sampleRate = sampleRate; - mCblk->channelCount = (uint8_t)channelCount; - if (sharedBuffer == 0) { - mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); - memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t)); - // Force underrun condition to avoid false underrun callback until first data is - // written to buffer - mCblk->flags = CBLK_UNDERRUN_ON; - } else { - mBuffer = sharedBuffer->pointer(); - } - mBufferEnd = (uint8_t *)mBuffer + bufferSize; - } - } else { - LOGE("not enough memory for AudioTrack size=%u", size); - client->heap()->dump("AudioTrack"); - return; - } - } else { - mCblk = (audio_track_cblk_t *)(new uint8_t[size]); - if (mCblk) { // construct the shared structure in-place. - new(mCblk) audio_track_cblk_t(); - // clear all buffers - mCblk->frameCount = frameCount; - mCblk->sampleRate = sampleRate; - mCblk->channelCount = (uint8_t)channelCount; - mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); - memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t)); - // Force underrun condition to avoid false underrun callback until first data is - // written to buffer - mCblk->flags = CBLK_UNDERRUN_ON; - mBufferEnd = (uint8_t *)mBuffer + bufferSize; - } - } -} - -AudioFlinger::ThreadBase::TrackBase::~TrackBase() -{ - if (mCblk) { - mCblk->~audio_track_cblk_t(); // destroy our shared-structure. - if (mClient == NULL) { - delete mCblk; - } - } - mCblkMemory.clear(); // and free the shared memory - if (mClient != NULL) { - Mutex::Autolock _l(mClient->audioFlinger()->mLock); - mClient.clear(); - } -} - -void AudioFlinger::ThreadBase::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer) -{ - buffer->raw = 0; - mFrameCount = buffer->frameCount; - step(); - buffer->frameCount = 0; -} - -bool AudioFlinger::ThreadBase::TrackBase::step() { - bool result; - audio_track_cblk_t* cblk = this->cblk(); - - result = cblk->stepServer(mFrameCount); - if (!result) { - LOGV("stepServer failed acquiring cblk mutex"); - mFlags |= STEPSERVER_FAILED; - } - return result; -} - -void AudioFlinger::ThreadBase::TrackBase::reset() { - audio_track_cblk_t* cblk = this->cblk(); - - cblk->user = 0; - cblk->server = 0; - cblk->userBase = 0; - cblk->serverBase = 0; - mFlags &= (uint32_t)(~SYSTEM_FLAGS_MASK); - LOGV("TrackBase::reset"); -} - -sp<IMemory> AudioFlinger::ThreadBase::TrackBase::getCblk() const -{ - return mCblkMemory; -} - -int AudioFlinger::ThreadBase::TrackBase::sampleRate() const { - return (int)mCblk->sampleRate; -} - -int AudioFlinger::ThreadBase::TrackBase::channelCount() const { - return (int)mCblk->channelCount; -} - -void* AudioFlinger::ThreadBase::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const { - audio_track_cblk_t* cblk = this->cblk(); - int8_t *bufferStart = (int8_t *)mBuffer + (offset-cblk->serverBase)*cblk->frameSize; - int8_t *bufferEnd = bufferStart + frames * cblk->frameSize; - - // Check validity of returned pointer in case the track control block would have been corrupted. - if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd || - ((unsigned long)bufferStart & (unsigned long)(cblk->frameSize - 1))) { - LOGE("TrackBase::getBuffer buffer out of range:\n start: %p, end %p , mBuffer %p mBufferEnd %p\n \ - server %d, serverBase %d, user %d, userBase %d, channelCount %d", - bufferStart, bufferEnd, mBuffer, mBufferEnd, - cblk->server, cblk->serverBase, cblk->user, cblk->userBase, cblk->channelCount); - return 0; - } - - return bufferStart; -} - -// ---------------------------------------------------------------------------- - -// Track constructor must be called with AudioFlinger::mLock and ThreadBase::mLock held -AudioFlinger::PlaybackThread::Track::Track( - const wp<ThreadBase>& thread, - const sp<Client>& client, - int streamType, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - const sp<IMemory>& sharedBuffer, - int sessionId) - : TrackBase(thread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer, sessionId), - mMute(false), mSharedBuffer(sharedBuffer), mName(-1), mMainBuffer(NULL), mAuxBuffer(NULL), mAuxEffectId(0) -{ - if (mCblk != NULL) { - sp<ThreadBase> baseThread = thread.promote(); - if (baseThread != 0) { - PlaybackThread *playbackThread = (PlaybackThread *)baseThread.get(); - mName = playbackThread->getTrackName_l(); - mMainBuffer = playbackThread->mixBuffer(); - } - LOGV("Track constructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid()); - if (mName < 0) { - LOGE("no more track names available"); - } - mVolume[0] = 1.0f; - mVolume[1] = 1.0f; - mStreamType = streamType; - // NOTE: audio_track_cblk_t::frameSize for 8 bit PCM data is based on a sample size of - // 16 bit because data is converted to 16 bit before being stored in buffer by AudioTrack - mCblk->frameSize = AudioSystem::isLinearPCM(format) ? channelCount * sizeof(int16_t) : sizeof(int8_t); - } -} - -AudioFlinger::PlaybackThread::Track::~Track() -{ - LOGV("PlaybackThread::Track destructor"); - sp<ThreadBase> thread = mThread.promote(); - if (thread != 0) { - Mutex::Autolock _l(thread->mLock); - mState = TERMINATED; - } -} - -void AudioFlinger::PlaybackThread::Track::destroy() -{ - // NOTE: destroyTrack_l() can remove a strong reference to this Track - // by removing it from mTracks vector, so there is a risk that this Tracks's - // desctructor is called. As the destructor needs to lock mLock, - // we must acquire a strong reference on this Track before locking mLock - // here so that the destructor is called only when exiting this function. - // On the other hand, as long as Track::destroy() is only called by - // TrackHandle destructor, the TrackHandle still holds a strong ref on - // this Track with its member mTrack. - sp<Track> keep(this); - { // scope for mLock - sp<ThreadBase> thread = mThread.promote(); - if (thread != 0) { - if (!isOutputTrack()) { - if (mState == ACTIVE || mState == RESUMING) { - AudioSystem::stopOutput(thread->id(), (AudioSystem::stream_type)mStreamType); - } - AudioSystem::releaseOutput(thread->id()); - } - Mutex::Autolock _l(thread->mLock); - PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); - playbackThread->destroyTrack_l(this); - } - } -} - -void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size) -{ - snprintf(buffer, size, " %05d %05d %03u %03u %03u %05u %04u %1d %1d %1d %05u %05u %05u 0x%08x 0x%08x 0x%08x 0x%08x\n", - mName - AudioMixer::TRACK0, - (mClient == NULL) ? getpid() : mClient->pid(), - mStreamType, - mFormat, - mCblk->channelCount, - mSessionId, - mFrameCount, - mState, - mMute, - mFillingUpStatus, - mCblk->sampleRate, - mCblk->volume[0], - mCblk->volume[1], - mCblk->server, - mCblk->user, - (int)mMainBuffer, - (int)mAuxBuffer); -} - -status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer) -{ - audio_track_cblk_t* cblk = this->cblk(); - uint32_t framesReady; - uint32_t framesReq = buffer->frameCount; - - // Check if last stepServer failed, try to step now - if (mFlags & TrackBase::STEPSERVER_FAILED) { - if (!step()) goto getNextBuffer_exit; - LOGV("stepServer recovered"); - mFlags &= ~TrackBase::STEPSERVER_FAILED; - } - - framesReady = cblk->framesReady(); - - if (LIKELY(framesReady)) { - uint32_t s = cblk->server; - uint32_t bufferEnd = cblk->serverBase + cblk->frameCount; - - bufferEnd = (cblk->loopEnd < bufferEnd) ? cblk->loopEnd : bufferEnd; - if (framesReq > framesReady) { - framesReq = framesReady; - } - if (s + framesReq > bufferEnd) { - framesReq = bufferEnd - s; - } - - buffer->raw = getBuffer(s, framesReq); - if (buffer->raw == 0) goto getNextBuffer_exit; - - buffer->frameCount = framesReq; - return NO_ERROR; - } - -getNextBuffer_exit: - buffer->raw = 0; - buffer->frameCount = 0; - LOGV("getNextBuffer() no more data for track %d on thread %p", mName, mThread.unsafe_get()); - return NOT_ENOUGH_DATA; -} - -bool AudioFlinger::PlaybackThread::Track::isReady() const { - if (mFillingUpStatus != FS_FILLING) return true; - - if (mCblk->framesReady() >= mCblk->frameCount || - (mCblk->flags & CBLK_FORCEREADY_MSK)) { - mFillingUpStatus = FS_FILLED; - mCblk->flags &= ~CBLK_FORCEREADY_MSK; - return true; - } - return false; -} - -status_t AudioFlinger::PlaybackThread::Track::start() -{ - status_t status = NO_ERROR; - LOGV("start(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid()); - sp<ThreadBase> thread = mThread.promote(); - if (thread != 0) { - Mutex::Autolock _l(thread->mLock); - int state = mState; - // here the track could be either new, or restarted - // in both cases "unstop" the track - if (mState == PAUSED) { - mState = TrackBase::RESUMING; - LOGV("PAUSED => RESUMING (%d) on thread %p", mName, this); - } else { - mState = TrackBase::ACTIVE; - LOGV("? => ACTIVE (%d) on thread %p", mName, this); - } - - if (!isOutputTrack() && state != ACTIVE && state != RESUMING) { - thread->mLock.unlock(); - status = AudioSystem::startOutput(thread->id(), (AudioSystem::stream_type)mStreamType); - thread->mLock.lock(); - } - if (status == NO_ERROR) { - PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); - playbackThread->addTrack_l(this); - } else { - mState = state; - } - } else { - status = BAD_VALUE; - } - return status; -} - -void AudioFlinger::PlaybackThread::Track::stop() -{ - LOGV("stop(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid()); - sp<ThreadBase> thread = mThread.promote(); - if (thread != 0) { - Mutex::Autolock _l(thread->mLock); - int state = mState; - if (mState > STOPPED) { - mState = STOPPED; - // If the track is not active (PAUSED and buffers full), flush buffers - PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); - if (playbackThread->mActiveTracks.indexOf(this) < 0) { - reset(); - } - LOGV("(> STOPPED) => STOPPED (%d) on thread %p", mName, playbackThread); - } - if (!isOutputTrack() && (state == ACTIVE || state == RESUMING)) { - thread->mLock.unlock(); - AudioSystem::stopOutput(thread->id(), (AudioSystem::stream_type)mStreamType); - thread->mLock.lock(); - } - } -} - -void AudioFlinger::PlaybackThread::Track::pause() -{ - LOGV("pause(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid()); - sp<ThreadBase> thread = mThread.promote(); - if (thread != 0) { - Mutex::Autolock _l(thread->mLock); - if (mState == ACTIVE || mState == RESUMING) { - mState = PAUSING; - LOGV("ACTIVE/RESUMING => PAUSING (%d) on thread %p", mName, thread.get()); - if (!isOutputTrack()) { - thread->mLock.unlock(); - AudioSystem::stopOutput(thread->id(), (AudioSystem::stream_type)mStreamType); - thread->mLock.lock(); - } - } - } -} - -void AudioFlinger::PlaybackThread::Track::flush() -{ - LOGV("flush(%d)", mName); - sp<ThreadBase> thread = mThread.promote(); - if (thread != 0) { - Mutex::Autolock _l(thread->mLock); - if (mState != STOPPED && mState != PAUSED && mState != PAUSING) { - return; - } - // No point remaining in PAUSED state after a flush => go to - // STOPPED state - mState = STOPPED; - - mCblk->lock.lock(); - // NOTE: reset() will reset cblk->user and cblk->server with - // the risk that at the same time, the AudioMixer is trying to read - // data. In this case, getNextBuffer() would return a NULL pointer - // as audio buffer => the AudioMixer code MUST always test that pointer - // returned by getNextBuffer() is not NULL! - reset(); - mCblk->lock.unlock(); - } -} - -void AudioFlinger::PlaybackThread::Track::reset() -{ - // Do not reset twice to avoid discarding data written just after a flush and before - // the audioflinger thread detects the track is stopped. - if (!mResetDone) { - TrackBase::reset(); - // Force underrun condition to avoid false underrun callback until first data is - // written to buffer - mCblk->flags |= CBLK_UNDERRUN_ON; - mCblk->flags &= ~CBLK_FORCEREADY_MSK; - mFillingUpStatus = FS_FILLING; - mResetDone = true; - } -} - -void AudioFlinger::PlaybackThread::Track::mute(bool muted) -{ - mMute = muted; -} - -void AudioFlinger::PlaybackThread::Track::setVolume(float left, float right) -{ - mVolume[0] = left; - mVolume[1] = right; -} - -status_t AudioFlinger::PlaybackThread::Track::attachAuxEffect(int EffectId) -{ - status_t status = DEAD_OBJECT; - sp<ThreadBase> thread = mThread.promote(); - if (thread != 0) { - PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); - status = playbackThread->attachAuxEffect(this, EffectId); - } - return status; -} - -void AudioFlinger::PlaybackThread::Track::setAuxBuffer(int EffectId, int32_t *buffer) -{ - mAuxEffectId = EffectId; - mAuxBuffer = buffer; -} - -// ---------------------------------------------------------------------------- - -// RecordTrack constructor must be called with AudioFlinger::mLock held -AudioFlinger::RecordThread::RecordTrack::RecordTrack( - const wp<ThreadBase>& thread, - const sp<Client>& client, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - uint32_t flags, - int sessionId) - : TrackBase(thread, client, sampleRate, format, - channelCount, frameCount, flags, 0, sessionId), - mOverflow(false) -{ - if (mCblk != NULL) { - LOGV("RecordTrack constructor, size %d", (int)mBufferEnd - (int)mBuffer); - if (format == AudioSystem::PCM_16_BIT) { - mCblk->frameSize = channelCount * sizeof(int16_t); - } else if (format == AudioSystem::PCM_8_BIT) { - mCblk->frameSize = channelCount * sizeof(int8_t); - } else { - mCblk->frameSize = sizeof(int8_t); - } - } -} - -AudioFlinger::RecordThread::RecordTrack::~RecordTrack() -{ - sp<ThreadBase> thread = mThread.promote(); - if (thread != 0) { - AudioSystem::releaseInput(thread->id()); - } -} - -status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer) -{ - audio_track_cblk_t* cblk = this->cblk(); - uint32_t framesAvail; - uint32_t framesReq = buffer->frameCount; - - // Check if last stepServer failed, try to step now - if (mFlags & TrackBase::STEPSERVER_FAILED) { - if (!step()) goto getNextBuffer_exit; - LOGV("stepServer recovered"); - mFlags &= ~TrackBase::STEPSERVER_FAILED; - } - - framesAvail = cblk->framesAvailable_l(); - - if (LIKELY(framesAvail)) { - uint32_t s = cblk->server; - uint32_t bufferEnd = cblk->serverBase + cblk->frameCount; - - if (framesReq > framesAvail) { - framesReq = framesAvail; - } - if (s + framesReq > bufferEnd) { - framesReq = bufferEnd - s; - } - - buffer->raw = getBuffer(s, framesReq); - if (buffer->raw == 0) goto getNextBuffer_exit; - - buffer->frameCount = framesReq; - return NO_ERROR; - } - -getNextBuffer_exit: - buffer->raw = 0; - buffer->frameCount = 0; - return NOT_ENOUGH_DATA; -} - -status_t AudioFlinger::RecordThread::RecordTrack::start() -{ - sp<ThreadBase> thread = mThread.promote(); - if (thread != 0) { - RecordThread *recordThread = (RecordThread *)thread.get(); - return recordThread->start(this); - } else { - return BAD_VALUE; - } -} - -void AudioFlinger::RecordThread::RecordTrack::stop() -{ - sp<ThreadBase> thread = mThread.promote(); - if (thread != 0) { - RecordThread *recordThread = (RecordThread *)thread.get(); - recordThread->stop(this); - TrackBase::reset(); - // Force overerrun condition to avoid false overrun callback until first data is - // read from buffer - mCblk->flags |= CBLK_UNDERRUN_ON; - } -} - -void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size) -{ - snprintf(buffer, size, " %05d %03u %03u %05d %04u %01d %05u %08x %08x\n", - (mClient == NULL) ? getpid() : mClient->pid(), - mFormat, - mCblk->channelCount, - mSessionId, - mFrameCount, - mState, - mCblk->sampleRate, - mCblk->server, - mCblk->user); -} - - -// ---------------------------------------------------------------------------- - -AudioFlinger::PlaybackThread::OutputTrack::OutputTrack( - const wp<ThreadBase>& thread, - DuplicatingThread *sourceThread, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount) - : Track(thread, NULL, AudioSystem::NUM_STREAM_TYPES, sampleRate, format, channelCount, frameCount, NULL, 0), - mActive(false), mSourceThread(sourceThread) -{ - - PlaybackThread *playbackThread = (PlaybackThread *)thread.unsafe_get(); - if (mCblk != NULL) { - mCblk->flags |= CBLK_DIRECTION_OUT; - mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); - mCblk->volume[0] = mCblk->volume[1] = 0x1000; - mOutBuffer.frameCount = 0; - playbackThread->mTracks.add(this); - LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channelCount %d mBufferEnd %p", - mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channelCount, mBufferEnd); - } else { - LOGW("Error creating output track on thread %p", playbackThread); - } -} - -AudioFlinger::PlaybackThread::OutputTrack::~OutputTrack() -{ - clearBufferQueue(); -} - -status_t AudioFlinger::PlaybackThread::OutputTrack::start() -{ - status_t status = Track::start(); - if (status != NO_ERROR) { - return status; - } - - mActive = true; - mRetryCount = 127; - return status; -} - -void AudioFlinger::PlaybackThread::OutputTrack::stop() -{ - Track::stop(); - clearBufferQueue(); - mOutBuffer.frameCount = 0; - mActive = false; -} - -bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t frames) -{ - Buffer *pInBuffer; - Buffer inBuffer; - uint32_t channelCount = mCblk->channelCount; - bool outputBufferFull = false; - inBuffer.frameCount = frames; - inBuffer.i16 = data; - - uint32_t waitTimeLeftMs = mSourceThread->waitTimeMs(); - - if (!mActive && frames != 0) { - start(); - sp<ThreadBase> thread = mThread.promote(); - if (thread != 0) { - MixerThread *mixerThread = (MixerThread *)thread.get(); - if (mCblk->frameCount > frames){ - if (mBufferQueue.size() < kMaxOverFlowBuffers) { - uint32_t startFrames = (mCblk->frameCount - frames); - pInBuffer = new Buffer; - pInBuffer->mBuffer = new int16_t[startFrames * channelCount]; - pInBuffer->frameCount = startFrames; - pInBuffer->i16 = pInBuffer->mBuffer; - memset(pInBuffer->raw, 0, startFrames * channelCount * sizeof(int16_t)); - mBufferQueue.add(pInBuffer); - } else { - LOGW ("OutputTrack::write() %p no more buffers in queue", this); - } - } - } - } - - while (waitTimeLeftMs) { - // First write pending buffers, then new data - if (mBufferQueue.size()) { - pInBuffer = mBufferQueue.itemAt(0); - } else { - pInBuffer = &inBuffer; - } - - if (pInBuffer->frameCount == 0) { - break; - } - - if (mOutBuffer.frameCount == 0) { - mOutBuffer.frameCount = pInBuffer->frameCount; - nsecs_t startTime = systemTime(); - if (obtainBuffer(&mOutBuffer, waitTimeLeftMs) == (status_t)AudioTrack::NO_MORE_BUFFERS) { - LOGV ("OutputTrack::write() %p thread %p no more output buffers", this, mThread.unsafe_get()); - outputBufferFull = true; - break; - } - uint32_t waitTimeMs = (uint32_t)ns2ms(systemTime() - startTime); - if (waitTimeLeftMs >= waitTimeMs) { - waitTimeLeftMs -= waitTimeMs; - } else { - waitTimeLeftMs = 0; - } - } - - uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount : pInBuffer->frameCount; - memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channelCount * sizeof(int16_t)); - mCblk->stepUser(outFrames); - pInBuffer->frameCount -= outFrames; - pInBuffer->i16 += outFrames * channelCount; - mOutBuffer.frameCount -= outFrames; - mOutBuffer.i16 += outFrames * channelCount; - - if (pInBuffer->frameCount == 0) { - if (mBufferQueue.size()) { - mBufferQueue.removeAt(0); - delete [] pInBuffer->mBuffer; - delete pInBuffer; - LOGV("OutputTrack::write() %p thread %p released overflow buffer %d", this, mThread.unsafe_get(), mBufferQueue.size()); - } else { - break; - } - } - } - - // If we could not write all frames, allocate a buffer and queue it for next time. - if (inBuffer.frameCount) { - sp<ThreadBase> thread = mThread.promote(); - if (thread != 0 && !thread->standby()) { - if (mBufferQueue.size() < kMaxOverFlowBuffers) { - pInBuffer = new Buffer; - pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channelCount]; - pInBuffer->frameCount = inBuffer.frameCount; - pInBuffer->i16 = pInBuffer->mBuffer; - memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channelCount * sizeof(int16_t)); - mBufferQueue.add(pInBuffer); - LOGV("OutputTrack::write() %p thread %p adding overflow buffer %d", this, mThread.unsafe_get(), mBufferQueue.size()); - } else { - LOGW("OutputTrack::write() %p thread %p no more overflow buffers", mThread.unsafe_get(), this); - } - } - } - - // Calling write() with a 0 length buffer, means that no more data will be written: - // If no more buffers are pending, fill output track buffer to make sure it is started - // by output mixer. - if (frames == 0 && mBufferQueue.size() == 0) { - if (mCblk->user < mCblk->frameCount) { - frames = mCblk->frameCount - mCblk->user; - pInBuffer = new Buffer; - pInBuffer->mBuffer = new int16_t[frames * channelCount]; - pInBuffer->frameCount = frames; - pInBuffer->i16 = pInBuffer->mBuffer; - memset(pInBuffer->raw, 0, frames * channelCount * sizeof(int16_t)); - mBufferQueue.add(pInBuffer); - } else if (mActive) { - stop(); - } - } - - return outputBufferFull; -} - -status_t AudioFlinger::PlaybackThread::OutputTrack::obtainBuffer(AudioBufferProvider::Buffer* buffer, uint32_t waitTimeMs) -{ - int active; - status_t result; - audio_track_cblk_t* cblk = mCblk; - uint32_t framesReq = buffer->frameCount; - -// LOGV("OutputTrack::obtainBuffer user %d, server %d", cblk->user, cblk->server); - buffer->frameCount = 0; - - uint32_t framesAvail = cblk->framesAvailable(); - - - if (framesAvail == 0) { - Mutex::Autolock _l(cblk->lock); - goto start_loop_here; - while (framesAvail == 0) { - active = mActive; - if (UNLIKELY(!active)) { - LOGV("Not active and NO_MORE_BUFFERS"); - return AudioTrack::NO_MORE_BUFFERS; - } - result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs)); - if (result != NO_ERROR) { - return AudioTrack::NO_MORE_BUFFERS; - } - // read the server count again - start_loop_here: - framesAvail = cblk->framesAvailable_l(); - } - } - -// if (framesAvail < framesReq) { -// return AudioTrack::NO_MORE_BUFFERS; -// } - - if (framesReq > framesAvail) { - framesReq = framesAvail; - } - - uint32_t u = cblk->user; - uint32_t bufferEnd = cblk->userBase + cblk->frameCount; - - if (u + framesReq > bufferEnd) { - framesReq = bufferEnd - u; - } - - buffer->frameCount = framesReq; - buffer->raw = (void *)cblk->buffer(u); - return NO_ERROR; -} - - -void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue() -{ - size_t size = mBufferQueue.size(); - Buffer *pBuffer; - - for (size_t i = 0; i < size; i++) { - pBuffer = mBufferQueue.itemAt(i); - delete [] pBuffer->mBuffer; - delete pBuffer; - } - mBufferQueue.clear(); -} - -// ---------------------------------------------------------------------------- - -AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid) - : RefBase(), - mAudioFlinger(audioFlinger), - mMemoryDealer(new MemoryDealer(1024*1024, "AudioFlinger::Client")), - mPid(pid) -{ - // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer -} - -// Client destructor must be called with AudioFlinger::mLock held -AudioFlinger::Client::~Client() -{ - mAudioFlinger->removeClient_l(mPid); -} - -const sp<MemoryDealer>& AudioFlinger::Client::heap() const -{ - return mMemoryDealer; -} - -// ---------------------------------------------------------------------------- - -AudioFlinger::NotificationClient::NotificationClient(const sp<AudioFlinger>& audioFlinger, - const sp<IAudioFlingerClient>& client, - pid_t pid) - : mAudioFlinger(audioFlinger), mPid(pid), mClient(client) -{ -} - -AudioFlinger::NotificationClient::~NotificationClient() -{ - mClient.clear(); -} - -void AudioFlinger::NotificationClient::binderDied(const wp<IBinder>& who) -{ - sp<NotificationClient> keep(this); - { - mAudioFlinger->removeNotificationClient(mPid); - } -} - -// ---------------------------------------------------------------------------- - -AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::PlaybackThread::Track>& track) - : BnAudioTrack(), - mTrack(track) -{ -} - -AudioFlinger::TrackHandle::~TrackHandle() { - // just stop the track on deletion, associated resources - // will be freed from the main thread once all pending buffers have - // been played. Unless it's not in the active track list, in which - // case we free everything now... - mTrack->destroy(); -} - -status_t AudioFlinger::TrackHandle::start() { - return mTrack->start(); -} - -void AudioFlinger::TrackHandle::stop() { - mTrack->stop(); -} - -void AudioFlinger::TrackHandle::flush() { - mTrack->flush(); -} - -void AudioFlinger::TrackHandle::mute(bool e) { - mTrack->mute(e); -} - -void AudioFlinger::TrackHandle::pause() { - mTrack->pause(); -} - -void AudioFlinger::TrackHandle::setVolume(float left, float right) { - mTrack->setVolume(left, right); -} - -sp<IMemory> AudioFlinger::TrackHandle::getCblk() const { - return mTrack->getCblk(); -} - -status_t AudioFlinger::TrackHandle::attachAuxEffect(int EffectId) -{ - return mTrack->attachAuxEffect(EffectId); -} - -status_t AudioFlinger::TrackHandle::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - return BnAudioTrack::onTransact(code, data, reply, flags); -} - -// ---------------------------------------------------------------------------- - -sp<IAudioRecord> AudioFlinger::openRecord( - pid_t pid, - int input, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - uint32_t flags, - int *sessionId, - status_t *status) -{ - sp<RecordThread::RecordTrack> recordTrack; - sp<RecordHandle> recordHandle; - sp<Client> client; - wp<Client> wclient; - status_t lStatus; - RecordThread *thread; - size_t inFrameCount; - int lSessionId; - - // check calling permissions - if (!recordingAllowed()) { - lStatus = PERMISSION_DENIED; - goto Exit; - } - - // add client to list - { // scope for mLock - Mutex::Autolock _l(mLock); - thread = checkRecordThread_l(input); - if (thread == NULL) { - lStatus = BAD_VALUE; - goto Exit; - } - - wclient = mClients.valueFor(pid); - if (wclient != NULL) { - client = wclient.promote(); - } else { - client = new Client(this, pid); - mClients.add(pid, client); - } - - // If no audio session id is provided, create one here - if (sessionId != NULL && *sessionId != 0) { - lSessionId = *sessionId; - } else { - lSessionId = nextUniqueId(); - if (sessionId != NULL) { - *sessionId = lSessionId; - } - } - // create new record track. The record track uses one track in mHardwareMixerThread by convention. - recordTrack = new RecordThread::RecordTrack(thread, client, sampleRate, - format, channelCount, frameCount, flags, lSessionId); - } - if (recordTrack->getCblk() == NULL) { - // remove local strong reference to Client before deleting the RecordTrack so that the Client - // destructor is called by the TrackBase destructor with mLock held - client.clear(); - recordTrack.clear(); - lStatus = NO_MEMORY; - goto Exit; - } - - // return to handle to client - recordHandle = new RecordHandle(recordTrack); - lStatus = NO_ERROR; - -Exit: - if (status) { - *status = lStatus; - } - return recordHandle; -} - -// ---------------------------------------------------------------------------- - -AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::RecordThread::RecordTrack>& recordTrack) - : BnAudioRecord(), - mRecordTrack(recordTrack) -{ -} - -AudioFlinger::RecordHandle::~RecordHandle() { - stop(); -} - -status_t AudioFlinger::RecordHandle::start() { - LOGV("RecordHandle::start()"); - return mRecordTrack->start(); -} - -void AudioFlinger::RecordHandle::stop() { - LOGV("RecordHandle::stop()"); - mRecordTrack->stop(); -} - -sp<IMemory> AudioFlinger::RecordHandle::getCblk() const { - return mRecordTrack->getCblk(); -} - -status_t AudioFlinger::RecordHandle::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - return BnAudioRecord::onTransact(code, data, reply, flags); -} - -// ---------------------------------------------------------------------------- - -AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, AudioStreamIn *input, uint32_t sampleRate, uint32_t channels, int id) : - ThreadBase(audioFlinger, id), - mInput(input), mResampler(0), mRsmpOutBuffer(0), mRsmpInBuffer(0) -{ - mReqChannelCount = AudioSystem::popCount(channels); - mReqSampleRate = sampleRate; - readInputParameters(); -} - - -AudioFlinger::RecordThread::~RecordThread() -{ - delete[] mRsmpInBuffer; - if (mResampler != 0) { - delete mResampler; - delete[] mRsmpOutBuffer; - } -} - -void AudioFlinger::RecordThread::onFirstRef() -{ - const size_t SIZE = 256; - char buffer[SIZE]; - - snprintf(buffer, SIZE, "Record Thread %p", this); - - run(buffer, PRIORITY_URGENT_AUDIO); -} - -bool AudioFlinger::RecordThread::threadLoop() -{ - AudioBufferProvider::Buffer buffer; - sp<RecordTrack> activeTrack; - - // start recording - while (!exitPending()) { - - processConfigEvents(); - - { // scope for mLock - Mutex::Autolock _l(mLock); - checkForNewParameters_l(); - if (mActiveTrack == 0 && mConfigEvents.isEmpty()) { - if (!mStandby) { - mInput->standby(); - mStandby = true; - } - - if (exitPending()) break; - - LOGV("RecordThread: loop stopping"); - // go to sleep - mWaitWorkCV.wait(mLock); - LOGV("RecordThread: loop starting"); - continue; - } - if (mActiveTrack != 0) { - if (mActiveTrack->mState == TrackBase::PAUSING) { - if (!mStandby) { - mInput->standby(); - mStandby = true; - } - mActiveTrack.clear(); - mStartStopCond.broadcast(); - } else if (mActiveTrack->mState == TrackBase::RESUMING) { - if (mReqChannelCount != mActiveTrack->channelCount()) { - mActiveTrack.clear(); - mStartStopCond.broadcast(); - } else if (mBytesRead != 0) { - // record start succeeds only if first read from audio input - // succeeds - if (mBytesRead > 0) { - mActiveTrack->mState = TrackBase::ACTIVE; - } else { - mActiveTrack.clear(); - } - mStartStopCond.broadcast(); - } - mStandby = false; - } - } - } - - if (mActiveTrack != 0) { - if (mActiveTrack->mState != TrackBase::ACTIVE && - mActiveTrack->mState != TrackBase::RESUMING) { - usleep(5000); - continue; - } - buffer.frameCount = mFrameCount; - if (LIKELY(mActiveTrack->getNextBuffer(&buffer) == NO_ERROR)) { - size_t framesOut = buffer.frameCount; - if (mResampler == 0) { - // no resampling - while (framesOut) { - size_t framesIn = mFrameCount - mRsmpInIndex; - if (framesIn) { - int8_t *src = (int8_t *)mRsmpInBuffer + mRsmpInIndex * mFrameSize; - int8_t *dst = buffer.i8 + (buffer.frameCount - framesOut) * mActiveTrack->mCblk->frameSize; - if (framesIn > framesOut) - framesIn = framesOut; - mRsmpInIndex += framesIn; - framesOut -= framesIn; - if ((int)mChannelCount == mReqChannelCount || - mFormat != AudioSystem::PCM_16_BIT) { - memcpy(dst, src, framesIn * mFrameSize); - } else { - int16_t *src16 = (int16_t *)src; - int16_t *dst16 = (int16_t *)dst; - if (mChannelCount == 1) { - while (framesIn--) { - *dst16++ = *src16; - *dst16++ = *src16++; - } - } else { - while (framesIn--) { - *dst16++ = (int16_t)(((int32_t)*src16 + (int32_t)*(src16 + 1)) >> 1); - src16 += 2; - } - } - } - } - if (framesOut && mFrameCount == mRsmpInIndex) { - if (framesOut == mFrameCount && - ((int)mChannelCount == mReqChannelCount || mFormat != AudioSystem::PCM_16_BIT)) { - mBytesRead = mInput->read(buffer.raw, mInputBytes); - framesOut = 0; - } else { - mBytesRead = mInput->read(mRsmpInBuffer, mInputBytes); - mRsmpInIndex = 0; - } - if (mBytesRead < 0) { - LOGE("Error reading audio input"); - if (mActiveTrack->mState == TrackBase::ACTIVE) { - // Force input into standby so that it tries to - // recover at next read attempt - mInput->standby(); - usleep(5000); - } - mRsmpInIndex = mFrameCount; - framesOut = 0; - buffer.frameCount = 0; - } - } - } - } else { - // resampling - - memset(mRsmpOutBuffer, 0, framesOut * 2 * sizeof(int32_t)); - // alter output frame count as if we were expecting stereo samples - if (mChannelCount == 1 && mReqChannelCount == 1) { - framesOut >>= 1; - } - mResampler->resample(mRsmpOutBuffer, framesOut, this); - // ditherAndClamp() works as long as all buffers returned by mActiveTrack->getNextBuffer() - // are 32 bit aligned which should be always true. - if (mChannelCount == 2 && mReqChannelCount == 1) { - AudioMixer::ditherAndClamp(mRsmpOutBuffer, mRsmpOutBuffer, framesOut); - // the resampler always outputs stereo samples: do post stereo to mono conversion - int16_t *src = (int16_t *)mRsmpOutBuffer; - int16_t *dst = buffer.i16; - while (framesOut--) { - *dst++ = (int16_t)(((int32_t)*src + (int32_t)*(src + 1)) >> 1); - src += 2; - } - } else { - AudioMixer::ditherAndClamp((int32_t *)buffer.raw, mRsmpOutBuffer, framesOut); - } - - } - mActiveTrack->releaseBuffer(&buffer); - mActiveTrack->overflow(); - } - // client isn't retrieving buffers fast enough - else { - if (!mActiveTrack->setOverflow()) - LOGW("RecordThread: buffer overflow"); - // Release the processor for a while before asking for a new buffer. - // This will give the application more chance to read from the buffer and - // clear the overflow. - usleep(5000); - } - } - } - - if (!mStandby) { - mInput->standby(); - } - mActiveTrack.clear(); - - mStartStopCond.broadcast(); - - LOGV("RecordThread %p exiting", this); - return false; -} - -status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack) -{ - LOGV("RecordThread::start"); - sp <ThreadBase> strongMe = this; - status_t status = NO_ERROR; - { - AutoMutex lock(&mLock); - if (mActiveTrack != 0) { - if (recordTrack != mActiveTrack.get()) { - status = -EBUSY; - } else if (mActiveTrack->mState == TrackBase::PAUSING) { - mActiveTrack->mState = TrackBase::ACTIVE; - } - return status; - } - - recordTrack->mState = TrackBase::IDLE; - mActiveTrack = recordTrack; - mLock.unlock(); - status_t status = AudioSystem::startInput(mId); - mLock.lock(); - if (status != NO_ERROR) { - mActiveTrack.clear(); - return status; - } - mActiveTrack->mState = TrackBase::RESUMING; - mRsmpInIndex = mFrameCount; - mBytesRead = 0; - // signal thread to start - LOGV("Signal record thread"); - mWaitWorkCV.signal(); - // do not wait for mStartStopCond if exiting - if (mExiting) { - mActiveTrack.clear(); - status = INVALID_OPERATION; - goto startError; - } - mStartStopCond.wait(mLock); - if (mActiveTrack == 0) { - LOGV("Record failed to start"); - status = BAD_VALUE; - goto startError; - } - LOGV("Record started OK"); - return status; - } -startError: - AudioSystem::stopInput(mId); - return status; -} - -void AudioFlinger::RecordThread::stop(RecordThread::RecordTrack* recordTrack) { - LOGV("RecordThread::stop"); - sp <ThreadBase> strongMe = this; - { - AutoMutex lock(&mLock); - if (mActiveTrack != 0 && recordTrack == mActiveTrack.get()) { - mActiveTrack->mState = TrackBase::PAUSING; - // do not wait for mStartStopCond if exiting - if (mExiting) { - return; - } - mStartStopCond.wait(mLock); - // if we have been restarted, recordTrack == mActiveTrack.get() here - if (mActiveTrack == 0 || recordTrack != mActiveTrack.get()) { - mLock.unlock(); - AudioSystem::stopInput(mId); - mLock.lock(); - LOGV("Record stopped OK"); - } - } - } -} - -status_t AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - pid_t pid = 0; - - snprintf(buffer, SIZE, "\nInput thread %p internals\n", this); - result.append(buffer); - - if (mActiveTrack != 0) { - result.append("Active Track:\n"); - result.append(" Clien Fmt Chn Session Buf S SRate Serv User\n"); - mActiveTrack->dump(buffer, SIZE); - result.append(buffer); - - snprintf(buffer, SIZE, "In index: %d\n", mRsmpInIndex); - result.append(buffer); - snprintf(buffer, SIZE, "In size: %d\n", mInputBytes); - result.append(buffer); - snprintf(buffer, SIZE, "Resampling: %d\n", (mResampler != 0)); - result.append(buffer); - snprintf(buffer, SIZE, "Out channel count: %d\n", mReqChannelCount); - result.append(buffer); - snprintf(buffer, SIZE, "Out sample rate: %d\n", mReqSampleRate); - result.append(buffer); - - - } else { - result.append("No record client\n"); - } - write(fd, result.string(), result.size()); - - dumpBase(fd, args); - - return NO_ERROR; -} - -status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer* buffer) -{ - size_t framesReq = buffer->frameCount; - size_t framesReady = mFrameCount - mRsmpInIndex; - int channelCount; - - if (framesReady == 0) { - mBytesRead = mInput->read(mRsmpInBuffer, mInputBytes); - if (mBytesRead < 0) { - LOGE("RecordThread::getNextBuffer() Error reading audio input"); - if (mActiveTrack->mState == TrackBase::ACTIVE) { - // Force input into standby so that it tries to - // recover at next read attempt - mInput->standby(); - usleep(5000); - } - buffer->raw = 0; - buffer->frameCount = 0; - return NOT_ENOUGH_DATA; - } - mRsmpInIndex = 0; - framesReady = mFrameCount; - } - - if (framesReq > framesReady) { - framesReq = framesReady; - } - - if (mChannelCount == 1 && mReqChannelCount == 2) { - channelCount = 1; - } else { - channelCount = 2; - } - buffer->raw = mRsmpInBuffer + mRsmpInIndex * channelCount; - buffer->frameCount = framesReq; - return NO_ERROR; -} - -void AudioFlinger::RecordThread::releaseBuffer(AudioBufferProvider::Buffer* buffer) -{ - mRsmpInIndex += buffer->frameCount; - buffer->frameCount = 0; -} - -bool AudioFlinger::RecordThread::checkForNewParameters_l() -{ - bool reconfig = false; - - while (!mNewParameters.isEmpty()) { - status_t status = NO_ERROR; - String8 keyValuePair = mNewParameters[0]; - AudioParameter param = AudioParameter(keyValuePair); - int value; - int reqFormat = mFormat; - int reqSamplingRate = mReqSampleRate; - int reqChannelCount = mReqChannelCount; - - if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) { - reqSamplingRate = value; - reconfig = true; - } - if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) { - reqFormat = value; - reconfig = true; - } - if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) { - reqChannelCount = AudioSystem::popCount(value); - reconfig = true; - } - if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) { - // do not accept frame count changes if tracks are open as the track buffer - // size depends on frame count and correct behavior would not be garantied - // if frame count is changed after track creation - if (mActiveTrack != 0) { - status = INVALID_OPERATION; - } else { - reconfig = true; - } - } - if (status == NO_ERROR) { - status = mInput->setParameters(keyValuePair); - if (status == INVALID_OPERATION) { - mInput->standby(); - status = mInput->setParameters(keyValuePair); - } - if (reconfig) { - if (status == BAD_VALUE && - reqFormat == mInput->format() && reqFormat == AudioSystem::PCM_16_BIT && - ((int)mInput->sampleRate() <= 2 * reqSamplingRate) && - (AudioSystem::popCount(mInput->channels()) < 3) && (reqChannelCount < 3)) { - status = NO_ERROR; - } - if (status == NO_ERROR) { - readInputParameters(); - sendConfigEvent_l(AudioSystem::INPUT_CONFIG_CHANGED); - } - } - } - - mNewParameters.removeAt(0); - - mParamStatus = status; - mParamCond.signal(); - mWaitWorkCV.wait(mLock); - } - return reconfig; -} - -String8 AudioFlinger::RecordThread::getParameters(const String8& keys) -{ - return mInput->getParameters(keys); -} - -void AudioFlinger::RecordThread::audioConfigChanged_l(int event, int param) { - AudioSystem::OutputDescriptor desc; - void *param2 = 0; - - switch (event) { - case AudioSystem::INPUT_OPENED: - case AudioSystem::INPUT_CONFIG_CHANGED: - desc.channels = mChannels; - desc.samplingRate = mSampleRate; - desc.format = mFormat; - desc.frameCount = mFrameCount; - desc.latency = 0; - param2 = &desc; - break; - - case AudioSystem::INPUT_CLOSED: - default: - break; - } - mAudioFlinger->audioConfigChanged_l(event, mId, param2); -} - -void AudioFlinger::RecordThread::readInputParameters() -{ - if (mRsmpInBuffer) delete mRsmpInBuffer; - if (mRsmpOutBuffer) delete mRsmpOutBuffer; - if (mResampler) delete mResampler; - mResampler = 0; - - mSampleRate = mInput->sampleRate(); - mChannels = mInput->channels(); - mChannelCount = (uint16_t)AudioSystem::popCount(mChannels); - mFormat = mInput->format(); - mFrameSize = (uint16_t)mInput->frameSize(); - mInputBytes = mInput->bufferSize(); - mFrameCount = mInputBytes / mFrameSize; - mRsmpInBuffer = new int16_t[mFrameCount * mChannelCount]; - - if (mSampleRate != mReqSampleRate && mChannelCount < 3 && mReqChannelCount < 3) - { - int channelCount; - // optmization: if mono to mono, use the resampler in stereo to stereo mode to avoid - // stereo to mono post process as the resampler always outputs stereo. - if (mChannelCount == 1 && mReqChannelCount == 2) { - channelCount = 1; - } else { - channelCount = 2; - } - mResampler = AudioResampler::create(16, channelCount, mReqSampleRate); - mResampler->setSampleRate(mSampleRate); - mResampler->setVolume(AudioMixer::UNITY_GAIN, AudioMixer::UNITY_GAIN); - mRsmpOutBuffer = new int32_t[mFrameCount * 2]; - - // optmization: if mono to mono, alter input frame count as if we were inputing stereo samples - if (mChannelCount == 1 && mReqChannelCount == 1) { - mFrameCount >>= 1; - } - - } - mRsmpInIndex = mFrameCount; -} - -unsigned int AudioFlinger::RecordThread::getInputFramesLost() -{ - return mInput->getInputFramesLost(); -} - -// ---------------------------------------------------------------------------- - -int AudioFlinger::openOutput(uint32_t *pDevices, - uint32_t *pSamplingRate, - uint32_t *pFormat, - uint32_t *pChannels, - uint32_t *pLatencyMs, - uint32_t flags) -{ - status_t status; - PlaybackThread *thread = NULL; - mHardwareStatus = AUDIO_HW_OUTPUT_OPEN; - uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0; - uint32_t format = pFormat ? *pFormat : 0; - uint32_t channels = pChannels ? *pChannels : 0; - uint32_t latency = pLatencyMs ? *pLatencyMs : 0; - - LOGV("openOutput(), Device %x, SamplingRate %d, Format %d, Channels %x, flags %x", - pDevices ? *pDevices : 0, - samplingRate, - format, - channels, - flags); - - if (pDevices == NULL || *pDevices == 0) { - return 0; - } - Mutex::Autolock _l(mLock); - - AudioStreamOut *output = mAudioHardware->openOutputStream(*pDevices, - (int *)&format, - &channels, - &samplingRate, - &status); - LOGV("openOutput() openOutputStream returned output %p, SamplingRate %d, Format %d, Channels %x, status %d", - output, - samplingRate, - format, - channels, - status); - - mHardwareStatus = AUDIO_HW_IDLE; - if (output != 0) { - int id = nextUniqueId(); - if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) || - (format != AudioSystem::PCM_16_BIT) || - (channels != AudioSystem::CHANNEL_OUT_STEREO)) { - thread = new DirectOutputThread(this, output, id, *pDevices); - LOGV("openOutput() created direct output: ID %d thread %p", id, thread); - } else { - thread = new MixerThread(this, output, id, *pDevices); - LOGV("openOutput() created mixer output: ID %d thread %p", id, thread); - -#ifdef LVMX - unsigned bitsPerSample = - (format == AudioSystem::PCM_16_BIT) ? 16 : - ((format == AudioSystem::PCM_8_BIT) ? 8 : 0); - unsigned channelCount = (channels == AudioSystem::CHANNEL_OUT_STEREO) ? 2 : 1; - int audioOutputType = LifeVibes::threadIdToAudioOutputType(thread->id()); - - LifeVibes::init_aot(audioOutputType, samplingRate, bitsPerSample, channelCount); - LifeVibes::setDevice(audioOutputType, *pDevices); -#endif - - } - mPlaybackThreads.add(id, thread); - - if (pSamplingRate) *pSamplingRate = samplingRate; - if (pFormat) *pFormat = format; - if (pChannels) *pChannels = channels; - if (pLatencyMs) *pLatencyMs = thread->latency(); - - // notify client processes of the new output creation - thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED); - return id; - } - - return 0; -} - -int AudioFlinger::openDuplicateOutput(int output1, int output2) -{ - Mutex::Autolock _l(mLock); - MixerThread *thread1 = checkMixerThread_l(output1); - MixerThread *thread2 = checkMixerThread_l(output2); - - if (thread1 == NULL || thread2 == NULL) { - LOGW("openDuplicateOutput() wrong output mixer type for output %d or %d", output1, output2); - return 0; - } - - int id = nextUniqueId(); - DuplicatingThread *thread = new DuplicatingThread(this, thread1, id); - thread->addOutputTrack(thread2); - mPlaybackThreads.add(id, thread); - // notify client processes of the new output creation - thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED); - return id; -} - -status_t AudioFlinger::closeOutput(int output) -{ - // keep strong reference on the playback thread so that - // it is not destroyed while exit() is executed - sp <PlaybackThread> thread; - { - Mutex::Autolock _l(mLock); - thread = checkPlaybackThread_l(output); - if (thread == NULL) { - return BAD_VALUE; - } - - LOGV("closeOutput() %d", output); - - if (thread->type() == PlaybackThread::MIXER) { - for (size_t i = 0; i < mPlaybackThreads.size(); i++) { - if (mPlaybackThreads.valueAt(i)->type() == PlaybackThread::DUPLICATING) { - DuplicatingThread *dupThread = (DuplicatingThread *)mPlaybackThreads.valueAt(i).get(); - dupThread->removeOutputTrack((MixerThread *)thread.get()); - } - } - } - void *param2 = 0; - audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, output, param2); - mPlaybackThreads.removeItem(output); - } - thread->exit(); - - if (thread->type() != PlaybackThread::DUPLICATING) { - mAudioHardware->closeOutputStream(thread->getOutput()); - } - return NO_ERROR; -} - -status_t AudioFlinger::suspendOutput(int output) -{ - Mutex::Autolock _l(mLock); - PlaybackThread *thread = checkPlaybackThread_l(output); - - if (thread == NULL) { - return BAD_VALUE; - } - - LOGV("suspendOutput() %d", output); - thread->suspend(); - - return NO_ERROR; -} - -status_t AudioFlinger::restoreOutput(int output) -{ - Mutex::Autolock _l(mLock); - PlaybackThread *thread = checkPlaybackThread_l(output); - - if (thread == NULL) { - return BAD_VALUE; - } - - LOGV("restoreOutput() %d", output); - - thread->restore(); - - return NO_ERROR; -} - -int AudioFlinger::openInput(uint32_t *pDevices, - uint32_t *pSamplingRate, - uint32_t *pFormat, - uint32_t *pChannels, - uint32_t acoustics) -{ - status_t status; - RecordThread *thread = NULL; - uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0; - uint32_t format = pFormat ? *pFormat : 0; - uint32_t channels = pChannels ? *pChannels : 0; - uint32_t reqSamplingRate = samplingRate; - uint32_t reqFormat = format; - uint32_t reqChannels = channels; - - if (pDevices == NULL || *pDevices == 0) { - return 0; - } - Mutex::Autolock _l(mLock); - - AudioStreamIn *input = mAudioHardware->openInputStream(*pDevices, - (int *)&format, - &channels, - &samplingRate, - &status, - (AudioSystem::audio_in_acoustics)acoustics); - LOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, acoustics %x, status %d", - input, - samplingRate, - format, - channels, - acoustics, - status); - - // If the input could not be opened with the requested parameters and we can handle the conversion internally, - // try to open again with the proposed parameters. The AudioFlinger can resample the input and do mono to stereo - // or stereo to mono conversions on 16 bit PCM inputs. - if (input == 0 && status == BAD_VALUE && - reqFormat == format && format == AudioSystem::PCM_16_BIT && - (samplingRate <= 2 * reqSamplingRate) && - (AudioSystem::popCount(channels) < 3) && (AudioSystem::popCount(reqChannels) < 3)) { - LOGV("openInput() reopening with proposed sampling rate and channels"); - input = mAudioHardware->openInputStream(*pDevices, - (int *)&format, - &channels, - &samplingRate, - &status, - (AudioSystem::audio_in_acoustics)acoustics); - } - - if (input != 0) { - int id = nextUniqueId(); - // Start record thread - thread = new RecordThread(this, input, reqSamplingRate, reqChannels, id); - mRecordThreads.add(id, thread); - LOGV("openInput() created record thread: ID %d thread %p", id, thread); - if (pSamplingRate) *pSamplingRate = reqSamplingRate; - if (pFormat) *pFormat = format; - if (pChannels) *pChannels = reqChannels; - - input->standby(); - - // notify client processes of the new input creation - thread->audioConfigChanged_l(AudioSystem::INPUT_OPENED); - return id; - } - - return 0; -} - -status_t AudioFlinger::closeInput(int input) -{ - // keep strong reference on the record thread so that - // it is not destroyed while exit() is executed - sp <RecordThread> thread; - { - Mutex::Autolock _l(mLock); - thread = checkRecordThread_l(input); - if (thread == NULL) { - return BAD_VALUE; - } - - LOGV("closeInput() %d", input); - void *param2 = 0; - audioConfigChanged_l(AudioSystem::INPUT_CLOSED, input, param2); - mRecordThreads.removeItem(input); - } - thread->exit(); - - mAudioHardware->closeInputStream(thread->getInput()); - - return NO_ERROR; -} - -status_t AudioFlinger::setStreamOutput(uint32_t stream, int output) -{ - Mutex::Autolock _l(mLock); - MixerThread *dstThread = checkMixerThread_l(output); - if (dstThread == NULL) { - LOGW("setStreamOutput() bad output id %d", output); - return BAD_VALUE; - } - - LOGV("setStreamOutput() stream %d to output %d", stream, output); - audioConfigChanged_l(AudioSystem::STREAM_CONFIG_CHANGED, output, &stream); - - for (size_t i = 0; i < mPlaybackThreads.size(); i++) { - PlaybackThread *thread = mPlaybackThreads.valueAt(i).get(); - if (thread != dstThread && - thread->type() != PlaybackThread::DIRECT) { - MixerThread *srcThread = (MixerThread *)thread; - srcThread->invalidateTracks(stream); - } - } - - return NO_ERROR; -} - - -int AudioFlinger::newAudioSessionId() -{ - return nextUniqueId(); -} - -// checkPlaybackThread_l() must be called with AudioFlinger::mLock held -AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(int output) const -{ - PlaybackThread *thread = NULL; - if (mPlaybackThreads.indexOfKey(output) >= 0) { - thread = (PlaybackThread *)mPlaybackThreads.valueFor(output).get(); - } - return thread; -} - -// checkMixerThread_l() must be called with AudioFlinger::mLock held -AudioFlinger::MixerThread *AudioFlinger::checkMixerThread_l(int output) const -{ - PlaybackThread *thread = checkPlaybackThread_l(output); - if (thread != NULL) { - if (thread->type() == PlaybackThread::DIRECT) { - thread = NULL; - } - } - return (MixerThread *)thread; -} - -// checkRecordThread_l() must be called with AudioFlinger::mLock held -AudioFlinger::RecordThread *AudioFlinger::checkRecordThread_l(int input) const -{ - RecordThread *thread = NULL; - if (mRecordThreads.indexOfKey(input) >= 0) { - thread = (RecordThread *)mRecordThreads.valueFor(input).get(); - } - return thread; -} - -int AudioFlinger::nextUniqueId() -{ - return android_atomic_inc(&mNextUniqueId); -} - -// ---------------------------------------------------------------------------- -// Effect management -// ---------------------------------------------------------------------------- - - -status_t AudioFlinger::loadEffectLibrary(const char *libPath, int *handle) -{ - Mutex::Autolock _l(mLock); - return EffectLoadLibrary(libPath, handle); -} - -status_t AudioFlinger::unloadEffectLibrary(int handle) -{ - Mutex::Autolock _l(mLock); - return EffectUnloadLibrary(handle); -} - -status_t AudioFlinger::queryNumberEffects(uint32_t *numEffects) -{ - Mutex::Autolock _l(mLock); - return EffectQueryNumberEffects(numEffects); -} - -status_t AudioFlinger::queryEffect(uint32_t index, effect_descriptor_t *descriptor) -{ - Mutex::Autolock _l(mLock); - return EffectQueryEffect(index, descriptor); -} - -status_t AudioFlinger::getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *descriptor) -{ - Mutex::Autolock _l(mLock); - return EffectGetDescriptor(pUuid, descriptor); -} - - -// this UUID must match the one defined in media/libeffects/EffectVisualizer.cpp -static const effect_uuid_t VISUALIZATION_UUID_ = - {0xd069d9e0, 0x8329, 0x11df, 0x9168, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}; - -sp<IEffect> AudioFlinger::createEffect(pid_t pid, - effect_descriptor_t *pDesc, - const sp<IEffectClient>& effectClient, - int32_t priority, - int output, - int sessionId, - status_t *status, - int *id, - int *enabled) -{ - status_t lStatus = NO_ERROR; - sp<EffectHandle> handle; - effect_interface_t itfe; - effect_descriptor_t desc; - sp<Client> client; - wp<Client> wclient; - - LOGV("createEffect pid %d, client %p, priority %d, sessionId %d, output %d", pid, effectClient.get(), priority, sessionId, output); - - if (pDesc == NULL) { - lStatus = BAD_VALUE; - goto Exit; - } - - { - Mutex::Autolock _l(mLock); - - // check recording permission for visualizer - if (memcmp(&pDesc->type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0 || - memcmp(&pDesc->uuid, &VISUALIZATION_UUID_, sizeof(effect_uuid_t)) == 0) { - if (!recordingAllowed()) { - lStatus = PERMISSION_DENIED; - goto Exit; - } - } - - if (!EffectIsNullUuid(&pDesc->uuid)) { - // if uuid is specified, request effect descriptor - lStatus = EffectGetDescriptor(&pDesc->uuid, &desc); - if (lStatus < 0) { - LOGW("createEffect() error %d from EffectGetDescriptor", lStatus); - goto Exit; - } - } else { - // if uuid is not specified, look for an available implementation - // of the required type in effect factory - if (EffectIsNullUuid(&pDesc->type)) { - LOGW("createEffect() no effect type"); - lStatus = BAD_VALUE; - goto Exit; - } - uint32_t numEffects = 0; - effect_descriptor_t d; - bool found = false; - - lStatus = EffectQueryNumberEffects(&numEffects); - if (lStatus < 0) { - LOGW("createEffect() error %d from EffectQueryNumberEffects", lStatus); - goto Exit; - } - for (uint32_t i = 0; i < numEffects; i++) { - lStatus = EffectQueryEffect(i, &desc); - if (lStatus < 0) { - LOGW("createEffect() error %d from EffectQueryEffect", lStatus); - continue; - } - if (memcmp(&desc.type, &pDesc->type, sizeof(effect_uuid_t)) == 0) { - // If matching type found save effect descriptor. If the session is - // 0 and the effect is not auxiliary, continue enumeration in case - // an auxiliary version of this effect type is available - found = true; - memcpy(&d, &desc, sizeof(effect_descriptor_t)); - if (sessionId != 0 || - (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { - break; - } - } - } - if (!found) { - lStatus = BAD_VALUE; - LOGW("createEffect() effect not found"); - goto Exit; - } - // For same effect type, chose auxiliary version over insert version if - // connect to output mix (Compliance to OpenSL ES) - if (sessionId == 0 && - (d.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_AUXILIARY) { - memcpy(&desc, &d, sizeof(effect_descriptor_t)); - } - } - - // Do not allow auxiliary effects on a session different from 0 (output mix) - if (sessionId != 0 && - (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { - lStatus = INVALID_OPERATION; - goto Exit; - } - - // Session -1 is reserved for output stage effects that can only be created - // by audio policy manager (running in same process) - if (sessionId == -1 && getpid() != IPCThreadState::self()->getCallingPid()) { - lStatus = INVALID_OPERATION; - goto Exit; - } - - // return effect descriptor - memcpy(pDesc, &desc, sizeof(effect_descriptor_t)); - - // If output is not specified try to find a matching audio session ID in one of the - // output threads. - // TODO: allow attachment of effect to inputs - if (output == 0) { - if (sessionId <= 0) { - // default to first output - // TODO: define criteria to choose output when not specified. Or - // receive output from audio policy manager - if (mPlaybackThreads.size() != 0) { - output = mPlaybackThreads.keyAt(0); - } - } else { - // look for the thread where the specified audio session is present - for (size_t i = 0; i < mPlaybackThreads.size(); i++) { - if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId)) { - output = mPlaybackThreads.keyAt(i); - break; - } - } - } - } - PlaybackThread *thread = checkPlaybackThread_l(output); - if (thread == NULL) { - LOGE("unknown output thread"); - lStatus = BAD_VALUE; - goto Exit; - } - - wclient = mClients.valueFor(pid); - - if (wclient != NULL) { - client = wclient.promote(); - } else { - client = new Client(this, pid); - mClients.add(pid, client); - } - - // create effect on selected output trhead - handle = thread->createEffect_l(client, effectClient, priority, sessionId, &desc, enabled, &lStatus); - if (handle != 0 && id != NULL) { - *id = handle->id(); - } - } - -Exit: - if(status) { - *status = lStatus; - } - return handle; -} - -status_t AudioFlinger::registerEffectResource_l(effect_descriptor_t *desc) { - if (mTotalEffectsCpuLoad + desc->cpuLoad > MAX_EFFECTS_CPU_LOAD) { - LOGW("registerEffectResource() CPU Load limit exceeded for Fx %s, CPU %f MIPS", - desc->name, (float)desc->cpuLoad/10); - return INVALID_OPERATION; - } - if (mTotalEffectsMemory + desc->memoryUsage > MAX_EFFECTS_MEMORY) { - LOGW("registerEffectResource() memory limit exceeded for Fx %s, Memory %d KB", - desc->name, desc->memoryUsage); - return INVALID_OPERATION; - } - mTotalEffectsCpuLoad += desc->cpuLoad; - mTotalEffectsMemory += desc->memoryUsage; - LOGV("registerEffectResource_l() effect %s, CPU %d, memory %d", - desc->name, desc->cpuLoad, desc->memoryUsage); - LOGV(" total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory); - return NO_ERROR; -} - -void AudioFlinger::unregisterEffectResource_l(effect_descriptor_t *desc) { - mTotalEffectsCpuLoad -= desc->cpuLoad; - mTotalEffectsMemory -= desc->memoryUsage; - LOGV("unregisterEffectResource_l() effect %s, CPU %d, memory %d", - desc->name, desc->cpuLoad, desc->memoryUsage); - LOGV(" total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory); -} - -// PlaybackThread::createEffect_l() must be called with AudioFlinger::mLock held -sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l( - const sp<AudioFlinger::Client>& client, - const sp<IEffectClient>& effectClient, - int32_t priority, - int sessionId, - effect_descriptor_t *desc, - int *enabled, - status_t *status - ) -{ - sp<EffectModule> effect; - sp<EffectHandle> handle; - status_t lStatus; - sp<Track> track; - sp<EffectChain> chain; - bool effectCreated = false; - bool effectRegistered = false; - - if (mOutput == 0) { - LOGW("createEffect_l() Audio driver not initialized."); - lStatus = NO_INIT; - goto Exit; - } - - // Do not allow auxiliary effect on session other than 0 - if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY && - sessionId != 0) { - LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", desc->name, sessionId); - lStatus = BAD_VALUE; - goto Exit; - } - - // Do not allow effects with session ID 0 on direct output or duplicating threads - // TODO: add rule for hw accelerated effects on direct outputs with non PCM format - if (sessionId == 0 && mType != MIXER) { - LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", desc->name, sessionId); - lStatus = BAD_VALUE; - goto Exit; - } - - LOGV("createEffect_l() thread %p effect %s on session %d", this, desc->name, sessionId); - - { // scope for mLock - Mutex::Autolock _l(mLock); - - // check for existing effect chain with the requested audio session - chain = getEffectChain_l(sessionId); - if (chain == 0) { - // create a new chain for this session - LOGV("createEffect_l() new effect chain for session %d", sessionId); - chain = new EffectChain(this, sessionId); - addEffectChain_l(chain); - } else { - effect = chain->getEffectFromDesc(desc); - } - - LOGV("createEffect_l() got effect %p on chain %p", effect == 0 ? 0 : effect.get(), chain.get()); - - if (effect == 0) { - // Check CPU and memory usage - lStatus = mAudioFlinger->registerEffectResource_l(desc); - if (lStatus != NO_ERROR) { - goto Exit; - } - effectRegistered = true; - // create a new effect module if none present in the chain - effect = new EffectModule(this, chain, desc, mAudioFlinger->nextUniqueId(), sessionId); - lStatus = effect->status(); - if (lStatus != NO_ERROR) { - goto Exit; - } - lStatus = chain->addEffect(effect); - if (lStatus != NO_ERROR) { - goto Exit; - } - effectCreated = true; - - effect->setDevice(mDevice); - effect->setMode(mAudioFlinger->getMode()); - } - // create effect handle and connect it to effect module - handle = new EffectHandle(effect, client, effectClient, priority); - lStatus = effect->addHandle(handle); - if (enabled) { - *enabled = (int)effect->isEnabled(); - } - } - -Exit: - if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) { - if (effectCreated) { - if (chain->removeEffect(effect) == 0) { - removeEffectChain_l(chain); - } - } - if (effectRegistered) { - mAudioFlinger->unregisterEffectResource_l(desc); - } - handle.clear(); - } - - if(status) { - *status = lStatus; - } - return handle; -} - -void AudioFlinger::PlaybackThread::disconnectEffect(const sp< EffectModule>& effect, - const wp<EffectHandle>& handle) { - effect_descriptor_t desc = effect->desc(); - Mutex::Autolock _l(mLock); - // delete the effect module if removing last handle on it - if (effect->removeHandle(handle) == 0) { - if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { - detachAuxEffect_l(effect->id()); - } - sp<EffectChain> chain = effect->chain().promote(); - if (chain != 0) { - // remove effect chain if remove last effect - if (chain->removeEffect(effect) == 0) { - removeEffectChain_l(chain); - } - } - mLock.unlock(); - mAudioFlinger->mLock.lock(); - mAudioFlinger->unregisterEffectResource_l(&desc); - mAudioFlinger->mLock.unlock(); - } -} - -status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& chain) -{ - int session = chain->sessionId(); - int16_t *buffer = mMixBuffer; - bool ownsBuffer = false; - - LOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session); - if (session > 0) { - // Only one effect chain can be present in direct output thread and it uses - // the mix buffer as input - if (mType != DIRECT) { - size_t numSamples = mFrameCount * mChannelCount; - buffer = new int16_t[numSamples]; - memset(buffer, 0, numSamples * sizeof(int16_t)); - LOGV("addEffectChain_l() creating new input buffer %p session %d", buffer, session); - ownsBuffer = true; - } - - // Attach all tracks with same session ID to this chain. - for (size_t i = 0; i < mTracks.size(); ++i) { - sp<Track> track = mTracks[i]; - if (session == track->sessionId()) { - LOGV("addEffectChain_l() track->setMainBuffer track %p buffer %p", track.get(), buffer); - track->setMainBuffer(buffer); - } - } - - // indicate all active tracks in the chain - for (size_t i = 0 ; i < mActiveTracks.size() ; ++i) { - sp<Track> track = mActiveTracks[i].promote(); - if (track == 0) continue; - if (session == track->sessionId()) { - LOGV("addEffectChain_l() activating track %p on session %d", track.get(), session); - chain->startTrack(); - } - } - } - - chain->setInBuffer(buffer, ownsBuffer); - chain->setOutBuffer(mMixBuffer); - // Effect chain for session -1 is inserted at end of effect chains list - // in order to be processed last as it contains output stage effects - // Effect chain for session 0 is inserted before session -1 to be processed - // after track specific effects and before output stage - // Effect chain for session other than 0 is inserted at beginning of effect - // chains list to be processed before output mix effects. Relative order between - // sessions other than 0 is not important - size_t size = mEffectChains.size(); - size_t i = 0; - for (i = 0; i < size; i++) { - if (mEffectChains[i]->sessionId() < session) break; - } - mEffectChains.insertAt(chain, i); - - return NO_ERROR; -} - -size_t AudioFlinger::PlaybackThread::removeEffectChain_l(const sp<EffectChain>& chain) -{ - int session = chain->sessionId(); - - LOGV("removeEffectChain_l() %p from thread %p for session %d", chain.get(), this, session); - - for (size_t i = 0; i < mEffectChains.size(); i++) { - if (chain == mEffectChains[i]) { - mEffectChains.removeAt(i); - // detach all tracks with same session ID from this chain - for (size_t i = 0; i < mTracks.size(); ++i) { - sp<Track> track = mTracks[i]; - if (session == track->sessionId()) { - track->setMainBuffer(mMixBuffer); - } - } - } - } - return mEffectChains.size(); -} - -void AudioFlinger::PlaybackThread::lockEffectChains_l() -{ - for (size_t i = 0; i < mEffectChains.size(); i++) { - mEffectChains[i]->lock(); - } -} - -void AudioFlinger::PlaybackThread::unlockEffectChains() -{ - Mutex::Autolock _l(mLock); - for (size_t i = 0; i < mEffectChains.size(); i++) { - mEffectChains[i]->unlock(); - } -} - -sp<AudioFlinger::EffectModule> AudioFlinger::PlaybackThread::getEffect_l(int sessionId, int effectId) -{ - sp<EffectModule> effect; - - sp<EffectChain> chain = getEffectChain_l(sessionId); - if (chain != 0) { - effect = chain->getEffectFromId(effectId); - } - return effect; -} - -status_t AudioFlinger::PlaybackThread::attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId) -{ - Mutex::Autolock _l(mLock); - return attachAuxEffect_l(track, EffectId); -} - -status_t AudioFlinger::PlaybackThread::attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId) -{ - status_t status = NO_ERROR; - - if (EffectId == 0) { - track->setAuxBuffer(0, NULL); - } else { - // Auxiliary effects are always in audio session 0 - sp<EffectModule> effect = getEffect_l(0, EffectId); - if (effect != 0) { - if ((effect->desc().flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { - track->setAuxBuffer(EffectId, (int32_t *)effect->inBuffer()); - } else { - status = INVALID_OPERATION; - } - } else { - status = BAD_VALUE; - } - } - return status; -} - -void AudioFlinger::PlaybackThread::detachAuxEffect_l(int effectId) -{ - for (size_t i = 0; i < mTracks.size(); ++i) { - sp<Track> track = mTracks[i]; - if (track->auxEffectId() == effectId) { - attachAuxEffect_l(track, 0); - } - } -} - -// ---------------------------------------------------------------------------- -// EffectModule implementation -// ---------------------------------------------------------------------------- - -#undef LOG_TAG -#define LOG_TAG "AudioFlinger::EffectModule" - -AudioFlinger::EffectModule::EffectModule(const wp<ThreadBase>& wThread, - const wp<AudioFlinger::EffectChain>& chain, - effect_descriptor_t *desc, - int id, - int sessionId) - : mThread(wThread), mChain(chain), mId(id), mSessionId(sessionId), mEffectInterface(NULL), - mStatus(NO_INIT), mState(IDLE) -{ - LOGV("Constructor %p", this); - int lStatus; - sp<ThreadBase> thread = mThread.promote(); - if (thread == 0) { - return; - } - PlaybackThread *p = (PlaybackThread *)thread.get(); - - memcpy(&mDescriptor, desc, sizeof(effect_descriptor_t)); - - // create effect engine from effect factory - mStatus = EffectCreate(&desc->uuid, sessionId, p->id(), &mEffectInterface); - - if (mStatus != NO_ERROR) { - return; - } - lStatus = init(); - if (lStatus < 0) { - mStatus = lStatus; - goto Error; - } - - LOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface); - return; -Error: - EffectRelease(mEffectInterface); - mEffectInterface = NULL; - LOGV("Constructor Error %d", mStatus); -} - -AudioFlinger::EffectModule::~EffectModule() -{ - LOGV("Destructor %p", this); - if (mEffectInterface != NULL) { - // release effect engine - EffectRelease(mEffectInterface); - } -} - -status_t AudioFlinger::EffectModule::addHandle(sp<EffectHandle>& handle) -{ - status_t status; - - Mutex::Autolock _l(mLock); - // First handle in mHandles has highest priority and controls the effect module - int priority = handle->priority(); - size_t size = mHandles.size(); - sp<EffectHandle> h; - size_t i; - for (i = 0; i < size; i++) { - h = mHandles[i].promote(); - if (h == 0) continue; - if (h->priority() <= priority) break; - } - // if inserted in first place, move effect control from previous owner to this handle - if (i == 0) { - if (h != 0) { - h->setControl(false, true); - } - handle->setControl(true, false); - status = NO_ERROR; - } else { - status = ALREADY_EXISTS; - } - mHandles.insertAt(handle, i); - return status; -} - -size_t AudioFlinger::EffectModule::removeHandle(const wp<EffectHandle>& handle) -{ - Mutex::Autolock _l(mLock); - size_t size = mHandles.size(); - size_t i; - for (i = 0; i < size; i++) { - if (mHandles[i] == handle) break; - } - if (i == size) { - return size; - } - mHandles.removeAt(i); - size = mHandles.size(); - // if removed from first place, move effect control from this handle to next in line - if (i == 0 && size != 0) { - sp<EffectHandle> h = mHandles[0].promote(); - if (h != 0) { - h->setControl(true, true); - } - } - - return size; -} - -void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle) -{ - // keep a strong reference on this EffectModule to avoid calling the - // destructor before we exit - sp<EffectModule> keep(this); - { - sp<ThreadBase> thread = mThread.promote(); - if (thread != 0) { - PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); - playbackThread->disconnectEffect(keep, handle); - } - } -} - -void AudioFlinger::EffectModule::updateState() { - Mutex::Autolock _l(mLock); - - switch (mState) { - case RESTART: - reset_l(); - // FALL THROUGH - - case STARTING: - // clear auxiliary effect input buffer for next accumulation - if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { - memset(mConfig.inputCfg.buffer.raw, - 0, - mConfig.inputCfg.buffer.frameCount*sizeof(int32_t)); - } - start_l(); - mState = ACTIVE; - break; - case STOPPING: - stop_l(); - mDisableWaitCnt = mMaxDisableWaitCnt; - mState = STOPPED; - break; - case STOPPED: - // mDisableWaitCnt is forced to 1 by process() when the engine indicates the end of the - // turn off sequence. - if (--mDisableWaitCnt == 0) { - reset_l(); - mState = IDLE; - } - break; - default: //IDLE , ACTIVE - break; - } -} - -void AudioFlinger::EffectModule::process() -{ - Mutex::Autolock _l(mLock); - - if (mEffectInterface == NULL || - mConfig.inputCfg.buffer.raw == NULL || - mConfig.outputCfg.buffer.raw == NULL) { - return; - } - - if (mState == ACTIVE || mState == STOPPING || mState == STOPPED) { - // do 32 bit to 16 bit conversion for auxiliary effect input buffer - if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { - AudioMixer::ditherAndClamp(mConfig.inputCfg.buffer.s32, - mConfig.inputCfg.buffer.s32, - mConfig.inputCfg.buffer.frameCount); - } - - // do the actual processing in the effect engine - int ret = (*mEffectInterface)->process(mEffectInterface, - &mConfig.inputCfg.buffer, - &mConfig.outputCfg.buffer); - - // force transition to IDLE state when engine is ready - if (mState == STOPPED && ret == -ENODATA) { - mDisableWaitCnt = 1; - } - - // clear auxiliary effect input buffer for next accumulation - if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { - memset(mConfig.inputCfg.buffer.raw, 0, mConfig.inputCfg.buffer.frameCount*sizeof(int32_t)); - } - } else if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_INSERT && - mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw){ - // If an insert effect is idle and input buffer is different from output buffer, copy input to - // output - sp<EffectChain> chain = mChain.promote(); - if (chain != 0 && chain->activeTracks() != 0) { - size_t size = mConfig.inputCfg.buffer.frameCount * sizeof(int16_t); - if (mConfig.inputCfg.channels == CHANNEL_STEREO) { - size *= 2; - } - memcpy(mConfig.outputCfg.buffer.raw, mConfig.inputCfg.buffer.raw, size); - } - } -} - -void AudioFlinger::EffectModule::reset_l() -{ - if (mEffectInterface == NULL) { - return; - } - (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_RESET, 0, NULL, 0, NULL); -} - -status_t AudioFlinger::EffectModule::configure() -{ - uint32_t channels; - if (mEffectInterface == NULL) { - return NO_INIT; - } - - sp<ThreadBase> thread = mThread.promote(); - if (thread == 0) { - return DEAD_OBJECT; - } - - // TODO: handle configuration of effects replacing track process - if (thread->channelCount() == 1) { - channels = CHANNEL_MONO; - } else { - channels = CHANNEL_STEREO; - } - - if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { - mConfig.inputCfg.channels = CHANNEL_MONO; - } else { - mConfig.inputCfg.channels = channels; - } - mConfig.outputCfg.channels = channels; - mConfig.inputCfg.format = SAMPLE_FORMAT_PCM_S15; - mConfig.outputCfg.format = SAMPLE_FORMAT_PCM_S15; - mConfig.inputCfg.samplingRate = thread->sampleRate(); - mConfig.outputCfg.samplingRate = mConfig.inputCfg.samplingRate; - mConfig.inputCfg.bufferProvider.cookie = NULL; - mConfig.inputCfg.bufferProvider.getBuffer = NULL; - mConfig.inputCfg.bufferProvider.releaseBuffer = NULL; - mConfig.outputCfg.bufferProvider.cookie = NULL; - mConfig.outputCfg.bufferProvider.getBuffer = NULL; - mConfig.outputCfg.bufferProvider.releaseBuffer = NULL; - mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; - // Insert effect: - // - in session 0 or -1, always overwrites output buffer: input buffer == output buffer - // - in other sessions: - // last effect in the chain accumulates in output buffer: input buffer != output buffer - // other effect: overwrites output buffer: input buffer == output buffer - // Auxiliary effect: - // accumulates in output buffer: input buffer != output buffer - // Therefore: accumulate <=> input buffer != output buffer - if (mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw) { - mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE; - } else { - mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE; - } - mConfig.inputCfg.mask = EFFECT_CONFIG_ALL; - mConfig.outputCfg.mask = EFFECT_CONFIG_ALL; - mConfig.inputCfg.buffer.frameCount = thread->frameCount(); - mConfig.outputCfg.buffer.frameCount = mConfig.inputCfg.buffer.frameCount; - - status_t cmdStatus; - int size = sizeof(int); - status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_CONFIGURE, sizeof(effect_config_t), &mConfig, &size, &cmdStatus); - if (status == 0) { - status = cmdStatus; - } - - mMaxDisableWaitCnt = (MAX_DISABLE_TIME_MS * mConfig.outputCfg.samplingRate) / - (1000 * mConfig.outputCfg.buffer.frameCount); - - return status; -} - -status_t AudioFlinger::EffectModule::init() -{ - Mutex::Autolock _l(mLock); - if (mEffectInterface == NULL) { - return NO_INIT; - } - status_t cmdStatus; - int size = sizeof(status_t); - status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_INIT, 0, NULL, &size, &cmdStatus); - if (status == 0) { - status = cmdStatus; - } - return status; -} - -status_t AudioFlinger::EffectModule::start_l() -{ - if (mEffectInterface == NULL) { - return NO_INIT; - } - status_t cmdStatus; - int size = sizeof(status_t); - status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_ENABLE, 0, NULL, &size, &cmdStatus); - if (status == 0) { - status = cmdStatus; - } - return status; -} - -status_t AudioFlinger::EffectModule::stop_l() -{ - if (mEffectInterface == NULL) { - return NO_INIT; - } - status_t cmdStatus; - int size = sizeof(status_t); - status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_DISABLE, 0, NULL, &size, &cmdStatus); - if (status == 0) { - status = cmdStatus; - } - return status; -} - -status_t AudioFlinger::EffectModule::command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData) -{ - Mutex::Autolock _l(mLock); -// LOGV("command(), cmdCode: %d, mEffectInterface: %p", cmdCode, mEffectInterface); - - if (mEffectInterface == NULL) { - return NO_INIT; - } - status_t status = (*mEffectInterface)->command(mEffectInterface, cmdCode, cmdSize, pCmdData, replySize, pReplyData); - if (cmdCode != EFFECT_CMD_GET_PARAM && status == NO_ERROR) { - int size = (replySize == NULL) ? 0 : *replySize; - for (size_t i = 1; i < mHandles.size(); i++) { - sp<EffectHandle> h = mHandles[i].promote(); - if (h != 0) { - h->commandExecuted(cmdCode, cmdSize, pCmdData, size, pReplyData); - } - } - } - return status; -} - -status_t AudioFlinger::EffectModule::setEnabled(bool enabled) -{ - Mutex::Autolock _l(mLock); - LOGV("setEnabled %p enabled %d", this, enabled); - - if (enabled != isEnabled()) { - switch (mState) { - // going from disabled to enabled - case IDLE: - mState = STARTING; - break; - case STOPPED: - mState = RESTART; - break; - case STOPPING: - mState = ACTIVE; - break; - - // going from enabled to disabled - case RESTART: - case STARTING: - mState = IDLE; - break; - case ACTIVE: - mState = STOPPING; - break; - } - for (size_t i = 1; i < mHandles.size(); i++) { - sp<EffectHandle> h = mHandles[i].promote(); - if (h != 0) { - h->setEnabled(enabled); - } - } - } - return NO_ERROR; -} - -bool AudioFlinger::EffectModule::isEnabled() -{ - switch (mState) { - case RESTART: - case STARTING: - case ACTIVE: - return true; - case IDLE: - case STOPPING: - case STOPPED: - default: - return false; - } -} - -status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right, bool controller) -{ - Mutex::Autolock _l(mLock); - status_t status = NO_ERROR; - - // Send volume indication if EFFECT_FLAG_VOLUME_IND is set and read back altered volume - // if controller flag is set (Note that controller == TRUE => EFFECT_FLAG_VOLUME_CTRL set) - if ((mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) & (EFFECT_FLAG_VOLUME_CTRL|EFFECT_FLAG_VOLUME_IND)) { - status_t cmdStatus; - uint32_t volume[2]; - uint32_t *pVolume = NULL; - int size = sizeof(volume); - volume[0] = *left; - volume[1] = *right; - if (controller) { - pVolume = volume; - } - status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_SET_VOLUME, size, volume, &size, pVolume); - if (controller && status == NO_ERROR && size == sizeof(volume)) { - *left = volume[0]; - *right = volume[1]; - } - } - return status; -} - -status_t AudioFlinger::EffectModule::setDevice(uint32_t device) -{ - Mutex::Autolock _l(mLock); - status_t status = NO_ERROR; - if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) { - // convert device bit field from AudioSystem to EffectApi format. - device = deviceAudioSystemToEffectApi(device); - if (device == 0) { - return BAD_VALUE; - } - status_t cmdStatus; - int size = sizeof(status_t); - status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_SET_DEVICE, sizeof(uint32_t), &device, &size, &cmdStatus); - if (status == NO_ERROR) { - status = cmdStatus; - } - } - return status; -} - -status_t AudioFlinger::EffectModule::setMode(uint32_t mode) -{ - Mutex::Autolock _l(mLock); - status_t status = NO_ERROR; - if ((mDescriptor.flags & EFFECT_FLAG_AUDIO_MODE_MASK) == EFFECT_FLAG_AUDIO_MODE_IND) { - // convert audio mode from AudioSystem to EffectApi format. - int effectMode = modeAudioSystemToEffectApi(mode); - if (effectMode < 0) { - return BAD_VALUE; - } - status_t cmdStatus; - int size = sizeof(status_t); - status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_SET_AUDIO_MODE, sizeof(int), &effectMode, &size, &cmdStatus); - if (status == NO_ERROR) { - status = cmdStatus; - } - } - return status; -} - -// update this table when AudioSystem::audio_devices or audio_device_e (in EffectApi.h) are modified -const uint32_t AudioFlinger::EffectModule::sDeviceConvTable[] = { - DEVICE_EARPIECE, // AudioSystem::DEVICE_OUT_EARPIECE - DEVICE_SPEAKER, // AudioSystem::DEVICE_OUT_SPEAKER - DEVICE_WIRED_HEADSET, // case AudioSystem::DEVICE_OUT_WIRED_HEADSET - DEVICE_WIRED_HEADPHONE, // AudioSystem::DEVICE_OUT_WIRED_HEADPHONE - DEVICE_BLUETOOTH_SCO, // AudioSystem::DEVICE_OUT_BLUETOOTH_SCO - DEVICE_BLUETOOTH_SCO_HEADSET, // AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET - DEVICE_BLUETOOTH_SCO_CARKIT, // AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT - DEVICE_BLUETOOTH_A2DP, // AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP - DEVICE_BLUETOOTH_A2DP_HEADPHONES, // AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES - DEVICE_BLUETOOTH_A2DP_SPEAKER, // AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER - DEVICE_AUX_DIGITAL // AudioSystem::DEVICE_OUT_AUX_DIGITAL -}; - -uint32_t AudioFlinger::EffectModule::deviceAudioSystemToEffectApi(uint32_t device) -{ - uint32_t deviceOut = 0; - while (device) { - const uint32_t i = 31 - __builtin_clz(device); - device &= ~(1 << i); - if (i >= sizeof(sDeviceConvTable)/sizeof(uint32_t)) { - LOGE("device convertion error for AudioSystem device 0x%08x", device); - return 0; - } - deviceOut |= (uint32_t)sDeviceConvTable[i]; - } - return deviceOut; -} - -// update this table when AudioSystem::audio_mode or audio_mode_e (in EffectApi.h) are modified -const uint32_t AudioFlinger::EffectModule::sModeConvTable[] = { - AUDIO_MODE_NORMAL, // AudioSystem::MODE_NORMAL - AUDIO_MODE_RINGTONE, // AudioSystem::MODE_RINGTONE - AUDIO_MODE_IN_CALL // AudioSystem::MODE_IN_CALL -}; - -int AudioFlinger::EffectModule::modeAudioSystemToEffectApi(uint32_t mode) -{ - int modeOut = -1; - if (mode < sizeof(sModeConvTable) / sizeof(uint32_t)) { - modeOut = (int)sModeConvTable[mode]; - } - return modeOut; -} - -status_t AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - - snprintf(buffer, SIZE, "\tEffect ID %d:\n", mId); - result.append(buffer); - - bool locked = tryLock(mLock); - // failed to lock - AudioFlinger is probably deadlocked - if (!locked) { - result.append("\t\tCould not lock Fx mutex:\n"); - } - - result.append("\t\tSession Status State Engine:\n"); - snprintf(buffer, SIZE, "\t\t%05d %03d %03d 0x%08x\n", - mSessionId, mStatus, mState, (uint32_t)mEffectInterface); - result.append(buffer); - - result.append("\t\tDescriptor:\n"); - snprintf(buffer, SIZE, "\t\t- UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n", - mDescriptor.uuid.timeLow, mDescriptor.uuid.timeMid, mDescriptor.uuid.timeHiAndVersion, - mDescriptor.uuid.clockSeq, mDescriptor.uuid.node[0], mDescriptor.uuid.node[1],mDescriptor.uuid.node[2], - mDescriptor.uuid.node[3],mDescriptor.uuid.node[4],mDescriptor.uuid.node[5]); - result.append(buffer); - snprintf(buffer, SIZE, "\t\t- TYPE: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n", - mDescriptor.type.timeLow, mDescriptor.type.timeMid, mDescriptor.type.timeHiAndVersion, - mDescriptor.type.clockSeq, mDescriptor.type.node[0], mDescriptor.type.node[1],mDescriptor.type.node[2], - mDescriptor.type.node[3],mDescriptor.type.node[4],mDescriptor.type.node[5]); - result.append(buffer); - snprintf(buffer, SIZE, "\t\t- apiVersion: %04X\n\t\t- flags: %08X\n", - mDescriptor.apiVersion, - mDescriptor.flags); - result.append(buffer); - snprintf(buffer, SIZE, "\t\t- name: %s\n", - mDescriptor.name); - result.append(buffer); - snprintf(buffer, SIZE, "\t\t- implementor: %s\n", - mDescriptor.implementor); - result.append(buffer); - - result.append("\t\t- Input configuration:\n"); - result.append("\t\t\tBuffer Frames Smp rate Channels Format\n"); - snprintf(buffer, SIZE, "\t\t\t0x%08x %05d %05d %08x %d\n", - (uint32_t)mConfig.inputCfg.buffer.raw, - mConfig.inputCfg.buffer.frameCount, - mConfig.inputCfg.samplingRate, - mConfig.inputCfg.channels, - mConfig.inputCfg.format); - result.append(buffer); - - result.append("\t\t- Output configuration:\n"); - result.append("\t\t\tBuffer Frames Smp rate Channels Format\n"); - snprintf(buffer, SIZE, "\t\t\t0x%08x %05d %05d %08x %d\n", - (uint32_t)mConfig.outputCfg.buffer.raw, - mConfig.outputCfg.buffer.frameCount, - mConfig.outputCfg.samplingRate, - mConfig.outputCfg.channels, - mConfig.outputCfg.format); - result.append(buffer); - - snprintf(buffer, SIZE, "\t\t%d Clients:\n", mHandles.size()); - result.append(buffer); - result.append("\t\t\tPid Priority Ctrl Locked client server\n"); - for (size_t i = 0; i < mHandles.size(); ++i) { - sp<EffectHandle> handle = mHandles[i].promote(); - if (handle != 0) { - handle->dump(buffer, SIZE); - result.append(buffer); - } - } - - result.append("\n"); - - write(fd, result.string(), result.length()); - - if (locked) { - mLock.unlock(); - } - - return NO_ERROR; -} - -// ---------------------------------------------------------------------------- -// EffectHandle implementation -// ---------------------------------------------------------------------------- - -#undef LOG_TAG -#define LOG_TAG "AudioFlinger::EffectHandle" - -AudioFlinger::EffectHandle::EffectHandle(const sp<EffectModule>& effect, - const sp<AudioFlinger::Client>& client, - const sp<IEffectClient>& effectClient, - int32_t priority) - : BnEffect(), - mEffect(effect), mEffectClient(effectClient), mClient(client), mPriority(priority), mHasControl(false) -{ - LOGV("constructor %p", this); - - int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int); - mCblkMemory = client->heap()->allocate(EFFECT_PARAM_BUFFER_SIZE + bufOffset); - if (mCblkMemory != 0) { - mCblk = static_cast<effect_param_cblk_t *>(mCblkMemory->pointer()); - - if (mCblk) { - new(mCblk) effect_param_cblk_t(); - mBuffer = (uint8_t *)mCblk + bufOffset; - } - } else { - LOGE("not enough memory for Effect size=%u", EFFECT_PARAM_BUFFER_SIZE + sizeof(effect_param_cblk_t)); - return; - } -} - -AudioFlinger::EffectHandle::~EffectHandle() -{ - LOGV("Destructor %p", this); - disconnect(); -} - -status_t AudioFlinger::EffectHandle::enable() -{ - if (!mHasControl) return INVALID_OPERATION; - if (mEffect == 0) return DEAD_OBJECT; - - return mEffect->setEnabled(true); -} - -status_t AudioFlinger::EffectHandle::disable() -{ - if (!mHasControl) return INVALID_OPERATION; - if (mEffect == NULL) return DEAD_OBJECT; - - return mEffect->setEnabled(false); -} - -void AudioFlinger::EffectHandle::disconnect() -{ - if (mEffect == 0) { - return; - } - mEffect->disconnect(this); - // release sp on module => module destructor can be called now - mEffect.clear(); - if (mCblk) { - mCblk->~effect_param_cblk_t(); // destroy our shared-structure. - } - mCblkMemory.clear(); // and free the shared memory - if (mClient != 0) { - Mutex::Autolock _l(mClient->audioFlinger()->mLock); - mClient.clear(); - } -} - -status_t AudioFlinger::EffectHandle::command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData) -{ -// LOGV("command(), cmdCode: %d, mHasControl: %d, mEffect: %p", cmdCode, mHasControl, (mEffect == 0) ? 0 : mEffect.get()); - - // only get parameter command is permitted for applications not controlling the effect - if (!mHasControl && cmdCode != EFFECT_CMD_GET_PARAM) { - return INVALID_OPERATION; - } - if (mEffect == 0) return DEAD_OBJECT; - - // handle commands that are not forwarded transparently to effect engine - if (cmdCode == EFFECT_CMD_SET_PARAM_COMMIT) { - // No need to trylock() here as this function is executed in the binder thread serving a particular client process: - // no risk to block the whole media server process or mixer threads is we are stuck here - Mutex::Autolock _l(mCblk->lock); - if (mCblk->clientIndex > EFFECT_PARAM_BUFFER_SIZE || - mCblk->serverIndex > EFFECT_PARAM_BUFFER_SIZE) { - mCblk->serverIndex = 0; - mCblk->clientIndex = 0; - return BAD_VALUE; - } - status_t status = NO_ERROR; - while (mCblk->serverIndex < mCblk->clientIndex) { - int reply; - int rsize = sizeof(int); - int *p = (int *)(mBuffer + mCblk->serverIndex); - int size = *p++; - if (((uint8_t *)p + size) > mBuffer + mCblk->clientIndex) { - LOGW("command(): invalid parameter block size"); - break; - } - effect_param_t *param = (effect_param_t *)p; - if (param->psize == 0 || param->vsize == 0) { - LOGW("command(): null parameter or value size"); - mCblk->serverIndex += size; - continue; - } - int psize = sizeof(effect_param_t) + ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize; - status_t ret = mEffect->command(EFFECT_CMD_SET_PARAM, psize, p, &rsize, &reply); - if (ret == NO_ERROR) { - if (reply != NO_ERROR) { - status = reply; - } - } else { - status = ret; - } - mCblk->serverIndex += size; - } - mCblk->serverIndex = 0; - mCblk->clientIndex = 0; - return status; - } else if (cmdCode == EFFECT_CMD_ENABLE) { - return enable(); - } else if (cmdCode == EFFECT_CMD_DISABLE) { - return disable(); - } - - return mEffect->command(cmdCode, cmdSize, pCmdData, replySize, pReplyData); -} - -sp<IMemory> AudioFlinger::EffectHandle::getCblk() const { - return mCblkMemory; -} - -void AudioFlinger::EffectHandle::setControl(bool hasControl, bool signal) -{ - LOGV("setControl %p control %d", this, hasControl); - - mHasControl = hasControl; - if (signal && mEffectClient != 0) { - mEffectClient->controlStatusChanged(hasControl); - } -} - -void AudioFlinger::EffectHandle::commandExecuted(int cmdCode, int cmdSize, void *pCmdData, int replySize, void *pReplyData) -{ - if (mEffectClient != 0) { - mEffectClient->commandExecuted(cmdCode, cmdSize, pCmdData, replySize, pReplyData); - } -} - - - -void AudioFlinger::EffectHandle::setEnabled(bool enabled) -{ - if (mEffectClient != 0) { - mEffectClient->enableStatusChanged(enabled); - } -} - -status_t AudioFlinger::EffectHandle::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - return BnEffect::onTransact(code, data, reply, flags); -} - - -void AudioFlinger::EffectHandle::dump(char* buffer, size_t size) -{ - bool locked = tryLock(mCblk->lock); - - snprintf(buffer, size, "\t\t\t%05d %05d %01u %01u %05u %05u\n", - (mClient == NULL) ? getpid() : mClient->pid(), - mPriority, - mHasControl, - !locked, - mCblk->clientIndex, - mCblk->serverIndex - ); - - if (locked) { - mCblk->lock.unlock(); - } -} - -#undef LOG_TAG -#define LOG_TAG "AudioFlinger::EffectChain" - -AudioFlinger::EffectChain::EffectChain(const wp<ThreadBase>& wThread, - int sessionId) - : mThread(wThread), mSessionId(sessionId), mVolumeCtrlIdx(-1), mActiveTrackCnt(0), mOwnInBuffer(false) -{ - -} - -AudioFlinger::EffectChain::~EffectChain() -{ - if (mOwnInBuffer) { - delete mInBuffer; - } - -} - -sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromDesc(effect_descriptor_t *descriptor) -{ - sp<EffectModule> effect; - size_t size = mEffects.size(); - - for (size_t i = 0; i < size; i++) { - if (memcmp(&mEffects[i]->desc().uuid, &descriptor->uuid, sizeof(effect_uuid_t)) == 0) { - effect = mEffects[i]; - break; - } - } - return effect; -} - -sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromId(int id) -{ - sp<EffectModule> effect; - size_t size = mEffects.size(); - - for (size_t i = 0; i < size; i++) { - if (mEffects[i]->id() == id) { - effect = mEffects[i]; - break; - } - } - return effect; -} - -// Must be called with EffectChain::mLock locked -void AudioFlinger::EffectChain::process_l() -{ - size_t size = mEffects.size(); - for (size_t i = 0; i < size; i++) { - mEffects[i]->process(); - } - for (size_t i = 0; i < size; i++) { - mEffects[i]->updateState(); - } - // if no track is active, input buffer must be cleared here as the mixer process - // will not do it - if (mSessionId > 0 && activeTracks() == 0) { - sp<ThreadBase> thread = mThread.promote(); - if (thread != 0) { - size_t numSamples = thread->frameCount() * thread->channelCount(); - memset(mInBuffer, 0, numSamples * sizeof(int16_t)); - } - } -} - -status_t AudioFlinger::EffectChain::addEffect(sp<EffectModule>& effect) -{ - effect_descriptor_t desc = effect->desc(); - uint32_t insertPref = desc.flags & EFFECT_FLAG_INSERT_MASK; - - Mutex::Autolock _l(mLock); - - if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { - // Auxiliary effects are inserted at the beginning of mEffects vector as - // they are processed first and accumulated in chain input buffer - mEffects.insertAt(effect, 0); - sp<ThreadBase> thread = mThread.promote(); - if (thread == 0) { - return NO_INIT; - } - // the input buffer for auxiliary effect contains mono samples in - // 32 bit format. This is to avoid saturation in AudoMixer - // accumulation stage. Saturation is done in EffectModule::process() before - // calling the process in effect engine - size_t numSamples = thread->frameCount(); - int32_t *buffer = new int32_t[numSamples]; - memset(buffer, 0, numSamples * sizeof(int32_t)); - effect->setInBuffer((int16_t *)buffer); - // auxiliary effects output samples to chain input buffer for further processing - // by insert effects - effect->setOutBuffer(mInBuffer); - } else { - // Insert effects are inserted at the end of mEffects vector as they are processed - // after track and auxiliary effects. - // Insert effect order as a function of indicated preference: - // if EFFECT_FLAG_INSERT_EXCLUSIVE, insert in first position or reject if - // another effect is present - // else if EFFECT_FLAG_INSERT_FIRST, insert in first position or after the - // last effect claiming first position - // else if EFFECT_FLAG_INSERT_LAST, insert in last position or before the - // first effect claiming last position - // else if EFFECT_FLAG_INSERT_ANY insert after first or before last - // Reject insertion if an effect with EFFECT_FLAG_INSERT_EXCLUSIVE is - // already present - - int size = (int)mEffects.size(); - int idx_insert = size; - int idx_insert_first = -1; - int idx_insert_last = -1; - - for (int i = 0; i < size; i++) { - effect_descriptor_t d = mEffects[i]->desc(); - uint32_t iMode = d.flags & EFFECT_FLAG_TYPE_MASK; - uint32_t iPref = d.flags & EFFECT_FLAG_INSERT_MASK; - if (iMode == EFFECT_FLAG_TYPE_INSERT) { - // check invalid effect chaining combinations - if (insertPref == EFFECT_FLAG_INSERT_EXCLUSIVE || - iPref == EFFECT_FLAG_INSERT_EXCLUSIVE) { - LOGW("addEffect() could not insert effect %s: exclusive conflict with %s", desc.name, d.name); - return INVALID_OPERATION; - } - // remember position of first insert effect and by default - // select this as insert position for new effect - if (idx_insert == size) { - idx_insert = i; - } - // remember position of last insert effect claiming - // first position - if (iPref == EFFECT_FLAG_INSERT_FIRST) { - idx_insert_first = i; - } - // remember position of first insert effect claiming - // last position - if (iPref == EFFECT_FLAG_INSERT_LAST && - idx_insert_last == -1) { - idx_insert_last = i; - } - } - } - - // modify idx_insert from first position if needed - if (insertPref == EFFECT_FLAG_INSERT_LAST) { - if (idx_insert_last != -1) { - idx_insert = idx_insert_last; - } else { - idx_insert = size; - } - } else { - if (idx_insert_first != -1) { - idx_insert = idx_insert_first + 1; - } - } - - // always read samples from chain input buffer - effect->setInBuffer(mInBuffer); - - // if last effect in the chain, output samples to chain - // output buffer, otherwise to chain input buffer - if (idx_insert == size) { - if (idx_insert != 0) { - mEffects[idx_insert-1]->setOutBuffer(mInBuffer); - mEffects[idx_insert-1]->configure(); - } - effect->setOutBuffer(mOutBuffer); - } else { - effect->setOutBuffer(mInBuffer); - } - mEffects.insertAt(effect, idx_insert); - // Always give volume control to last effect in chain with volume control capability - if (((desc.flags & EFFECT_FLAG_VOLUME_MASK) & EFFECT_FLAG_VOLUME_CTRL) && - mVolumeCtrlIdx < idx_insert) { - mVolumeCtrlIdx = idx_insert; - } - - LOGV("addEffect() effect %p, added in chain %p at rank %d", effect.get(), this, idx_insert); - } - effect->configure(); - return NO_ERROR; -} - -size_t AudioFlinger::EffectChain::removeEffect(const sp<EffectModule>& effect) -{ - Mutex::Autolock _l(mLock); - - int size = (int)mEffects.size(); - int i; - uint32_t type = effect->desc().flags & EFFECT_FLAG_TYPE_MASK; - - for (i = 0; i < size; i++) { - if (effect == mEffects[i]) { - if (type == EFFECT_FLAG_TYPE_AUXILIARY) { - delete[] effect->inBuffer(); - } else { - if (i == size - 1 && i != 0) { - mEffects[i - 1]->setOutBuffer(mOutBuffer); - mEffects[i - 1]->configure(); - } - } - mEffects.removeAt(i); - LOGV("removeEffect() effect %p, removed from chain %p at rank %d", effect.get(), this, i); - break; - } - } - // Return volume control to last effect in chain with volume control capability - if (mVolumeCtrlIdx == i) { - size = (int)mEffects.size(); - for (i = size; i > 0; i--) { - if ((mEffects[i - 1]->desc().flags & EFFECT_FLAG_VOLUME_MASK) & EFFECT_FLAG_VOLUME_CTRL) { - break; - } - } - // mVolumeCtrlIdx reset to -1 if no effect found with volume control flag set - mVolumeCtrlIdx = i - 1; - } - - return mEffects.size(); -} - -void AudioFlinger::EffectChain::setDevice(uint32_t device) -{ - size_t size = mEffects.size(); - for (size_t i = 0; i < size; i++) { - mEffects[i]->setDevice(device); - } -} - -void AudioFlinger::EffectChain::setMode(uint32_t mode) -{ - size_t size = mEffects.size(); - for (size_t i = 0; i < size; i++) { - mEffects[i]->setMode(mode); - } -} - -bool AudioFlinger::EffectChain::setVolume(uint32_t *left, uint32_t *right) -{ - uint32_t newLeft = *left; - uint32_t newRight = *right; - bool hasControl = false; - - // first get volume update from volume controller - if (mVolumeCtrlIdx >= 0) { - mEffects[mVolumeCtrlIdx]->setVolume(&newLeft, &newRight, true); - hasControl = true; - } - // then indicate volume to all other effects in chain. - // Pass altered volume to effects before volume controller - // and requested volume to effects after controller - uint32_t lVol = newLeft; - uint32_t rVol = newRight; - size_t size = mEffects.size(); - for (size_t i = 0; i < size; i++) { - if ((int)i == mVolumeCtrlIdx) continue; - // this also works for mVolumeCtrlIdx == -1 when there is no volume controller - if ((int)i > mVolumeCtrlIdx) { - lVol = *left; - rVol = *right; - } - mEffects[i]->setVolume(&lVol, &rVol, false); - } - *left = newLeft; - *right = newRight; - - return hasControl; -} - -sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getVolumeController() -{ - sp<EffectModule> effect; - if (mVolumeCtrlIdx >= 0) { - effect = mEffects[mVolumeCtrlIdx]; - } - return effect; -} - - -status_t AudioFlinger::EffectChain::dump(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - - snprintf(buffer, SIZE, "Effects for session %d:\n", mSessionId); - result.append(buffer); - - bool locked = tryLock(mLock); - // failed to lock - AudioFlinger is probably deadlocked - if (!locked) { - result.append("\tCould not lock mutex:\n"); - } - - result.append("\tNum fx In buffer Out buffer Vol ctrl Active tracks:\n"); - snprintf(buffer, SIZE, "\t%02d 0x%08x 0x%08x %02d %d\n", - mEffects.size(), - (uint32_t)mInBuffer, - (uint32_t)mOutBuffer, - (mVolumeCtrlIdx == -1) ? 0 : mEffects[mVolumeCtrlIdx]->id(), - mActiveTrackCnt); - result.append(buffer); - write(fd, result.string(), result.size()); - - for (size_t i = 0; i < mEffects.size(); ++i) { - sp<EffectModule> effect = mEffects[i]; - if (effect != 0) { - effect->dump(fd, args); - } - } - - if (locked) { - mLock.unlock(); - } - - return NO_ERROR; -} - -#undef LOG_TAG -#define LOG_TAG "AudioFlinger" - -// ---------------------------------------------------------------------------- - -status_t AudioFlinger::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - return BnAudioFlinger::onTransact(code, data, reply, flags); -} - -// ---------------------------------------------------------------------------- - -void AudioFlinger::instantiate() { - defaultServiceManager()->addService( - String16("media.audio_flinger"), new AudioFlinger()); -} - -}; // namespace android diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h deleted file mode 100644 index 507c9ac..0000000 --- a/libs/audioflinger/AudioFlinger.h +++ /dev/null @@ -1,1148 +0,0 @@ -/* //device/include/server/AudioFlinger/AudioFlinger.h -** -** Copyright 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. -*/ - -#ifndef ANDROID_AUDIO_FLINGER_H -#define ANDROID_AUDIO_FLINGER_H - -#include <stdint.h> -#include <sys/types.h> -#include <limits.h> - -#include <media/IAudioFlinger.h> -#include <media/IAudioFlingerClient.h> -#include <media/IAudioTrack.h> -#include <media/IAudioRecord.h> -#include <media/AudioTrack.h> - -#include <utils/Atomic.h> -#include <utils/Errors.h> -#include <utils/threads.h> -#include <binder/MemoryDealer.h> -#include <utils/SortedVector.h> -#include <utils/Vector.h> - -#include <hardware_legacy/AudioHardwareInterface.h> - -#include "AudioBufferProvider.h" - -namespace android { - -class audio_track_cblk_t; -class effect_param_cblk_t; -class AudioMixer; -class AudioBuffer; -class AudioResampler; - - -// ---------------------------------------------------------------------------- - -#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) -#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) - - -// ---------------------------------------------------------------------------- - -static const nsecs_t kStandbyTimeInNsecs = seconds(3); - -class AudioFlinger : public BnAudioFlinger -{ -public: - static void instantiate(); - - virtual status_t dump(int fd, const Vector<String16>& args); - - // IAudioFlinger interface - virtual sp<IAudioTrack> createTrack( - pid_t pid, - int streamType, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - uint32_t flags, - const sp<IMemory>& sharedBuffer, - int output, - int *sessionId, - status_t *status); - - virtual uint32_t sampleRate(int output) const; - virtual int channelCount(int output) const; - virtual int format(int output) const; - virtual size_t frameCount(int output) const; - virtual uint32_t latency(int output) const; - - virtual status_t setMasterVolume(float value); - virtual status_t setMasterMute(bool muted); - - virtual float masterVolume() const; - virtual bool masterMute() const; - - virtual status_t setStreamVolume(int stream, float value, int output); - virtual status_t setStreamMute(int stream, bool muted); - - virtual float streamVolume(int stream, int output) const; - virtual bool streamMute(int stream) const; - - virtual status_t setMode(int mode); - - virtual status_t setMicMute(bool state); - virtual bool getMicMute() const; - - virtual bool isStreamActive(int stream) const; - - virtual status_t setParameters(int ioHandle, const String8& keyValuePairs); - virtual String8 getParameters(int ioHandle, const String8& keys); - - virtual void registerClient(const sp<IAudioFlingerClient>& client); - - virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount); - virtual unsigned int getInputFramesLost(int ioHandle); - - virtual int openOutput(uint32_t *pDevices, - uint32_t *pSamplingRate, - uint32_t *pFormat, - uint32_t *pChannels, - uint32_t *pLatencyMs, - uint32_t flags); - - virtual int openDuplicateOutput(int output1, int output2); - - virtual status_t closeOutput(int output); - - virtual status_t suspendOutput(int output); - - virtual status_t restoreOutput(int output); - - virtual int openInput(uint32_t *pDevices, - uint32_t *pSamplingRate, - uint32_t *pFormat, - uint32_t *pChannels, - uint32_t acoustics); - - virtual status_t closeInput(int input); - - virtual status_t setStreamOutput(uint32_t stream, int output); - - virtual status_t setVoiceVolume(float volume); - - virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output); - - virtual int newAudioSessionId(); - - virtual status_t loadEffectLibrary(const char *libPath, int *handle); - - virtual status_t unloadEffectLibrary(int handle); - - virtual status_t queryNumberEffects(uint32_t *numEffects); - - virtual status_t queryEffect(uint32_t index, effect_descriptor_t *descriptor); - - virtual status_t getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *descriptor); - - virtual sp<IEffect> createEffect(pid_t pid, - effect_descriptor_t *pDesc, - const sp<IEffectClient>& effectClient, - int32_t priority, - int output, - int sessionId, - status_t *status, - int *id, - int *enabled); - - status_t registerEffectResource_l(effect_descriptor_t *desc); - void unregisterEffectResource_l(effect_descriptor_t *desc); - - enum hardware_call_state { - AUDIO_HW_IDLE = 0, - AUDIO_HW_INIT, - AUDIO_HW_OUTPUT_OPEN, - AUDIO_HW_OUTPUT_CLOSE, - AUDIO_HW_INPUT_OPEN, - AUDIO_HW_INPUT_CLOSE, - AUDIO_HW_STANDBY, - AUDIO_HW_SET_MASTER_VOLUME, - AUDIO_HW_GET_ROUTING, - AUDIO_HW_SET_ROUTING, - AUDIO_HW_GET_MODE, - AUDIO_HW_SET_MODE, - AUDIO_HW_GET_MIC_MUTE, - AUDIO_HW_SET_MIC_MUTE, - AUDIO_SET_VOICE_VOLUME, - AUDIO_SET_PARAMETER, - }; - - // record interface - virtual sp<IAudioRecord> openRecord( - pid_t pid, - int input, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - uint32_t flags, - int *sessionId, - status_t *status); - - virtual status_t onTransact( - uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags); - - uint32_t getMode() { return mMode; } - -private: - AudioFlinger(); - virtual ~AudioFlinger(); - - - // Internal dump utilites. - status_t dumpPermissionDenial(int fd, const Vector<String16>& args); - status_t dumpClients(int fd, const Vector<String16>& args); - status_t dumpInternals(int fd, const Vector<String16>& args); - - // --- Client --- - class Client : public RefBase { - public: - Client(const sp<AudioFlinger>& audioFlinger, pid_t pid); - virtual ~Client(); - const sp<MemoryDealer>& heap() const; - pid_t pid() const { return mPid; } - sp<AudioFlinger> audioFlinger() { return mAudioFlinger; } - - private: - Client(const Client&); - Client& operator = (const Client&); - sp<AudioFlinger> mAudioFlinger; - sp<MemoryDealer> mMemoryDealer; - pid_t mPid; - }; - - // --- Notification Client --- - class NotificationClient : public IBinder::DeathRecipient { - public: - NotificationClient(const sp<AudioFlinger>& audioFlinger, - const sp<IAudioFlingerClient>& client, - pid_t pid); - virtual ~NotificationClient(); - - sp<IAudioFlingerClient> client() { return mClient; } - - // IBinder::DeathRecipient - virtual void binderDied(const wp<IBinder>& who); - - private: - NotificationClient(const NotificationClient&); - NotificationClient& operator = (const NotificationClient&); - - sp<AudioFlinger> mAudioFlinger; - pid_t mPid; - sp<IAudioFlingerClient> mClient; - }; - - class TrackHandle; - class RecordHandle; - class RecordThread; - class PlaybackThread; - class MixerThread; - class DirectOutputThread; - class DuplicatingThread; - class Track; - class RecordTrack; - class EffectModule; - class EffectHandle; - class EffectChain; - - class ThreadBase : public Thread { - public: - ThreadBase (const sp<AudioFlinger>& audioFlinger, int id); - virtual ~ThreadBase(); - - status_t dumpBase(int fd, const Vector<String16>& args); - - // base for record and playback - class TrackBase : public AudioBufferProvider, public RefBase { - - public: - enum track_state { - IDLE, - TERMINATED, - STOPPED, - RESUMING, - ACTIVE, - PAUSING, - PAUSED - }; - - enum track_flags { - STEPSERVER_FAILED = 0x01, // StepServer could not acquire cblk->lock mutex - SYSTEM_FLAGS_MASK = 0x0000ffffUL, - // The upper 16 bits are used for track-specific flags. - }; - - TrackBase(const wp<ThreadBase>& thread, - const sp<Client>& client, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - uint32_t flags, - const sp<IMemory>& sharedBuffer, - int sessionId); - ~TrackBase(); - - virtual status_t start() = 0; - virtual void stop() = 0; - sp<IMemory> getCblk() const; - audio_track_cblk_t* cblk() const { return mCblk; } - int sessionId() { return mSessionId; } - - protected: - friend class ThreadBase; - friend class RecordHandle; - friend class PlaybackThread; - friend class RecordThread; - friend class MixerThread; - friend class DirectOutputThread; - - TrackBase(const TrackBase&); - TrackBase& operator = (const TrackBase&); - - virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0; - virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer); - - int format() const { - return mFormat; - } - - int channelCount() const ; - - int sampleRate() const; - - void* getBuffer(uint32_t offset, uint32_t frames) const; - - bool isStopped() const { - return mState == STOPPED; - } - - bool isTerminated() const { - return mState == TERMINATED; - } - - bool step(); - void reset(); - - wp<ThreadBase> mThread; - sp<Client> mClient; - sp<IMemory> mCblkMemory; - audio_track_cblk_t* mCblk; - void* mBuffer; - void* mBufferEnd; - uint32_t mFrameCount; - // we don't really need a lock for these - int mState; - int mClientTid; - uint8_t mFormat; - uint32_t mFlags; - int mSessionId; - }; - - class ConfigEvent { - public: - ConfigEvent() : mEvent(0), mParam(0) {} - - int mEvent; - int mParam; - }; - - uint32_t sampleRate() const; - int channelCount() const; - int format() const; - size_t frameCount() const; - void wakeUp() { mWaitWorkCV.broadcast(); } - void exit(); - virtual bool checkForNewParameters_l() = 0; - virtual status_t setParameters(const String8& keyValuePairs); - virtual String8 getParameters(const String8& keys) = 0; - virtual void audioConfigChanged_l(int event, int param = 0) = 0; - void sendConfigEvent(int event, int param = 0); - void sendConfigEvent_l(int event, int param = 0); - void processConfigEvents(); - int id() const { return mId;} - bool standby() { return mStandby; } - - mutable Mutex mLock; - - protected: - - friend class Track; - friend class TrackBase; - friend class PlaybackThread; - friend class MixerThread; - friend class DirectOutputThread; - friend class DuplicatingThread; - friend class RecordThread; - friend class RecordTrack; - - Condition mWaitWorkCV; - sp<AudioFlinger> mAudioFlinger; - uint32_t mSampleRate; - size_t mFrameCount; - uint32_t mChannels; - uint16_t mChannelCount; - uint16_t mFrameSize; - int mFormat; - Condition mParamCond; - Vector<String8> mNewParameters; - status_t mParamStatus; - Vector<ConfigEvent *> mConfigEvents; - bool mStandby; - int mId; - bool mExiting; - }; - - // --- PlaybackThread --- - class PlaybackThread : public ThreadBase { - public: - - enum type { - MIXER, - DIRECT, - DUPLICATING - }; - - enum mixer_state { - MIXER_IDLE, - MIXER_TRACKS_ENABLED, - MIXER_TRACKS_READY - }; - - // playback track - class Track : public TrackBase { - public: - Track( const wp<ThreadBase>& thread, - const sp<Client>& client, - int streamType, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - const sp<IMemory>& sharedBuffer, - int sessionId); - ~Track(); - - void dump(char* buffer, size_t size); - virtual status_t start(); - virtual void stop(); - void pause(); - - void flush(); - void destroy(); - void mute(bool); - void setVolume(float left, float right); - int name() const { - return mName; - } - - int type() const { - return mStreamType; - } - status_t attachAuxEffect(int EffectId); - void setAuxBuffer(int EffectId, int32_t *buffer); - int32_t *auxBuffer() { return mAuxBuffer; } - void setMainBuffer(int16_t *buffer) { mMainBuffer = buffer; } - int16_t *mainBuffer() { return mMainBuffer; } - int auxEffectId() { return mAuxEffectId; } - - - protected: - friend class ThreadBase; - friend class AudioFlinger; - friend class TrackHandle; - friend class PlaybackThread; - friend class MixerThread; - friend class DirectOutputThread; - - Track(const Track&); - Track& operator = (const Track&); - - virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer); - bool isMuted() { return mMute; } - bool isPausing() const { - return mState == PAUSING; - } - bool isPaused() const { - return mState == PAUSED; - } - bool isReady() const; - void setPaused() { mState = PAUSED; } - void reset(); - - bool isOutputTrack() const { - return (mStreamType == AudioSystem::NUM_STREAM_TYPES); - } - - // we don't really need a lock for these - float mVolume[2]; - volatile bool mMute; - // FILLED state is used for suppressing volume ramp at begin of playing - enum {FS_FILLING, FS_FILLED, FS_ACTIVE}; - mutable uint8_t mFillingUpStatus; - int8_t mRetryCount; - sp<IMemory> mSharedBuffer; - bool mResetDone; - int mStreamType; - int mName; - int16_t *mMainBuffer; - int32_t *mAuxBuffer; - int mAuxEffectId; - }; // end of Track - - - // playback track - class OutputTrack : public Track { - public: - - class Buffer: public AudioBufferProvider::Buffer { - public: - int16_t *mBuffer; - }; - - OutputTrack( const wp<ThreadBase>& thread, - DuplicatingThread *sourceThread, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount); - ~OutputTrack(); - - virtual status_t start(); - virtual void stop(); - bool write(int16_t* data, uint32_t frames); - bool bufferQueueEmpty() { return (mBufferQueue.size() == 0) ? true : false; } - bool isActive() { return mActive; } - wp<ThreadBase>& thread() { return mThread; } - - private: - - status_t obtainBuffer(AudioBufferProvider::Buffer* buffer, uint32_t waitTimeMs); - void clearBufferQueue(); - - // Maximum number of pending buffers allocated by OutputTrack::write() - static const uint8_t kMaxOverFlowBuffers = 10; - - Vector < Buffer* > mBufferQueue; - AudioBufferProvider::Buffer mOutBuffer; - bool mActive; - DuplicatingThread* mSourceThread; - }; // end of OutputTrack - - PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device); - virtual ~PlaybackThread(); - - virtual status_t dump(int fd, const Vector<String16>& args); - - // Thread virtuals - virtual status_t readyToRun(); - virtual void onFirstRef(); - - virtual uint32_t latency() const; - - virtual status_t setMasterVolume(float value); - virtual status_t setMasterMute(bool muted); - - virtual float masterVolume() const; - virtual bool masterMute() const; - - virtual status_t setStreamVolume(int stream, float value); - virtual status_t setStreamMute(int stream, bool muted); - - virtual float streamVolume(int stream) const; - virtual bool streamMute(int stream) const; - - bool isStreamActive(int stream) const; - - sp<Track> createTrack_l( - const sp<AudioFlinger::Client>& client, - int streamType, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - const sp<IMemory>& sharedBuffer, - int sessionId, - status_t *status); - - AudioStreamOut* getOutput() { return mOutput; } - - virtual int type() const { return mType; } - void suspend() { mSuspended++; } - void restore() { if (mSuspended) mSuspended--; } - bool isSuspended() { return (mSuspended != 0); } - virtual String8 getParameters(const String8& keys); - virtual void audioConfigChanged_l(int event, int param = 0); - virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames); - int16_t *mixBuffer() { return mMixBuffer; }; - - sp<EffectHandle> createEffect_l( - const sp<AudioFlinger::Client>& client, - const sp<IEffectClient>& effectClient, - int32_t priority, - int sessionId, - effect_descriptor_t *desc, - int *enabled, - status_t *status); - void disconnectEffect(const sp< EffectModule>& effect, - const wp<EffectHandle>& handle); - - bool hasAudioSession(int sessionId); - sp<EffectChain> getEffectChain(int sessionId); - sp<EffectChain> getEffectChain_l(int sessionId); - status_t addEffectChain_l(const sp<EffectChain>& chain); - size_t removeEffectChain_l(const sp<EffectChain>& chain); - void lockEffectChains_l(); - void unlockEffectChains(); - - sp<AudioFlinger::EffectModule> getEffect_l(int sessionId, int effectId); - void detachAuxEffect_l(int effectId); - status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId); - status_t attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId); - void setMode(uint32_t mode); - - struct stream_type_t { - stream_type_t() - : volume(1.0f), - mute(false) - { - } - float volume; - bool mute; - }; - - protected: - int mType; - int16_t* mMixBuffer; - int mSuspended; - int mBytesWritten; - bool mMasterMute; - SortedVector< wp<Track> > mActiveTracks; - - virtual int getTrackName_l() = 0; - virtual void deleteTrackName_l(int name) = 0; - virtual uint32_t activeSleepTimeUs() = 0; - virtual uint32_t idleSleepTimeUs() = 0; - - private: - - friend class AudioFlinger; - friend class OutputTrack; - friend class Track; - friend class TrackBase; - friend class MixerThread; - friend class DirectOutputThread; - friend class DuplicatingThread; - - PlaybackThread(const Client&); - PlaybackThread& operator = (const PlaybackThread&); - - status_t addTrack_l(const sp<Track>& track); - void destroyTrack_l(const sp<Track>& track); - - void readOutputParameters(); - - uint32_t device() { return mDevice; } - - virtual status_t dumpInternals(int fd, const Vector<String16>& args); - status_t dumpTracks(int fd, const Vector<String16>& args); - status_t dumpEffectChains(int fd, const Vector<String16>& args); - - SortedVector< sp<Track> > mTracks; - // mStreamTypes[] uses 1 additionnal stream type internally for the OutputTrack used by DuplicatingThread - stream_type_t mStreamTypes[AudioSystem::NUM_STREAM_TYPES + 1]; - AudioStreamOut* mOutput; - float mMasterVolume; - nsecs_t mLastWriteTime; - int mNumWrites; - int mNumDelayedWrites; - bool mInWrite; - Vector< sp<EffectChain> > mEffectChains; - uint32_t mDevice; - }; - - class MixerThread : public PlaybackThread { - public: - MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device); - virtual ~MixerThread(); - - // Thread virtuals - virtual bool threadLoop(); - - void invalidateTracks(int streamType); - virtual bool checkForNewParameters_l(); - virtual status_t dumpInternals(int fd, const Vector<String16>& args); - - protected: - uint32_t prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove); - virtual int getTrackName_l(); - virtual void deleteTrackName_l(int name); - virtual uint32_t activeSleepTimeUs(); - virtual uint32_t idleSleepTimeUs(); - - AudioMixer* mAudioMixer; - }; - - class DirectOutputThread : public PlaybackThread { - public: - - DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device); - ~DirectOutputThread(); - - // Thread virtuals - virtual bool threadLoop(); - - virtual bool checkForNewParameters_l(); - - protected: - virtual int getTrackName_l(); - virtual void deleteTrackName_l(int name); - virtual uint32_t activeSleepTimeUs(); - virtual uint32_t idleSleepTimeUs(); - - private: - void applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp); - - float mLeftVolFloat; - float mRightVolFloat; - uint16_t mLeftVolShort; - uint16_t mRightVolShort; - }; - - class DuplicatingThread : public MixerThread { - public: - DuplicatingThread (const sp<AudioFlinger>& audioFlinger, MixerThread* mainThread, int id); - ~DuplicatingThread(); - - // Thread virtuals - virtual bool threadLoop(); - void addOutputTrack(MixerThread* thread); - void removeOutputTrack(MixerThread* thread); - uint32_t waitTimeMs() { return mWaitTimeMs; } - protected: - virtual uint32_t activeSleepTimeUs(); - - private: - bool outputsReady(SortedVector< sp<OutputTrack> > &outputTracks); - void updateWaitTime(); - - SortedVector < sp<OutputTrack> > mOutputTracks; - uint32_t mWaitTimeMs; - }; - - PlaybackThread *checkPlaybackThread_l(int output) const; - MixerThread *checkMixerThread_l(int output) const; - RecordThread *checkRecordThread_l(int input) const; - float streamVolumeInternal(int stream) const { return mStreamTypes[stream].volume; } - void audioConfigChanged_l(int event, int ioHandle, void *param2); - - int nextUniqueId(); - - friend class AudioBuffer; - - class TrackHandle : public android::BnAudioTrack { - public: - TrackHandle(const sp<PlaybackThread::Track>& track); - virtual ~TrackHandle(); - virtual status_t start(); - virtual void stop(); - virtual void flush(); - virtual void mute(bool); - virtual void pause(); - virtual void setVolume(float left, float right); - virtual sp<IMemory> getCblk() const; - virtual status_t attachAuxEffect(int effectId); - virtual status_t onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); - private: - sp<PlaybackThread::Track> mTrack; - }; - - friend class Client; - friend class PlaybackThread::Track; - - - void removeClient_l(pid_t pid); - void removeNotificationClient(pid_t pid); - - - // record thread - class RecordThread : public ThreadBase, public AudioBufferProvider - { - public: - - // record track - class RecordTrack : public TrackBase { - public: - RecordTrack(const wp<ThreadBase>& thread, - const sp<Client>& client, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - uint32_t flags, - int sessionId); - ~RecordTrack(); - - virtual status_t start(); - virtual void stop(); - - bool overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; } - bool setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; } - - void dump(char* buffer, size_t size); - private: - friend class AudioFlinger; - friend class RecordThread; - - RecordTrack(const RecordTrack&); - RecordTrack& operator = (const RecordTrack&); - - virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer); - - bool mOverflow; - }; - - - RecordThread(const sp<AudioFlinger>& audioFlinger, - AudioStreamIn *input, - uint32_t sampleRate, - uint32_t channels, - int id); - ~RecordThread(); - - virtual bool threadLoop(); - virtual status_t readyToRun() { return NO_ERROR; } - virtual void onFirstRef(); - - status_t start(RecordTrack* recordTrack); - void stop(RecordTrack* recordTrack); - status_t dump(int fd, const Vector<String16>& args); - AudioStreamIn* getInput() { return mInput; } - - virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer); - virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer); - virtual bool checkForNewParameters_l(); - virtual String8 getParameters(const String8& keys); - virtual void audioConfigChanged_l(int event, int param = 0); - void readInputParameters(); - virtual unsigned int getInputFramesLost(); - - private: - RecordThread(); - AudioStreamIn *mInput; - sp<RecordTrack> mActiveTrack; - Condition mStartStopCond; - AudioResampler *mResampler; - int32_t *mRsmpOutBuffer; - int16_t *mRsmpInBuffer; - size_t mRsmpInIndex; - size_t mInputBytes; - int mReqChannelCount; - uint32_t mReqSampleRate; - ssize_t mBytesRead; - }; - - class RecordHandle : public android::BnAudioRecord { - public: - RecordHandle(const sp<RecordThread::RecordTrack>& recordTrack); - virtual ~RecordHandle(); - virtual status_t start(); - virtual void stop(); - virtual sp<IMemory> getCblk() const; - virtual status_t onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); - private: - sp<RecordThread::RecordTrack> mRecordTrack; - }; - - //--- Audio Effect Management - - // EffectModule and EffectChain classes both have their own mutex to protect - // state changes or resource modifications. Always respect the following order - // if multiple mutexes must be acquired to avoid cross deadlock: - // AudioFlinger -> ThreadBase -> EffectChain -> EffectModule - - // The EffectModule class is a wrapper object controlling the effect engine implementation - // in the effect library. It prevents concurrent calls to process() and command() functions - // from different client threads. It keeps a list of EffectHandle objects corresponding - // to all client applications using this effect and notifies applications of effect state, - // control or parameter changes. It manages the activation state machine to send appropriate - // reset, enable, disable commands to effect engine and provide volume - // ramping when effects are activated/deactivated. - // When controlling an auxiliary effect, the EffectModule also provides an input buffer used by - // the attached track(s) to accumulate their auxiliary channel. - class EffectModule: public RefBase { - public: - EffectModule(const wp<ThreadBase>& wThread, - const wp<AudioFlinger::EffectChain>& chain, - effect_descriptor_t *desc, - int id, - int sessionId); - ~EffectModule(); - - enum effect_state { - IDLE, - RESTART, - STARTING, - ACTIVE, - STOPPING, - STOPPED - }; - - int id() { return mId; } - void process(); - void updateState(); - status_t command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData); - - void reset_l(); - status_t configure(); - status_t init(); - uint32_t state() { - return mState; - } - uint32_t status() { - return mStatus; - } - status_t setEnabled(bool enabled); - bool isEnabled(); - - void setInBuffer(int16_t *buffer) { mConfig.inputCfg.buffer.s16 = buffer; } - int16_t *inBuffer() { return mConfig.inputCfg.buffer.s16; } - void setOutBuffer(int16_t *buffer) { mConfig.outputCfg.buffer.s16 = buffer; } - int16_t *outBuffer() { return mConfig.outputCfg.buffer.s16; } - - status_t addHandle(sp<EffectHandle>& handle); - void disconnect(const wp<EffectHandle>& handle); - size_t removeHandle (const wp<EffectHandle>& handle); - - effect_descriptor_t& desc() { return mDescriptor; } - wp<EffectChain>& chain() { return mChain; } - - status_t setDevice(uint32_t device); - status_t setVolume(uint32_t *left, uint32_t *right, bool controller); - status_t setMode(uint32_t mode); - - status_t dump(int fd, const Vector<String16>& args); - - protected: - - // Maximum time allocated to effect engines to complete the turn off sequence - static const uint32_t MAX_DISABLE_TIME_MS = 10000; - - EffectModule(const EffectModule&); - EffectModule& operator = (const EffectModule&); - - status_t start_l(); - status_t stop_l(); - - // update this table when AudioSystem::audio_devices or audio_device_e (in EffectApi.h) are modified - static const uint32_t sDeviceConvTable[]; - static uint32_t deviceAudioSystemToEffectApi(uint32_t device); - - // update this table when AudioSystem::audio_mode or audio_mode_e (in EffectApi.h) are modified - static const uint32_t sModeConvTable[]; - static int modeAudioSystemToEffectApi(uint32_t mode); - - Mutex mLock; // mutex for process, commands and handles list protection - wp<ThreadBase> mThread; // parent thread - wp<EffectChain> mChain; // parent effect chain - int mId; // this instance unique ID - int mSessionId; // audio session ID - effect_descriptor_t mDescriptor;// effect descriptor received from effect engine - effect_config_t mConfig; // input and output audio configuration - effect_interface_t mEffectInterface; // Effect module C API - status_t mStatus; // initialization status - uint32_t mState; // current activation state (effect_state) - Vector< wp<EffectHandle> > mHandles; // list of client handles - uint32_t mMaxDisableWaitCnt; // maximum grace period before forcing an effect off after - // sending disable command. - uint32_t mDisableWaitCnt; // current process() calls count during disable period. - }; - - // The EffectHandle class implements the IEffect interface. It provides resources - // to receive parameter updates, keeps track of effect control - // ownership and state and has a pointer to the EffectModule object it is controlling. - // There is one EffectHandle object for each application controlling (or using) - // an effect module. - // The EffectHandle is obtained by calling AudioFlinger::createEffect(). - class EffectHandle: public android::BnEffect { - public: - - EffectHandle(const sp<EffectModule>& effect, - const sp<AudioFlinger::Client>& client, - const sp<IEffectClient>& effectClient, - int32_t priority); - virtual ~EffectHandle(); - - // IEffect - virtual status_t enable(); - virtual status_t disable(); - virtual status_t command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData); - virtual void disconnect(); - virtual sp<IMemory> getCblk() const; - virtual status_t onTransact(uint32_t code, const Parcel& data, - Parcel* reply, uint32_t flags); - - - // Give or take control of effect module - void setControl(bool hasControl, bool signal); - void commandExecuted(int cmdCode, int cmdSize, void *pCmdData, int replySize, void *pReplyData); - void setEnabled(bool enabled); - - // Getters - int id() { return mEffect->id(); } - int priority() { return mPriority; } - bool hasControl() { return mHasControl; } - sp<EffectModule> effect() { return mEffect; } - - void dump(char* buffer, size_t size); - - protected: - - EffectHandle(const EffectHandle&); - EffectHandle& operator =(const EffectHandle&); - - sp<EffectModule> mEffect; // pointer to controlled EffectModule - sp<IEffectClient> mEffectClient; // callback interface for client notifications - sp<Client> mClient; // client for shared memory allocation - sp<IMemory> mCblkMemory; // shared memory for control block - effect_param_cblk_t* mCblk; // control block for deferred parameter setting via shared memory - uint8_t* mBuffer; // pointer to parameter area in shared memory - int mPriority; // client application priority to control the effect - bool mHasControl; // true if this handle is controlling the effect - }; - - // the EffectChain class represents a group of effects associated to one audio session. - // There can be any number of EffectChain objects per output mixer thread (PlaybackThread). - // The EffecChain with session ID 0 contains global effects applied to the output mix. - // Effects in this chain can be insert or auxiliary. Effects in other chains (attached to tracks) - // are insert only. The EffectChain maintains an ordered list of effect module, the order corresponding - // in the effect process order. When attached to a track (session ID != 0), it also provide it's own - // input buffer used by the track as accumulation buffer. - class EffectChain: public RefBase { - public: - EffectChain(const wp<ThreadBase>& wThread, int sessionId); - ~EffectChain(); - - void process_l(); - - void lock() { - mLock.lock(); - } - void unlock() { - mLock.unlock(); - } - - status_t addEffect(sp<EffectModule>& handle); - size_t removeEffect(const sp<EffectModule>& handle); - - int sessionId() { - return mSessionId; - } - sp<EffectModule> getEffectFromDesc(effect_descriptor_t *descriptor); - sp<EffectModule> getEffectFromId(int id); - sp<EffectModule> getVolumeController(); - bool setVolume(uint32_t *left, uint32_t *right); - void setDevice(uint32_t device); - void setMode(uint32_t mode); - - - void setInBuffer(int16_t *buffer, bool ownsBuffer = false) { - mInBuffer = buffer; - mOwnInBuffer = ownsBuffer; - } - int16_t *inBuffer() { - return mInBuffer; - } - void setOutBuffer(int16_t *buffer) { - mOutBuffer = buffer; - } - int16_t *outBuffer() { - return mOutBuffer; - } - - void startTrack() {mActiveTrackCnt++;} - void stopTrack() {mActiveTrackCnt--;} - int activeTracks() { return mActiveTrackCnt;} - - status_t dump(int fd, const Vector<String16>& args); - - protected: - - EffectChain(const EffectChain&); - EffectChain& operator =(const EffectChain&); - - wp<ThreadBase> mThread; // parent mixer thread - Mutex mLock; // mutex protecting effect list - Vector<sp<EffectModule> > mEffects; // list of effect modules - int mSessionId; // audio session ID - int16_t *mInBuffer; // chain input buffer - int16_t *mOutBuffer; // chain output buffer - int mVolumeCtrlIdx; // index of insert effect having control over volume - int mActiveTrackCnt; // number of active tracks connected - bool mOwnInBuffer; // true if the chain owns its input buffer - }; - - friend class RecordThread; - friend class PlaybackThread; - - - mutable Mutex mLock; - - DefaultKeyedVector< pid_t, wp<Client> > mClients; - - mutable Mutex mHardwareLock; - AudioHardwareInterface* mAudioHardware; - mutable int mHardwareStatus; - - - DefaultKeyedVector< int, sp<PlaybackThread> > mPlaybackThreads; - PlaybackThread::stream_type_t mStreamTypes[AudioSystem::NUM_STREAM_TYPES]; - float mMasterVolume; - bool mMasterMute; - - DefaultKeyedVector< int, sp<RecordThread> > mRecordThreads; - - DefaultKeyedVector< pid_t, sp<NotificationClient> > mNotificationClients; - volatile int32_t mNextUniqueId; -#ifdef LVMX - int mLifeVibesClientPid; -#endif - uint32_t mMode; - - // Maximum CPU load allocated to audio effects in 0.1 MIPS (ARMv5TE, 0 WS memory) units - static const uint32_t MAX_EFFECTS_CPU_LOAD = 1000; - // Maximum memory allocated to audio effects in KB - static const uint32_t MAX_EFFECTS_MEMORY = 512; - uint32_t mTotalEffectsCpuLoad; // current CPU load used by effects - uint32_t mTotalEffectsMemory; // current memory used by effects -}; - -// ---------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_AUDIO_FLINGER_H diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/libs/audioflinger/AudioHardwareGeneric.cpp deleted file mode 100644 index d63c031..0000000 --- a/libs/audioflinger/AudioHardwareGeneric.cpp +++ /dev/null @@ -1,411 +0,0 @@ -/* -** -** Copyright 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 <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <sched.h> -#include <fcntl.h> -#include <sys/ioctl.h> - -#define LOG_TAG "AudioHardware" -#include <utils/Log.h> -#include <utils/String8.h> - -#include "AudioHardwareGeneric.h" -#include <media/AudioRecord.h> - -namespace android { - -// ---------------------------------------------------------------------------- - -static char const * const kAudioDeviceName = "/dev/eac"; - -// ---------------------------------------------------------------------------- - -AudioHardwareGeneric::AudioHardwareGeneric() - : mOutput(0), mInput(0), mFd(-1), mMicMute(false) -{ - mFd = ::open(kAudioDeviceName, O_RDWR); -} - -AudioHardwareGeneric::~AudioHardwareGeneric() -{ - if (mFd >= 0) ::close(mFd); - closeOutputStream((AudioStreamOut *)mOutput); - closeInputStream((AudioStreamIn *)mInput); -} - -status_t AudioHardwareGeneric::initCheck() -{ - if (mFd >= 0) { - if (::access(kAudioDeviceName, O_RDWR) == NO_ERROR) - return NO_ERROR; - } - return NO_INIT; -} - -AudioStreamOut* AudioHardwareGeneric::openOutputStream( - uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status) -{ - AutoMutex lock(mLock); - - // only one output stream allowed - if (mOutput) { - if (status) { - *status = INVALID_OPERATION; - } - return 0; - } - - // create new output stream - AudioStreamOutGeneric* out = new AudioStreamOutGeneric(); - status_t lStatus = out->set(this, mFd, devices, format, channels, sampleRate); - if (status) { - *status = lStatus; - } - if (lStatus == NO_ERROR) { - mOutput = out; - } else { - delete out; - } - return mOutput; -} - -void AudioHardwareGeneric::closeOutputStream(AudioStreamOut* out) { - if (mOutput && out == mOutput) { - delete mOutput; - mOutput = 0; - } -} - -AudioStreamIn* AudioHardwareGeneric::openInputStream( - uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, - status_t *status, AudioSystem::audio_in_acoustics acoustics) -{ - // check for valid input source - if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) { - return 0; - } - - AutoMutex lock(mLock); - - // only one input stream allowed - if (mInput) { - if (status) { - *status = INVALID_OPERATION; - } - return 0; - } - - // create new output stream - AudioStreamInGeneric* in = new AudioStreamInGeneric(); - status_t lStatus = in->set(this, mFd, devices, format, channels, sampleRate, acoustics); - if (status) { - *status = lStatus; - } - if (lStatus == NO_ERROR) { - mInput = in; - } else { - delete in; - } - return mInput; -} - -void AudioHardwareGeneric::closeInputStream(AudioStreamIn* in) { - if (mInput && in == mInput) { - delete mInput; - mInput = 0; - } -} - -status_t AudioHardwareGeneric::setVoiceVolume(float v) -{ - // Implement: set voice volume - return NO_ERROR; -} - -status_t AudioHardwareGeneric::setMasterVolume(float v) -{ - // Implement: set master volume - // return error - software mixer will handle it - return INVALID_OPERATION; -} - -status_t AudioHardwareGeneric::setMicMute(bool state) -{ - mMicMute = state; - return NO_ERROR; -} - -status_t AudioHardwareGeneric::getMicMute(bool* state) -{ - *state = mMicMute; - return NO_ERROR; -} - -status_t AudioHardwareGeneric::dumpInternals(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - result.append("AudioHardwareGeneric::dumpInternals\n"); - snprintf(buffer, SIZE, "\tmFd: %d mMicMute: %s\n", mFd, mMicMute? "true": "false"); - result.append(buffer); - ::write(fd, result.string(), result.size()); - return NO_ERROR; -} - -status_t AudioHardwareGeneric::dump(int fd, const Vector<String16>& args) -{ - dumpInternals(fd, args); - if (mInput) { - mInput->dump(fd, args); - } - if (mOutput) { - mOutput->dump(fd, args); - } - return NO_ERROR; -} - -// ---------------------------------------------------------------------------- - -status_t AudioStreamOutGeneric::set( - AudioHardwareGeneric *hw, - int fd, - uint32_t devices, - int *pFormat, - uint32_t *pChannels, - uint32_t *pRate) -{ - int lFormat = pFormat ? *pFormat : 0; - uint32_t lChannels = pChannels ? *pChannels : 0; - uint32_t lRate = pRate ? *pRate : 0; - - // fix up defaults - if (lFormat == 0) lFormat = format(); - if (lChannels == 0) lChannels = channels(); - if (lRate == 0) lRate = sampleRate(); - - // check values - if ((lFormat != format()) || - (lChannels != channels()) || - (lRate != sampleRate())) { - if (pFormat) *pFormat = format(); - if (pChannels) *pChannels = channels(); - if (pRate) *pRate = sampleRate(); - return BAD_VALUE; - } - - if (pFormat) *pFormat = lFormat; - if (pChannels) *pChannels = lChannels; - if (pRate) *pRate = lRate; - - mAudioHardware = hw; - mFd = fd; - mDevice = devices; - return NO_ERROR; -} - -AudioStreamOutGeneric::~AudioStreamOutGeneric() -{ -} - -ssize_t AudioStreamOutGeneric::write(const void* buffer, size_t bytes) -{ - Mutex::Autolock _l(mLock); - return ssize_t(::write(mFd, buffer, bytes)); -} - -status_t AudioStreamOutGeneric::standby() -{ - // Implement: audio hardware to standby mode - return NO_ERROR; -} - -status_t AudioStreamOutGeneric::dump(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - snprintf(buffer, SIZE, "AudioStreamOutGeneric::dump\n"); - result.append(buffer); - snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate()); - result.append(buffer); - snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize()); - result.append(buffer); - snprintf(buffer, SIZE, "\tchannels: %d\n", channels()); - result.append(buffer); - snprintf(buffer, SIZE, "\tformat: %d\n", format()); - result.append(buffer); - snprintf(buffer, SIZE, "\tdevice: %d\n", mDevice); - result.append(buffer); - snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware); - result.append(buffer); - snprintf(buffer, SIZE, "\tmFd: %d\n", mFd); - result.append(buffer); - ::write(fd, result.string(), result.size()); - return NO_ERROR; -} - -status_t AudioStreamOutGeneric::setParameters(const String8& keyValuePairs) -{ - AudioParameter param = AudioParameter(keyValuePairs); - String8 key = String8(AudioParameter::keyRouting); - status_t status = NO_ERROR; - int device; - LOGV("setParameters() %s", keyValuePairs.string()); - - if (param.getInt(key, device) == NO_ERROR) { - mDevice = device; - param.remove(key); - } - - if (param.size()) { - status = BAD_VALUE; - } - return status; -} - -String8 AudioStreamOutGeneric::getParameters(const String8& keys) -{ - AudioParameter param = AudioParameter(keys); - String8 value; - String8 key = String8(AudioParameter::keyRouting); - - if (param.get(key, value) == NO_ERROR) { - param.addInt(key, (int)mDevice); - } - - LOGV("getParameters() %s", param.toString().string()); - return param.toString(); -} - -status_t AudioStreamOutGeneric::getRenderPosition(uint32_t *dspFrames) -{ - return INVALID_OPERATION; -} - -// ---------------------------------------------------------------------------- - -// record functions -status_t AudioStreamInGeneric::set( - AudioHardwareGeneric *hw, - int fd, - uint32_t devices, - int *pFormat, - uint32_t *pChannels, - uint32_t *pRate, - AudioSystem::audio_in_acoustics acoustics) -{ - if (pFormat == 0 || pChannels == 0 || pRate == 0) return BAD_VALUE; - LOGV("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, *pFormat, *pChannels, *pRate); - // check values - if ((*pFormat != format()) || - (*pChannels != channels()) || - (*pRate != sampleRate())) { - LOGE("Error opening input channel"); - *pFormat = format(); - *pChannels = channels(); - *pRate = sampleRate(); - return BAD_VALUE; - } - - mAudioHardware = hw; - mFd = fd; - mDevice = devices; - return NO_ERROR; -} - -AudioStreamInGeneric::~AudioStreamInGeneric() -{ -} - -ssize_t AudioStreamInGeneric::read(void* buffer, ssize_t bytes) -{ - AutoMutex lock(mLock); - if (mFd < 0) { - LOGE("Attempt to read from unopened device"); - return NO_INIT; - } - return ::read(mFd, buffer, bytes); -} - -status_t AudioStreamInGeneric::dump(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - snprintf(buffer, SIZE, "AudioStreamInGeneric::dump\n"); - result.append(buffer); - snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate()); - result.append(buffer); - snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize()); - result.append(buffer); - snprintf(buffer, SIZE, "\tchannels: %d\n", channels()); - result.append(buffer); - snprintf(buffer, SIZE, "\tformat: %d\n", format()); - result.append(buffer); - snprintf(buffer, SIZE, "\tdevice: %d\n", mDevice); - result.append(buffer); - snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware); - result.append(buffer); - snprintf(buffer, SIZE, "\tmFd: %d\n", mFd); - result.append(buffer); - ::write(fd, result.string(), result.size()); - return NO_ERROR; -} - -status_t AudioStreamInGeneric::setParameters(const String8& keyValuePairs) -{ - AudioParameter param = AudioParameter(keyValuePairs); - String8 key = String8(AudioParameter::keyRouting); - status_t status = NO_ERROR; - int device; - LOGV("setParameters() %s", keyValuePairs.string()); - - if (param.getInt(key, device) == NO_ERROR) { - mDevice = device; - param.remove(key); - } - - if (param.size()) { - status = BAD_VALUE; - } - return status; -} - -String8 AudioStreamInGeneric::getParameters(const String8& keys) -{ - AudioParameter param = AudioParameter(keys); - String8 value; - String8 key = String8(AudioParameter::keyRouting); - - if (param.get(key, value) == NO_ERROR) { - param.addInt(key, (int)mDevice); - } - - LOGV("getParameters() %s", param.toString().string()); - return param.toString(); -} - -// ---------------------------------------------------------------------------- - -}; // namespace android diff --git a/libs/audioflinger/AudioHardwareGeneric.h b/libs/audioflinger/AudioHardwareGeneric.h deleted file mode 100644 index aa4e78d..0000000 --- a/libs/audioflinger/AudioHardwareGeneric.h +++ /dev/null @@ -1,151 +0,0 @@ -/* -** -** Copyright 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. -*/ - -#ifndef ANDROID_AUDIO_HARDWARE_GENERIC_H -#define ANDROID_AUDIO_HARDWARE_GENERIC_H - -#include <stdint.h> -#include <sys/types.h> - -#include <utils/threads.h> - -#include <hardware_legacy/AudioHardwareBase.h> - -namespace android { - -// ---------------------------------------------------------------------------- - -class AudioHardwareGeneric; - -class AudioStreamOutGeneric : public AudioStreamOut { -public: - AudioStreamOutGeneric() : mAudioHardware(0), mFd(-1) {} - virtual ~AudioStreamOutGeneric(); - - virtual status_t set( - AudioHardwareGeneric *hw, - int mFd, - uint32_t devices, - int *pFormat, - uint32_t *pChannels, - uint32_t *pRate); - - virtual uint32_t sampleRate() const { return 44100; } - virtual size_t bufferSize() const { return 4096; } - virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; } - virtual int format() const { return AudioSystem::PCM_16_BIT; } - virtual uint32_t latency() const { return 20; } - virtual status_t setVolume(float left, float right) { return INVALID_OPERATION; } - virtual ssize_t write(const void* buffer, size_t bytes); - virtual status_t standby(); - virtual status_t dump(int fd, const Vector<String16>& args); - virtual status_t setParameters(const String8& keyValuePairs); - virtual String8 getParameters(const String8& keys); - virtual status_t getRenderPosition(uint32_t *dspFrames); - -private: - AudioHardwareGeneric *mAudioHardware; - Mutex mLock; - int mFd; - uint32_t mDevice; -}; - -class AudioStreamInGeneric : public AudioStreamIn { -public: - AudioStreamInGeneric() : mAudioHardware(0), mFd(-1) {} - virtual ~AudioStreamInGeneric(); - - virtual status_t set( - AudioHardwareGeneric *hw, - int mFd, - uint32_t devices, - int *pFormat, - uint32_t *pChannels, - uint32_t *pRate, - AudioSystem::audio_in_acoustics acoustics); - - virtual uint32_t sampleRate() const { return 8000; } - virtual size_t bufferSize() const { return 320; } - virtual uint32_t channels() const { return AudioSystem::CHANNEL_IN_MONO; } - virtual int format() const { return AudioSystem::PCM_16_BIT; } - virtual status_t setGain(float gain) { return INVALID_OPERATION; } - virtual ssize_t read(void* buffer, ssize_t bytes); - virtual status_t dump(int fd, const Vector<String16>& args); - virtual status_t standby() { return NO_ERROR; } - virtual status_t setParameters(const String8& keyValuePairs); - virtual String8 getParameters(const String8& keys); - virtual unsigned int getInputFramesLost() const { return 0; } - -private: - AudioHardwareGeneric *mAudioHardware; - Mutex mLock; - int mFd; - uint32_t mDevice; -}; - - -class AudioHardwareGeneric : public AudioHardwareBase -{ -public: - AudioHardwareGeneric(); - virtual ~AudioHardwareGeneric(); - virtual status_t initCheck(); - virtual status_t setVoiceVolume(float volume); - virtual status_t setMasterVolume(float volume); - - // mic mute - virtual status_t setMicMute(bool state); - virtual status_t getMicMute(bool* state); - - // create I/O streams - virtual AudioStreamOut* openOutputStream( - uint32_t devices, - int *format=0, - uint32_t *channels=0, - uint32_t *sampleRate=0, - status_t *status=0); - virtual void closeOutputStream(AudioStreamOut* out); - - virtual AudioStreamIn* openInputStream( - uint32_t devices, - int *format, - uint32_t *channels, - uint32_t *sampleRate, - status_t *status, - AudioSystem::audio_in_acoustics acoustics); - virtual void closeInputStream(AudioStreamIn* in); - - void closeOutputStream(AudioStreamOutGeneric* out); - void closeInputStream(AudioStreamInGeneric* in); -protected: - virtual status_t dump(int fd, const Vector<String16>& args); - -private: - status_t dumpInternals(int fd, const Vector<String16>& args); - - Mutex mLock; - AudioStreamOutGeneric *mOutput; - AudioStreamInGeneric *mInput; - int mFd; - bool mMicMute; -}; - -// ---------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_AUDIO_HARDWARE_GENERIC_H diff --git a/libs/audioflinger/AudioHardwareInterface.cpp b/libs/audioflinger/AudioHardwareInterface.cpp deleted file mode 100644 index 9a4a7f9..0000000 --- a/libs/audioflinger/AudioHardwareInterface.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/* -** -** Copyright 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 <cutils/properties.h> -#include <string.h> -#include <unistd.h> -//#define LOG_NDEBUG 0 - -#define LOG_TAG "AudioHardwareInterface" -#include <utils/Log.h> -#include <utils/String8.h> - -#include "AudioHardwareStub.h" -#include "AudioHardwareGeneric.h" -#ifdef WITH_A2DP -#include "A2dpAudioInterface.h" -#endif - -#ifdef ENABLE_AUDIO_DUMP -#include "AudioDumpInterface.h" -#endif - - -// change to 1 to log routing calls -#define LOG_ROUTING_CALLS 1 - -namespace android { - -#if LOG_ROUTING_CALLS -static const char* routingModeStrings[] = -{ - "OUT OF RANGE", - "INVALID", - "CURRENT", - "NORMAL", - "RINGTONE", - "IN_CALL" -}; - -static const char* routeNone = "NONE"; - -static const char* displayMode(int mode) -{ - if ((mode < -2) || (mode > 2)) - return routingModeStrings[0]; - return routingModeStrings[mode+3]; -} -#endif - -// ---------------------------------------------------------------------------- - -AudioHardwareInterface* AudioHardwareInterface::create() -{ - /* - * FIXME: This code needs to instantiate the correct audio device - * interface. For now - we use compile-time switches. - */ - AudioHardwareInterface* hw = 0; - char value[PROPERTY_VALUE_MAX]; - -#ifdef GENERIC_AUDIO - hw = new AudioHardwareGeneric(); -#else - // if running in emulation - use the emulator driver - if (property_get("ro.kernel.qemu", value, 0)) { - LOGD("Running in emulation - using generic audio driver"); - hw = new AudioHardwareGeneric(); - } - else { - LOGV("Creating Vendor Specific AudioHardware"); - hw = createAudioHardware(); - } -#endif - if (hw->initCheck() != NO_ERROR) { - LOGW("Using stubbed audio hardware. No sound will be produced."); - delete hw; - hw = new AudioHardwareStub(); - } - -#ifdef WITH_A2DP - hw = new A2dpAudioInterface(hw); -#endif - -#ifdef ENABLE_AUDIO_DUMP - // This code adds a record of buffers in a file to write calls made by AudioFlinger. - // It replaces the current AudioHardwareInterface object by an intermediate one which - // will record buffers in a file (after sending them to hardware) for testing purpose. - // This feature is enabled by defining symbol ENABLE_AUDIO_DUMP. - // The output file is set with setParameters("test_cmd_file_name=<name>"). Pause are not recorded in the file. - LOGV("opening PCM dump interface"); - hw = new AudioDumpInterface(hw); // replace interface -#endif - return hw; -} - -AudioStreamOut::~AudioStreamOut() -{ -} - -AudioStreamIn::~AudioStreamIn() {} - -AudioHardwareBase::AudioHardwareBase() -{ - mMode = 0; -} - -status_t AudioHardwareBase::setMode(int mode) -{ -#if LOG_ROUTING_CALLS - LOGD("setMode(%s)", displayMode(mode)); -#endif - if ((mode < 0) || (mode >= AudioSystem::NUM_MODES)) - return BAD_VALUE; - if (mMode == mode) - return ALREADY_EXISTS; - mMode = mode; - return NO_ERROR; -} - -// default implementation -status_t AudioHardwareBase::setParameters(const String8& keyValuePairs) -{ - return NO_ERROR; -} - -// default implementation -String8 AudioHardwareBase::getParameters(const String8& keys) -{ - AudioParameter param = AudioParameter(keys); - return param.toString(); -} - -// default implementation -size_t AudioHardwareBase::getInputBufferSize(uint32_t sampleRate, int format, int channelCount) -{ - if (sampleRate != 8000) { - LOGW("getInputBufferSize bad sampling rate: %d", sampleRate); - return 0; - } - if (format != AudioSystem::PCM_16_BIT) { - LOGW("getInputBufferSize bad format: %d", format); - return 0; - } - if (channelCount != 1) { - LOGW("getInputBufferSize bad channel count: %d", channelCount); - return 0; - } - - return 320; -} - -status_t AudioHardwareBase::dumpState(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - snprintf(buffer, SIZE, "AudioHardwareBase::dumpState\n"); - result.append(buffer); - snprintf(buffer, SIZE, "\tmMode: %d\n", mMode); - result.append(buffer); - ::write(fd, result.string(), result.size()); - dump(fd, args); // Dump the state of the concrete child. - return NO_ERROR; -} - -// ---------------------------------------------------------------------------- - -}; // namespace android diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/libs/audioflinger/AudioHardwareStub.cpp deleted file mode 100644 index d481150..0000000 --- a/libs/audioflinger/AudioHardwareStub.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/* //device/servers/AudioFlinger/AudioHardwareStub.cpp -** -** Copyright 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 <stdlib.h> -#include <unistd.h> -#include <utils/String8.h> - -#include "AudioHardwareStub.h" -#include <media/AudioRecord.h> - -namespace android { - -// ---------------------------------------------------------------------------- - -AudioHardwareStub::AudioHardwareStub() : mMicMute(false) -{ -} - -AudioHardwareStub::~AudioHardwareStub() -{ -} - -status_t AudioHardwareStub::initCheck() -{ - return NO_ERROR; -} - -AudioStreamOut* AudioHardwareStub::openOutputStream( - uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status) -{ - AudioStreamOutStub* out = new AudioStreamOutStub(); - status_t lStatus = out->set(format, channels, sampleRate); - if (status) { - *status = lStatus; - } - if (lStatus == NO_ERROR) - return out; - delete out; - return 0; -} - -void AudioHardwareStub::closeOutputStream(AudioStreamOut* out) -{ - delete out; -} - -AudioStreamIn* AudioHardwareStub::openInputStream( - uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, - status_t *status, AudioSystem::audio_in_acoustics acoustics) -{ - // check for valid input source - if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) { - return 0; - } - - AudioStreamInStub* in = new AudioStreamInStub(); - status_t lStatus = in->set(format, channels, sampleRate, acoustics); - if (status) { - *status = lStatus; - } - if (lStatus == NO_ERROR) - return in; - delete in; - return 0; -} - -void AudioHardwareStub::closeInputStream(AudioStreamIn* in) -{ - delete in; -} - -status_t AudioHardwareStub::setVoiceVolume(float volume) -{ - return NO_ERROR; -} - -status_t AudioHardwareStub::setMasterVolume(float volume) -{ - return NO_ERROR; -} - -status_t AudioHardwareStub::dumpInternals(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - result.append("AudioHardwareStub::dumpInternals\n"); - snprintf(buffer, SIZE, "\tmMicMute: %s\n", mMicMute? "true": "false"); - result.append(buffer); - ::write(fd, result.string(), result.size()); - return NO_ERROR; -} - -status_t AudioHardwareStub::dump(int fd, const Vector<String16>& args) -{ - dumpInternals(fd, args); - return NO_ERROR; -} - -// ---------------------------------------------------------------------------- - -status_t AudioStreamOutStub::set(int *pFormat, uint32_t *pChannels, uint32_t *pRate) -{ - if (pFormat) *pFormat = format(); - if (pChannels) *pChannels = channels(); - if (pRate) *pRate = sampleRate(); - - return NO_ERROR; -} - -ssize_t AudioStreamOutStub::write(const void* buffer, size_t bytes) -{ - // fake timing for audio output - usleep(bytes * 1000000 / sizeof(int16_t) / AudioSystem::popCount(channels()) / sampleRate()); - return bytes; -} - -status_t AudioStreamOutStub::standby() -{ - return NO_ERROR; -} - -status_t AudioStreamOutStub::dump(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - snprintf(buffer, SIZE, "AudioStreamOutStub::dump\n"); - snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate()); - snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize()); - snprintf(buffer, SIZE, "\tchannels: %d\n", channels()); - snprintf(buffer, SIZE, "\tformat: %d\n", format()); - result.append(buffer); - ::write(fd, result.string(), result.size()); - return NO_ERROR; -} - -String8 AudioStreamOutStub::getParameters(const String8& keys) -{ - AudioParameter param = AudioParameter(keys); - return param.toString(); -} - -status_t AudioStreamOutStub::getRenderPosition(uint32_t *dspFrames) -{ - return INVALID_OPERATION; -} - -// ---------------------------------------------------------------------------- - -status_t AudioStreamInStub::set(int *pFormat, uint32_t *pChannels, uint32_t *pRate, - AudioSystem::audio_in_acoustics acoustics) -{ - return NO_ERROR; -} - -ssize_t AudioStreamInStub::read(void* buffer, ssize_t bytes) -{ - // fake timing for audio input - usleep(bytes * 1000000 / sizeof(int16_t) / AudioSystem::popCount(channels()) / sampleRate()); - memset(buffer, 0, bytes); - return bytes; -} - -status_t AudioStreamInStub::dump(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - snprintf(buffer, SIZE, "AudioStreamInStub::dump\n"); - result.append(buffer); - snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate()); - result.append(buffer); - snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize()); - result.append(buffer); - snprintf(buffer, SIZE, "\tchannels: %d\n", channels()); - result.append(buffer); - snprintf(buffer, SIZE, "\tformat: %d\n", format()); - result.append(buffer); - ::write(fd, result.string(), result.size()); - return NO_ERROR; -} - -String8 AudioStreamInStub::getParameters(const String8& keys) -{ - AudioParameter param = AudioParameter(keys); - return param.toString(); -} - -// ---------------------------------------------------------------------------- - -}; // namespace android diff --git a/libs/audioflinger/AudioHardwareStub.h b/libs/audioflinger/AudioHardwareStub.h deleted file mode 100644 index 06a29de..0000000 --- a/libs/audioflinger/AudioHardwareStub.h +++ /dev/null @@ -1,106 +0,0 @@ -/* //device/servers/AudioFlinger/AudioHardwareStub.h -** -** Copyright 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. -*/ - -#ifndef ANDROID_AUDIO_HARDWARE_STUB_H -#define ANDROID_AUDIO_HARDWARE_STUB_H - -#include <stdint.h> -#include <sys/types.h> - -#include <hardware_legacy/AudioHardwareBase.h> - -namespace android { - -// ---------------------------------------------------------------------------- - -class AudioStreamOutStub : public AudioStreamOut { -public: - virtual status_t set(int *pFormat, uint32_t *pChannels, uint32_t *pRate); - virtual uint32_t sampleRate() const { return 44100; } - virtual size_t bufferSize() const { return 4096; } - virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; } - virtual int format() const { return AudioSystem::PCM_16_BIT; } - virtual uint32_t latency() const { return 0; } - virtual status_t setVolume(float left, float right) { return NO_ERROR; } - virtual ssize_t write(const void* buffer, size_t bytes); - virtual status_t standby(); - virtual status_t dump(int fd, const Vector<String16>& args); - virtual status_t setParameters(const String8& keyValuePairs) { return NO_ERROR;} - virtual String8 getParameters(const String8& keys); - virtual status_t getRenderPosition(uint32_t *dspFrames); -}; - -class AudioStreamInStub : public AudioStreamIn { -public: - virtual status_t set(int *pFormat, uint32_t *pChannels, uint32_t *pRate, AudioSystem::audio_in_acoustics acoustics); - virtual uint32_t sampleRate() const { return 8000; } - virtual size_t bufferSize() const { return 320; } - virtual uint32_t channels() const { return AudioSystem::CHANNEL_IN_MONO; } - virtual int format() const { return AudioSystem::PCM_16_BIT; } - virtual status_t setGain(float gain) { return NO_ERROR; } - virtual ssize_t read(void* buffer, ssize_t bytes); - virtual status_t dump(int fd, const Vector<String16>& args); - virtual status_t standby() { return NO_ERROR; } - virtual status_t setParameters(const String8& keyValuePairs) { return NO_ERROR;} - virtual String8 getParameters(const String8& keys); - virtual unsigned int getInputFramesLost() const { return 0; } -}; - -class AudioHardwareStub : public AudioHardwareBase -{ -public: - AudioHardwareStub(); - virtual ~AudioHardwareStub(); - virtual status_t initCheck(); - virtual status_t setVoiceVolume(float volume); - virtual status_t setMasterVolume(float volume); - - // mic mute - virtual status_t setMicMute(bool state) { mMicMute = state; return NO_ERROR; } - virtual status_t getMicMute(bool* state) { *state = mMicMute ; return NO_ERROR; } - - // create I/O streams - virtual AudioStreamOut* openOutputStream( - uint32_t devices, - int *format=0, - uint32_t *channels=0, - uint32_t *sampleRate=0, - status_t *status=0); - virtual void closeOutputStream(AudioStreamOut* out); - - virtual AudioStreamIn* openInputStream( - uint32_t devices, - int *format, - uint32_t *channels, - uint32_t *sampleRate, - status_t *status, - AudioSystem::audio_in_acoustics acoustics); - virtual void closeInputStream(AudioStreamIn* in); - -protected: - virtual status_t dump(int fd, const Vector<String16>& args); - - bool mMicMute; -private: - status_t dumpInternals(int fd, const Vector<String16>& args); -}; - -// ---------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_AUDIO_HARDWARE_STUB_H diff --git a/libs/audioflinger/AudioMixer.cpp b/libs/audioflinger/AudioMixer.cpp deleted file mode 100644 index 8aaa325..0000000 --- a/libs/audioflinger/AudioMixer.cpp +++ /dev/null @@ -1,1195 +0,0 @@ -/* //device/include/server/AudioFlinger/AudioMixer.cpp -** -** Copyright 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. -*/ - -#define LOG_TAG "AudioMixer" -//#define LOG_NDEBUG 0 - -#include <stdint.h> -#include <string.h> -#include <stdlib.h> -#include <sys/types.h> - -#include <utils/Errors.h> -#include <utils/Log.h> - -#include "AudioMixer.h" - -namespace android { -// ---------------------------------------------------------------------------- - -static inline int16_t clamp16(int32_t sample) -{ - if ((sample>>15) ^ (sample>>31)) - sample = 0x7FFF ^ (sample>>31); - return sample; -} - -// ---------------------------------------------------------------------------- - -AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate) - : mActiveTrack(0), mTrackNames(0), mSampleRate(sampleRate) -{ - mState.enabledTracks= 0; - mState.needsChanged = 0; - mState.frameCount = frameCount; - mState.outputTemp = 0; - mState.resampleTemp = 0; - mState.hook = process__nop; - track_t* t = mState.tracks; - for (int i=0 ; i<32 ; i++) { - t->needs = 0; - t->volume[0] = UNITY_GAIN; - t->volume[1] = UNITY_GAIN; - t->volumeInc[0] = 0; - t->volumeInc[1] = 0; - t->auxLevel = 0; - t->auxInc = 0; - t->channelCount = 2; - t->enabled = 0; - t->format = 16; - t->buffer.raw = 0; - t->bufferProvider = 0; - t->hook = 0; - t->resampler = 0; - t->sampleRate = mSampleRate; - t->in = 0; - t->mainBuffer = NULL; - t->auxBuffer = NULL; - t++; - } -} - - AudioMixer::~AudioMixer() - { - track_t* t = mState.tracks; - for (int i=0 ; i<32 ; i++) { - delete t->resampler; - t++; - } - delete [] mState.outputTemp; - delete [] mState.resampleTemp; - } - - int AudioMixer::getTrackName() - { - uint32_t names = mTrackNames; - uint32_t mask = 1; - int n = 0; - while (names & mask) { - mask <<= 1; - n++; - } - if (mask) { - LOGV("add track (%d)", n); - mTrackNames |= mask; - return TRACK0 + n; - } - return -1; - } - - void AudioMixer::invalidateState(uint32_t mask) - { - if (mask) { - mState.needsChanged |= mask; - mState.hook = process__validate; - } - } - - void AudioMixer::deleteTrackName(int name) - { - name -= TRACK0; - if (uint32_t(name) < MAX_NUM_TRACKS) { - LOGV("deleteTrackName(%d)", name); - track_t& track(mState.tracks[ name ]); - if (track.enabled != 0) { - track.enabled = 0; - invalidateState(1<<name); - } - if (track.resampler) { - // delete the resampler - delete track.resampler; - track.resampler = 0; - track.sampleRate = mSampleRate; - invalidateState(1<<name); - } - track.volumeInc[0] = 0; - track.volumeInc[1] = 0; - mTrackNames &= ~(1<<name); - } - } - -status_t AudioMixer::enable(int name) -{ - switch (name) { - case MIXING: { - if (mState.tracks[ mActiveTrack ].enabled != 1) { - mState.tracks[ mActiveTrack ].enabled = 1; - LOGV("enable(%d)", mActiveTrack); - invalidateState(1<<mActiveTrack); - } - } break; - default: - return NAME_NOT_FOUND; - } - return NO_ERROR; -} - -status_t AudioMixer::disable(int name) -{ - switch (name) { - case MIXING: { - if (mState.tracks[ mActiveTrack ].enabled != 0) { - mState.tracks[ mActiveTrack ].enabled = 0; - LOGV("disable(%d)", mActiveTrack); - invalidateState(1<<mActiveTrack); - } - } break; - default: - return NAME_NOT_FOUND; - } - return NO_ERROR; -} - -status_t AudioMixer::setActiveTrack(int track) -{ - if (uint32_t(track-TRACK0) >= MAX_NUM_TRACKS) { - return BAD_VALUE; - } - mActiveTrack = track - TRACK0; - return NO_ERROR; -} - -status_t AudioMixer::setParameter(int target, int name, void *value) -{ - int valueInt = (int)value; - int32_t *valueBuf = (int32_t *)value; - - switch (target) { - case TRACK: - if (name == CHANNEL_COUNT) { - if ((uint32_t(valueInt) <= MAX_NUM_CHANNELS) && (valueInt)) { - if (mState.tracks[ mActiveTrack ].channelCount != valueInt) { - mState.tracks[ mActiveTrack ].channelCount = valueInt; - LOGV("setParameter(TRACK, CHANNEL_COUNT, %d)", valueInt); - invalidateState(1<<mActiveTrack); - } - return NO_ERROR; - } - } - if (name == MAIN_BUFFER) { - if (mState.tracks[ mActiveTrack ].mainBuffer != valueBuf) { - mState.tracks[ mActiveTrack ].mainBuffer = valueBuf; - LOGV("setParameter(TRACK, MAIN_BUFFER, %p)", valueBuf); - invalidateState(1<<mActiveTrack); - } - return NO_ERROR; - } - if (name == AUX_BUFFER) { - if (mState.tracks[ mActiveTrack ].auxBuffer != valueBuf) { - mState.tracks[ mActiveTrack ].auxBuffer = valueBuf; - LOGV("setParameter(TRACK, AUX_BUFFER, %p)", valueBuf); - invalidateState(1<<mActiveTrack); - } - return NO_ERROR; - } - - break; - case RESAMPLE: - if (name == SAMPLE_RATE) { - if (valueInt > 0) { - track_t& track = mState.tracks[ mActiveTrack ]; - if (track.setResampler(uint32_t(valueInt), mSampleRate)) { - LOGV("setParameter(RESAMPLE, SAMPLE_RATE, %u)", - uint32_t(valueInt)); - invalidateState(1<<mActiveTrack); - } - return NO_ERROR; - } - } - break; - case RAMP_VOLUME: - case VOLUME: - if ((uint32_t(name-VOLUME0) < MAX_NUM_CHANNELS)) { - track_t& track = mState.tracks[ mActiveTrack ]; - if (track.volume[name-VOLUME0] != valueInt) { - LOGV("setParameter(VOLUME, VOLUME0/1: %04x)", valueInt); - track.prevVolume[name-VOLUME0] = track.volume[name-VOLUME0] << 16; - track.volume[name-VOLUME0] = valueInt; - if (target == VOLUME) { - track.prevVolume[name-VOLUME0] = valueInt << 16; - track.volumeInc[name-VOLUME0] = 0; - } else { - int32_t d = (valueInt<<16) - track.prevVolume[name-VOLUME0]; - int32_t volInc = d / int32_t(mState.frameCount); - track.volumeInc[name-VOLUME0] = volInc; - if (volInc == 0) { - track.prevVolume[name-VOLUME0] = valueInt << 16; - } - } - invalidateState(1<<mActiveTrack); - } - return NO_ERROR; - } else if (name == AUXLEVEL) { - track_t& track = mState.tracks[ mActiveTrack ]; - if (track.auxLevel != valueInt) { - LOGV("setParameter(VOLUME, AUXLEVEL: %04x)", valueInt); - track.prevAuxLevel = track.auxLevel << 16; - track.auxLevel = valueInt; - if (target == VOLUME) { - track.prevAuxLevel = valueInt << 16; - track.auxInc = 0; - } else { - int32_t d = (valueInt<<16) - track.prevAuxLevel; - int32_t volInc = d / int32_t(mState.frameCount); - track.auxInc = volInc; - if (volInc == 0) { - track.prevAuxLevel = valueInt << 16; - } - } - invalidateState(1<<mActiveTrack); - } - return NO_ERROR; - } - break; - } - return BAD_VALUE; -} - -bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate) -{ - if (value!=devSampleRate || resampler) { - if (sampleRate != value) { - sampleRate = value; - if (resampler == 0) { - resampler = AudioResampler::create( - format, channelCount, devSampleRate); - } - return true; - } - } - return false; -} - -bool AudioMixer::track_t::doesResample() const -{ - return resampler != 0; -} - -inline -void AudioMixer::track_t::adjustVolumeRamp(bool aux) -{ - for (int i=0 ; i<2 ; i++) { - if (((volumeInc[i]>0) && (((prevVolume[i]+volumeInc[i])>>16) >= volume[i])) || - ((volumeInc[i]<0) && (((prevVolume[i]+volumeInc[i])>>16) <= volume[i]))) { - volumeInc[i] = 0; - prevVolume[i] = volume[i]<<16; - } - } - if (aux) { - if (((auxInc>0) && (((prevAuxLevel+auxInc)>>16) >= auxLevel)) || - ((auxInc<0) && (((prevAuxLevel+auxInc)>>16) <= auxLevel))) { - auxInc = 0; - prevAuxLevel = auxLevel<<16; - } - } -} - - -status_t AudioMixer::setBufferProvider(AudioBufferProvider* buffer) -{ - mState.tracks[ mActiveTrack ].bufferProvider = buffer; - return NO_ERROR; -} - - - -void AudioMixer::process() -{ - mState.hook(&mState); -} - - -void AudioMixer::process__validate(state_t* state) -{ - LOGW_IF(!state->needsChanged, - "in process__validate() but nothing's invalid"); - - uint32_t changed = state->needsChanged; - state->needsChanged = 0; // clear the validation flag - - // recompute which tracks are enabled / disabled - uint32_t enabled = 0; - uint32_t disabled = 0; - while (changed) { - const int i = 31 - __builtin_clz(changed); - const uint32_t mask = 1<<i; - changed &= ~mask; - track_t& t = state->tracks[i]; - (t.enabled ? enabled : disabled) |= mask; - } - state->enabledTracks &= ~disabled; - state->enabledTracks |= enabled; - - // compute everything we need... - int countActiveTracks = 0; - int all16BitsStereoNoResample = 1; - int resampling = 0; - int volumeRamp = 0; - uint32_t en = state->enabledTracks; - while (en) { - const int i = 31 - __builtin_clz(en); - en &= ~(1<<i); - - countActiveTracks++; - track_t& t = state->tracks[i]; - uint32_t n = 0; - n |= NEEDS_CHANNEL_1 + t.channelCount - 1; - n |= NEEDS_FORMAT_16; - n |= t.doesResample() ? NEEDS_RESAMPLE_ENABLED : NEEDS_RESAMPLE_DISABLED; - if (t.auxLevel != 0 && t.auxBuffer != NULL) { - n |= NEEDS_AUX_ENABLED; - } - - if (t.volumeInc[0]|t.volumeInc[1]) { - volumeRamp = 1; - } else if (!t.doesResample() && t.volumeRL == 0) { - n |= NEEDS_MUTE_ENABLED; - } - t.needs = n; - - if ((n & NEEDS_MUTE__MASK) == NEEDS_MUTE_ENABLED) { - t.hook = track__nop; - } else { - if ((n & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) { - all16BitsStereoNoResample = 0; - } - if ((n & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) { - all16BitsStereoNoResample = 0; - resampling = 1; - t.hook = track__genericResample; - } else { - if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){ - t.hook = track__16BitsMono; - all16BitsStereoNoResample = 0; - } - if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_2){ - t.hook = track__16BitsStereo; - } - } - } - } - - // select the processing hooks - state->hook = process__nop; - if (countActiveTracks) { - if (resampling) { - if (!state->outputTemp) { - state->outputTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount]; - } - if (!state->resampleTemp) { - state->resampleTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount]; - } - state->hook = process__genericResampling; - } else { - if (state->outputTemp) { - delete [] state->outputTemp; - state->outputTemp = 0; - } - if (state->resampleTemp) { - delete [] state->resampleTemp; - state->resampleTemp = 0; - } - state->hook = process__genericNoResampling; - if (all16BitsStereoNoResample && !volumeRamp) { - if (countActiveTracks == 1) { - state->hook = process__OneTrack16BitsStereoNoResampling; - } - } - } - } - - LOGV("mixer configuration change: %d activeTracks (%08x) " - "all16BitsStereoNoResample=%d, resampling=%d, volumeRamp=%d", - countActiveTracks, state->enabledTracks, - all16BitsStereoNoResample, resampling, volumeRamp); - - state->hook(state); - - // Now that the volume ramp has been done, set optimal state and - // track hooks for subsequent mixer process - if (countActiveTracks) { - int allMuted = 1; - uint32_t en = state->enabledTracks; - while (en) { - const int i = 31 - __builtin_clz(en); - en &= ~(1<<i); - track_t& t = state->tracks[i]; - if (!t.doesResample() && t.volumeRL == 0) - { - t.needs |= NEEDS_MUTE_ENABLED; - t.hook = track__nop; - } else { - allMuted = 0; - } - } - if (allMuted) { - state->hook = process__nop; - } else if (all16BitsStereoNoResample) { - if (countActiveTracks == 1) { - state->hook = process__OneTrack16BitsStereoNoResampling; - } - } - } -} - -static inline -int32_t mulAdd(int16_t in, int16_t v, int32_t a) -{ -#if defined(__arm__) && !defined(__thumb__) - int32_t out; - asm( "smlabb %[out], %[in], %[v], %[a] \n" - : [out]"=r"(out) - : [in]"%r"(in), [v]"r"(v), [a]"r"(a) - : ); - return out; -#else - return a + in * int32_t(v); -#endif -} - -static inline -int32_t mul(int16_t in, int16_t v) -{ -#if defined(__arm__) && !defined(__thumb__) - int32_t out; - asm( "smulbb %[out], %[in], %[v] \n" - : [out]"=r"(out) - : [in]"%r"(in), [v]"r"(v) - : ); - return out; -#else - return in * int32_t(v); -#endif -} - -static inline -int32_t mulAddRL(int left, uint32_t inRL, uint32_t vRL, int32_t a) -{ -#if defined(__arm__) && !defined(__thumb__) - int32_t out; - if (left) { - asm( "smlabb %[out], %[inRL], %[vRL], %[a] \n" - : [out]"=r"(out) - : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a) - : ); - } else { - asm( "smlatt %[out], %[inRL], %[vRL], %[a] \n" - : [out]"=r"(out) - : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a) - : ); - } - return out; -#else - if (left) { - return a + int16_t(inRL&0xFFFF) * int16_t(vRL&0xFFFF); - } else { - return a + int16_t(inRL>>16) * int16_t(vRL>>16); - } -#endif -} - -static inline -int32_t mulRL(int left, uint32_t inRL, uint32_t vRL) -{ -#if defined(__arm__) && !defined(__thumb__) - int32_t out; - if (left) { - asm( "smulbb %[out], %[inRL], %[vRL] \n" - : [out]"=r"(out) - : [inRL]"%r"(inRL), [vRL]"r"(vRL) - : ); - } else { - asm( "smultt %[out], %[inRL], %[vRL] \n" - : [out]"=r"(out) - : [inRL]"%r"(inRL), [vRL]"r"(vRL) - : ); - } - return out; -#else - if (left) { - return int16_t(inRL&0xFFFF) * int16_t(vRL&0xFFFF); - } else { - return int16_t(inRL>>16) * int16_t(vRL>>16); - } -#endif -} - - -void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp, int32_t* aux) -{ - t->resampler->setSampleRate(t->sampleRate); - - // ramp gain - resample to temp buffer and scale/mix in 2nd step - if (aux != NULL) { - // always resample with unity gain when sending to auxiliary buffer to be able - // to apply send level after resampling - // TODO: modify each resampler to support aux channel? - t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN); - memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t)); - t->resampler->resample(temp, outFrameCount, t->bufferProvider); - if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) { - volumeRampStereo(t, out, outFrameCount, temp, aux); - } else { - volumeStereo(t, out, outFrameCount, temp, aux); - } - } else { - if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) { - t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN); - memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t)); - t->resampler->resample(temp, outFrameCount, t->bufferProvider); - volumeRampStereo(t, out, outFrameCount, temp, aux); - } - - // constant gain - else { - t->resampler->setVolume(t->volume[0], t->volume[1]); - t->resampler->resample(out, outFrameCount, t->bufferProvider); - } - } -} - -void AudioMixer::track__nop(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp, int32_t* aux) -{ -} - -void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux) -{ - int32_t vl = t->prevVolume[0]; - int32_t vr = t->prevVolume[1]; - const int32_t vlInc = t->volumeInc[0]; - const int32_t vrInc = t->volumeInc[1]; - - //LOGD("[0] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", - // t, vlInc/65536.0f, vl/65536.0f, t->volume[0], - // (vl + vlInc*frameCount)/65536.0f, frameCount); - - // ramp volume - if UNLIKELY(aux != NULL) { - int32_t va = t->prevAuxLevel; - const int32_t vaInc = t->auxInc; - int32_t l; - int32_t r; - - do { - l = (*temp++ >> 12); - r = (*temp++ >> 12); - *out++ += (vl >> 16) * l; - *out++ += (vr >> 16) * r; - *aux++ += (va >> 17) * (l + r); - vl += vlInc; - vr += vrInc; - va += vaInc; - } while (--frameCount); - t->prevAuxLevel = va; - } else { - do { - *out++ += (vl >> 16) * (*temp++ >> 12); - *out++ += (vr >> 16) * (*temp++ >> 12); - vl += vlInc; - vr += vrInc; - } while (--frameCount); - } - t->prevVolume[0] = vl; - t->prevVolume[1] = vr; - t->adjustVolumeRamp((aux != NULL)); -} - -void AudioMixer::volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux) -{ - const int16_t vl = t->volume[0]; - const int16_t vr = t->volume[1]; - - if UNLIKELY(aux != NULL) { - const int16_t va = (int16_t)t->auxLevel; - do { - int16_t l = (int16_t)(*temp++ >> 12); - int16_t r = (int16_t)(*temp++ >> 12); - out[0] = mulAdd(l, vl, out[0]); - int16_t a = (int16_t)(((int32_t)l + r) >> 1); - out[1] = mulAdd(r, vr, out[1]); - out += 2; - aux[0] = mulAdd(a, va, aux[0]); - aux++; - } while (--frameCount); - } else { - do { - int16_t l = (int16_t)(*temp++ >> 12); - int16_t r = (int16_t)(*temp++ >> 12); - out[0] = mulAdd(l, vl, out[0]); - out[1] = mulAdd(r, vr, out[1]); - out += 2; - } while (--frameCount); - } -} - -void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux) -{ - int16_t const *in = static_cast<int16_t const *>(t->in); - - if UNLIKELY(aux != NULL) { - int32_t l; - int32_t r; - // ramp gain - if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) { - int32_t vl = t->prevVolume[0]; - int32_t vr = t->prevVolume[1]; - int32_t va = t->prevAuxLevel; - const int32_t vlInc = t->volumeInc[0]; - const int32_t vrInc = t->volumeInc[1]; - const int32_t vaInc = t->auxInc; - // LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", - // t, vlInc/65536.0f, vl/65536.0f, t->volume[0], - // (vl + vlInc*frameCount)/65536.0f, frameCount); - - do { - l = (int32_t)*in++; - r = (int32_t)*in++; - *out++ += (vl >> 16) * l; - *out++ += (vr >> 16) * r; - *aux++ += (va >> 17) * (l + r); - vl += vlInc; - vr += vrInc; - va += vaInc; - } while (--frameCount); - - t->prevVolume[0] = vl; - t->prevVolume[1] = vr; - t->prevAuxLevel = va; - t->adjustVolumeRamp(true); - } - - // constant gain - else { - const uint32_t vrl = t->volumeRL; - const int16_t va = (int16_t)t->auxLevel; - do { - uint32_t rl = *reinterpret_cast<uint32_t const *>(in); - int16_t a = (int16_t)(((int32_t)in[0] + in[1]) >> 1); - in += 2; - out[0] = mulAddRL(1, rl, vrl, out[0]); - out[1] = mulAddRL(0, rl, vrl, out[1]); - out += 2; - aux[0] = mulAdd(a, va, aux[0]); - aux++; - } while (--frameCount); - } - } else { - // ramp gain - if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) { - int32_t vl = t->prevVolume[0]; - int32_t vr = t->prevVolume[1]; - const int32_t vlInc = t->volumeInc[0]; - const int32_t vrInc = t->volumeInc[1]; - - // LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", - // t, vlInc/65536.0f, vl/65536.0f, t->volume[0], - // (vl + vlInc*frameCount)/65536.0f, frameCount); - - do { - *out++ += (vl >> 16) * (int32_t) *in++; - *out++ += (vr >> 16) * (int32_t) *in++; - vl += vlInc; - vr += vrInc; - } while (--frameCount); - - t->prevVolume[0] = vl; - t->prevVolume[1] = vr; - t->adjustVolumeRamp(false); - } - - // constant gain - else { - const uint32_t vrl = t->volumeRL; - do { - uint32_t rl = *reinterpret_cast<uint32_t const *>(in); - in += 2; - out[0] = mulAddRL(1, rl, vrl, out[0]); - out[1] = mulAddRL(0, rl, vrl, out[1]); - out += 2; - } while (--frameCount); - } - } - t->in = in; -} - -void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux) -{ - int16_t const *in = static_cast<int16_t const *>(t->in); - - if UNLIKELY(aux != NULL) { - // ramp gain - if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) { - int32_t vl = t->prevVolume[0]; - int32_t vr = t->prevVolume[1]; - int32_t va = t->prevAuxLevel; - const int32_t vlInc = t->volumeInc[0]; - const int32_t vrInc = t->volumeInc[1]; - const int32_t vaInc = t->auxInc; - - // LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", - // t, vlInc/65536.0f, vl/65536.0f, t->volume[0], - // (vl + vlInc*frameCount)/65536.0f, frameCount); - - do { - int32_t l = *in++; - *out++ += (vl >> 16) * l; - *out++ += (vr >> 16) * l; - *aux++ += (va >> 16) * l; - vl += vlInc; - vr += vrInc; - va += vaInc; - } while (--frameCount); - - t->prevVolume[0] = vl; - t->prevVolume[1] = vr; - t->prevAuxLevel = va; - t->adjustVolumeRamp(true); - } - // constant gain - else { - const int16_t vl = t->volume[0]; - const int16_t vr = t->volume[1]; - const int16_t va = (int16_t)t->auxLevel; - do { - int16_t l = *in++; - out[0] = mulAdd(l, vl, out[0]); - out[1] = mulAdd(l, vr, out[1]); - out += 2; - aux[0] = mulAdd(l, va, aux[0]); - aux++; - } while (--frameCount); - } - } else { - // ramp gain - if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) { - int32_t vl = t->prevVolume[0]; - int32_t vr = t->prevVolume[1]; - const int32_t vlInc = t->volumeInc[0]; - const int32_t vrInc = t->volumeInc[1]; - - // LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", - // t, vlInc/65536.0f, vl/65536.0f, t->volume[0], - // (vl + vlInc*frameCount)/65536.0f, frameCount); - - do { - int32_t l = *in++; - *out++ += (vl >> 16) * l; - *out++ += (vr >> 16) * l; - vl += vlInc; - vr += vrInc; - } while (--frameCount); - - t->prevVolume[0] = vl; - t->prevVolume[1] = vr; - t->adjustVolumeRamp(false); - } - // constant gain - else { - const int16_t vl = t->volume[0]; - const int16_t vr = t->volume[1]; - do { - int16_t l = *in++; - out[0] = mulAdd(l, vl, out[0]); - out[1] = mulAdd(l, vr, out[1]); - out += 2; - } while (--frameCount); - } - } - t->in = in; -} - -void AudioMixer::ditherAndClamp(int32_t* out, int32_t const *sums, size_t c) -{ - for (size_t i=0 ; i<c ; i++) { - int32_t l = *sums++; - int32_t r = *sums++; - int32_t nl = l >> 12; - int32_t nr = r >> 12; - l = clamp16(nl); - r = clamp16(nr); - *out++ = (r<<16) | (l & 0xFFFF); - } -} - -// no-op case -void AudioMixer::process__nop(state_t* state) -{ - uint32_t e0 = state->enabledTracks; - size_t bufSize = state->frameCount * sizeof(int16_t) * MAX_NUM_CHANNELS; - while (e0) { - // process by group of tracks with same output buffer to - // avoid multiple memset() on same buffer - uint32_t e1 = e0, e2 = e0; - int i = 31 - __builtin_clz(e1); - track_t& t1 = state->tracks[i]; - e2 &= ~(1<<i); - while (e2) { - i = 31 - __builtin_clz(e2); - e2 &= ~(1<<i); - track_t& t2 = state->tracks[i]; - if UNLIKELY(t2.mainBuffer != t1.mainBuffer) { - e1 &= ~(1<<i); - } - } - e0 &= ~(e1); - - memset(t1.mainBuffer, 0, bufSize); - - while (e1) { - i = 31 - __builtin_clz(e1); - e1 &= ~(1<<i); - t1 = state->tracks[i]; - size_t outFrames = state->frameCount; - while (outFrames) { - t1.buffer.frameCount = outFrames; - t1.bufferProvider->getNextBuffer(&t1.buffer); - if (!t1.buffer.raw) break; - outFrames -= t1.buffer.frameCount; - t1.bufferProvider->releaseBuffer(&t1.buffer); - } - } - } -} - -// generic code without resampling -void AudioMixer::process__genericNoResampling(state_t* state) -{ - int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32))); - - // acquire each track's buffer - uint32_t enabledTracks = state->enabledTracks; - uint32_t e0 = enabledTracks; - while (e0) { - const int i = 31 - __builtin_clz(e0); - e0 &= ~(1<<i); - track_t& t = state->tracks[i]; - t.buffer.frameCount = state->frameCount; - t.bufferProvider->getNextBuffer(&t.buffer); - t.frameCount = t.buffer.frameCount; - t.in = t.buffer.raw; - // t.in == NULL can happen if the track was flushed just after having - // been enabled for mixing. - if (t.in == NULL) - enabledTracks &= ~(1<<i); - } - - e0 = enabledTracks; - while (e0) { - // process by group of tracks with same output buffer to - // optimize cache use - uint32_t e1 = e0, e2 = e0; - int j = 31 - __builtin_clz(e1); - track_t& t1 = state->tracks[j]; - e2 &= ~(1<<j); - while (e2) { - j = 31 - __builtin_clz(e2); - e2 &= ~(1<<j); - track_t& t2 = state->tracks[j]; - if UNLIKELY(t2.mainBuffer != t1.mainBuffer) { - e1 &= ~(1<<j); - } - } - e0 &= ~(e1); - // this assumes output 16 bits stereo, no resampling - int32_t *out = t1.mainBuffer; - size_t numFrames = 0; - do { - memset(outTemp, 0, sizeof(outTemp)); - e2 = e1; - while (e2) { - const int i = 31 - __builtin_clz(e2); - e2 &= ~(1<<i); - track_t& t = state->tracks[i]; - size_t outFrames = BLOCKSIZE; - int32_t *aux = NULL; - if UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) { - aux = t.auxBuffer + numFrames; - } - while (outFrames) { - size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount; - if (inFrames) { - (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp, aux); - t.frameCount -= inFrames; - outFrames -= inFrames; - if UNLIKELY(aux != NULL) { - aux += inFrames; - } - } - if (t.frameCount == 0 && outFrames) { - t.bufferProvider->releaseBuffer(&t.buffer); - t.buffer.frameCount = (state->frameCount - numFrames) - (BLOCKSIZE - outFrames); - t.bufferProvider->getNextBuffer(&t.buffer); - t.in = t.buffer.raw; - if (t.in == NULL) { - enabledTracks &= ~(1<<i); - e1 &= ~(1<<i); - break; - } - t.frameCount = t.buffer.frameCount; - } - } - } - ditherAndClamp(out, outTemp, BLOCKSIZE); - out += BLOCKSIZE; - numFrames += BLOCKSIZE; - } while (numFrames < state->frameCount); - } - - // release each track's buffer - e0 = enabledTracks; - while (e0) { - const int i = 31 - __builtin_clz(e0); - e0 &= ~(1<<i); - track_t& t = state->tracks[i]; - t.bufferProvider->releaseBuffer(&t.buffer); - } -} - - - // generic code with resampling -void AudioMixer::process__genericResampling(state_t* state) -{ - int32_t* const outTemp = state->outputTemp; - const size_t size = sizeof(int32_t) * MAX_NUM_CHANNELS * state->frameCount; - memset(outTemp, 0, size); - - size_t numFrames = state->frameCount; - - uint32_t e0 = state->enabledTracks; - while (e0) { - // process by group of tracks with same output buffer - // to optimize cache use - uint32_t e1 = e0, e2 = e0; - int j = 31 - __builtin_clz(e1); - track_t& t1 = state->tracks[j]; - e2 &= ~(1<<j); - while (e2) { - j = 31 - __builtin_clz(e2); - e2 &= ~(1<<j); - track_t& t2 = state->tracks[j]; - if UNLIKELY(t2.mainBuffer != t1.mainBuffer) { - e1 &= ~(1<<j); - } - } - e0 &= ~(e1); - int32_t *out = t1.mainBuffer; - while (e1) { - const int i = 31 - __builtin_clz(e1); - e1 &= ~(1<<i); - track_t& t = state->tracks[i]; - int32_t *aux = NULL; - if UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) { - aux = t.auxBuffer; - } - - // this is a little goofy, on the resampling case we don't - // acquire/release the buffers because it's done by - // the resampler. - if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) { - (t.hook)(&t, outTemp, numFrames, state->resampleTemp, aux); - } else { - - size_t outFrames = 0; - - while (outFrames < numFrames) { - t.buffer.frameCount = numFrames - outFrames; - t.bufferProvider->getNextBuffer(&t.buffer); - t.in = t.buffer.raw; - // t.in == NULL can happen if the track was flushed just after having - // been enabled for mixing. - if (t.in == NULL) break; - - if UNLIKELY(aux != NULL) { - aux += outFrames; - } - (t.hook)(&t, outTemp + outFrames*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp, aux); - outFrames += t.buffer.frameCount; - t.bufferProvider->releaseBuffer(&t.buffer); - } - } - } - ditherAndClamp(out, outTemp, numFrames); - } -} - -// one track, 16 bits stereo without resampling is the most common case -void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state) -{ - const int i = 31 - __builtin_clz(state->enabledTracks); - const track_t& t = state->tracks[i]; - - AudioBufferProvider::Buffer& b(t.buffer); - - int32_t* out = t.mainBuffer; - size_t numFrames = state->frameCount; - - const int16_t vl = t.volume[0]; - const int16_t vr = t.volume[1]; - const uint32_t vrl = t.volumeRL; - while (numFrames) { - b.frameCount = numFrames; - t.bufferProvider->getNextBuffer(&b); - int16_t const *in = b.i16; - - // in == NULL can happen if the track was flushed just after having - // been enabled for mixing. - if (in == NULL || ((unsigned long)in & 3)) { - memset(out, 0, numFrames*MAX_NUM_CHANNELS*sizeof(int16_t)); - LOGE_IF(((unsigned long)in & 3), "process stereo track: input buffer alignment pb: buffer %p track %d, channels %d, needs %08x", - in, i, t.channelCount, t.needs); - return; - } - size_t outFrames = b.frameCount; - - if (UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) { - // volume is boosted, so we might need to clamp even though - // we process only one track. - do { - uint32_t rl = *reinterpret_cast<uint32_t const *>(in); - in += 2; - int32_t l = mulRL(1, rl, vrl) >> 12; - int32_t r = mulRL(0, rl, vrl) >> 12; - // clamping... - l = clamp16(l); - r = clamp16(r); - *out++ = (r<<16) | (l & 0xFFFF); - } while (--outFrames); - } else { - do { - uint32_t rl = *reinterpret_cast<uint32_t const *>(in); - in += 2; - int32_t l = mulRL(1, rl, vrl) >> 12; - int32_t r = mulRL(0, rl, vrl) >> 12; - *out++ = (r<<16) | (l & 0xFFFF); - } while (--outFrames); - } - numFrames -= b.frameCount; - t.bufferProvider->releaseBuffer(&b); - } -} - -// 2 tracks is also a common case -// NEVER used in current implementation of process__validate() -// only use if the 2 tracks have the same output buffer -void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state) -{ - int i; - uint32_t en = state->enabledTracks; - - i = 31 - __builtin_clz(en); - const track_t& t0 = state->tracks[i]; - AudioBufferProvider::Buffer& b0(t0.buffer); - - en &= ~(1<<i); - i = 31 - __builtin_clz(en); - const track_t& t1 = state->tracks[i]; - AudioBufferProvider::Buffer& b1(t1.buffer); - - int16_t const *in0; - const int16_t vl0 = t0.volume[0]; - const int16_t vr0 = t0.volume[1]; - size_t frameCount0 = 0; - - int16_t const *in1; - const int16_t vl1 = t1.volume[0]; - const int16_t vr1 = t1.volume[1]; - size_t frameCount1 = 0; - - //FIXME: only works if two tracks use same buffer - int32_t* out = t0.mainBuffer; - size_t numFrames = state->frameCount; - int16_t const *buff = NULL; - - - while (numFrames) { - - if (frameCount0 == 0) { - b0.frameCount = numFrames; - t0.bufferProvider->getNextBuffer(&b0); - if (b0.i16 == NULL) { - if (buff == NULL) { - buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount]; - } - in0 = buff; - b0.frameCount = numFrames; - } else { - in0 = b0.i16; - } - frameCount0 = b0.frameCount; - } - if (frameCount1 == 0) { - b1.frameCount = numFrames; - t1.bufferProvider->getNextBuffer(&b1); - if (b1.i16 == NULL) { - if (buff == NULL) { - buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount]; - } - in1 = buff; - b1.frameCount = numFrames; - } else { - in1 = b1.i16; - } - frameCount1 = b1.frameCount; - } - - size_t outFrames = frameCount0 < frameCount1?frameCount0:frameCount1; - - numFrames -= outFrames; - frameCount0 -= outFrames; - frameCount1 -= outFrames; - - do { - int32_t l0 = *in0++; - int32_t r0 = *in0++; - l0 = mul(l0, vl0); - r0 = mul(r0, vr0); - int32_t l = *in1++; - int32_t r = *in1++; - l = mulAdd(l, vl1, l0) >> 12; - r = mulAdd(r, vr1, r0) >> 12; - // clamping... - l = clamp16(l); - r = clamp16(r); - *out++ = (r<<16) | (l & 0xFFFF); - } while (--outFrames); - - if (frameCount0 == 0) { - t0.bufferProvider->releaseBuffer(&b0); - } - if (frameCount1 == 0) { - t1.bufferProvider->releaseBuffer(&b1); - } - } - - if (buff != NULL) { - delete [] buff; - } -} - -// ---------------------------------------------------------------------------- -}; // namespace android - diff --git a/libs/audioflinger/AudioMixer.h b/libs/audioflinger/AudioMixer.h deleted file mode 100644 index aee3e17..0000000 --- a/libs/audioflinger/AudioMixer.h +++ /dev/null @@ -1,207 +0,0 @@ -/* //device/include/server/AudioFlinger/AudioMixer.h -** -** Copyright 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. -*/ - -#ifndef ANDROID_AUDIO_MIXER_H -#define ANDROID_AUDIO_MIXER_H - -#include <stdint.h> -#include <sys/types.h> - -#include "AudioBufferProvider.h" -#include "AudioResampler.h" - -namespace android { - -// ---------------------------------------------------------------------------- - -#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) -#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) - -// ---------------------------------------------------------------------------- - -class AudioMixer -{ -public: - AudioMixer(size_t frameCount, uint32_t sampleRate); - - ~AudioMixer(); - - static const uint32_t MAX_NUM_TRACKS = 32; - static const uint32_t MAX_NUM_CHANNELS = 2; - - static const uint16_t UNITY_GAIN = 0x1000; - - enum { // names - - // track units (32 units) - TRACK0 = 0x1000, - - // enable/disable - MIXING = 0x2000, - - // setParameter targets - TRACK = 0x3000, - RESAMPLE = 0x3001, - RAMP_VOLUME = 0x3002, // ramp to new volume - VOLUME = 0x3003, // don't ramp - - // set Parameter names - // for target TRACK - CHANNEL_COUNT = 0x4000, - FORMAT = 0x4001, - MAIN_BUFFER = 0x4002, - AUX_BUFFER = 0x4003, - // for TARGET RESAMPLE - SAMPLE_RATE = 0x4100, - // for TARGET VOLUME (8 channels max) - VOLUME0 = 0x4200, - VOLUME1 = 0x4201, - AUXLEVEL = 0x4210, - }; - - - int getTrackName(); - void deleteTrackName(int name); - - status_t enable(int name); - status_t disable(int name); - - status_t setActiveTrack(int track); - status_t setParameter(int target, int name, void *value); - - status_t setBufferProvider(AudioBufferProvider* bufferProvider); - void process(); - - uint32_t trackNames() const { return mTrackNames; } - - static void ditherAndClamp(int32_t* out, int32_t const *sums, size_t c); - -private: - - enum { - NEEDS_CHANNEL_COUNT__MASK = 0x00000003, - NEEDS_FORMAT__MASK = 0x000000F0, - NEEDS_MUTE__MASK = 0x00000100, - NEEDS_RESAMPLE__MASK = 0x00001000, - NEEDS_AUX__MASK = 0x00010000, - }; - - enum { - NEEDS_CHANNEL_1 = 0x00000000, - NEEDS_CHANNEL_2 = 0x00000001, - - NEEDS_FORMAT_16 = 0x00000010, - - NEEDS_MUTE_DISABLED = 0x00000000, - NEEDS_MUTE_ENABLED = 0x00000100, - - NEEDS_RESAMPLE_DISABLED = 0x00000000, - NEEDS_RESAMPLE_ENABLED = 0x00001000, - - NEEDS_AUX_DISABLED = 0x00000000, - NEEDS_AUX_ENABLED = 0x00010000, - }; - - static inline int32_t applyVolume(int32_t in, int32_t v) { - return in * v; - } - - - struct state_t; - struct track_t; - - typedef void (*mix_t)(state_t* state); - typedef void (*hook_t)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp, int32_t* aux); - static const int BLOCKSIZE = 16; // 4 cache lines - - struct track_t { - uint32_t needs; - - union { - int16_t volume[2]; // [0]3.12 fixed point - int32_t volumeRL; - }; - - int32_t prevVolume[2]; - - int32_t volumeInc[2]; - int32_t auxLevel; - int32_t auxInc; - int32_t prevAuxLevel; - - uint16_t frameCount; - - uint8_t channelCount : 4; - uint8_t enabled : 1; - uint8_t reserved0 : 3; - uint8_t format; - - AudioBufferProvider* bufferProvider; - mutable AudioBufferProvider::Buffer buffer; - - hook_t hook; - void const* in; // current location in buffer - - AudioResampler* resampler; - uint32_t sampleRate; - int32_t* mainBuffer; - int32_t* auxBuffer; - - bool setResampler(uint32_t sampleRate, uint32_t devSampleRate); - bool doesResample() const; - void adjustVolumeRamp(bool aux); - }; - - // pad to 32-bytes to fill cache line - struct state_t { - uint32_t enabledTracks; - uint32_t needsChanged; - size_t frameCount; - mix_t hook; - int32_t *outputTemp; - int32_t *resampleTemp; - int32_t reserved[2]; - track_t tracks[32]; __attribute__((aligned(32))); - }; - - int mActiveTrack; - uint32_t mTrackNames; - const uint32_t mSampleRate; - - state_t mState __attribute__((aligned(32))); - - void invalidateState(uint32_t mask); - - static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux); - static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux); - static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux); - static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux); - static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux); - static void volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux); - - static void process__validate(state_t* state); - static void process__nop(state_t* state); - static void process__genericNoResampling(state_t* state); - static void process__genericResampling(state_t* state); - static void process__OneTrack16BitsStereoNoResampling(state_t* state); - static void process__TwoTracks16BitsStereoNoResampling(state_t* state); -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_AUDIO_MIXER_H diff --git a/libs/audioflinger/AudioPolicyManagerBase.cpp b/libs/audioflinger/AudioPolicyManagerBase.cpp deleted file mode 100644 index 381a958..0000000 --- a/libs/audioflinger/AudioPolicyManagerBase.cpp +++ /dev/null @@ -1,1973 +0,0 @@ -/* - * Copyright (C) 2009 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. - */ - -#define LOG_TAG "AudioPolicyManagerBase" -//#define LOG_NDEBUG 0 -#include <utils/Log.h> -#include <hardware_legacy/AudioPolicyManagerBase.h> -#include <media/mediarecorder.h> - -namespace android { - - -// ---------------------------------------------------------------------------- -// AudioPolicyInterface implementation -// ---------------------------------------------------------------------------- - - -status_t AudioPolicyManagerBase::setDeviceConnectionState(AudioSystem::audio_devices device, - AudioSystem::device_connection_state state, - const char *device_address) -{ - - LOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address); - - // connect/disconnect only 1 device at a time - if (AudioSystem::popCount(device) != 1) return BAD_VALUE; - - if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) { - LOGE("setDeviceConnectionState() invalid address: %s", device_address); - return BAD_VALUE; - } - - // handle output devices - if (AudioSystem::isOutputDevice(device)) { - -#ifndef WITH_A2DP - if (AudioSystem::isA2dpDevice(device)) { - LOGE("setDeviceConnectionState() invalid device: %x", device); - return BAD_VALUE; - } -#endif - - switch (state) - { - // handle output device connection - case AudioSystem::DEVICE_STATE_AVAILABLE: - if (mAvailableOutputDevices & device) { - LOGW("setDeviceConnectionState() device already connected: %x", device); - return INVALID_OPERATION; - } - LOGV("setDeviceConnectionState() connecting device %x", device); - - // register new device as available - mAvailableOutputDevices |= device; - -#ifdef WITH_A2DP - // handle A2DP device connection - if (AudioSystem::isA2dpDevice(device)) { - status_t status = handleA2dpConnection(device, device_address); - if (status != NO_ERROR) { - mAvailableOutputDevices &= ~device; - return status; - } - } else -#endif - { - if (AudioSystem::isBluetoothScoDevice(device)) { - LOGV("setDeviceConnectionState() BT SCO device, address %s", device_address); - // keep track of SCO device address - mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN); -#ifdef WITH_A2DP - if (mA2dpOutput != 0 && - mPhoneState != AudioSystem::MODE_NORMAL) { - mpClientInterface->suspendOutput(mA2dpOutput); - } -#endif - } - } - break; - // handle output device disconnection - case AudioSystem::DEVICE_STATE_UNAVAILABLE: { - if (!(mAvailableOutputDevices & device)) { - LOGW("setDeviceConnectionState() device not connected: %x", device); - return INVALID_OPERATION; - } - - - LOGV("setDeviceConnectionState() disconnecting device %x", device); - // remove device from available output devices - mAvailableOutputDevices &= ~device; - -#ifdef WITH_A2DP - // handle A2DP device disconnection - if (AudioSystem::isA2dpDevice(device)) { - status_t status = handleA2dpDisconnection(device, device_address); - if (status != NO_ERROR) { - mAvailableOutputDevices |= device; - return status; - } - } else -#endif - { - if (AudioSystem::isBluetoothScoDevice(device)) { - mScoDeviceAddress = ""; -#ifdef WITH_A2DP - if (mA2dpOutput != 0 && - mPhoneState != AudioSystem::MODE_NORMAL) { - mpClientInterface->restoreOutput(mA2dpOutput); - } -#endif - } - } - } break; - - default: - LOGE("setDeviceConnectionState() invalid state: %x", state); - return BAD_VALUE; - } - - // request routing change if necessary - uint32_t newDevice = getNewDevice(mHardwareOutput, false); -#ifdef WITH_A2DP - checkOutputForAllStrategies(newDevice); - // A2DP outputs must be closed after checkOutputForAllStrategies() is executed - if (state == AudioSystem::DEVICE_STATE_UNAVAILABLE && AudioSystem::isA2dpDevice(device)) { - closeA2dpOutputs(); - } -#endif - updateDeviceForStrategy(); - setOutputDevice(mHardwareOutput, newDevice); - - if (device == AudioSystem::DEVICE_OUT_WIRED_HEADSET) { - device = AudioSystem::DEVICE_IN_WIRED_HEADSET; - } else if (device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO || - device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET || - device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT) { - device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET; - } else { - return NO_ERROR; - } - } - // handle input devices - if (AudioSystem::isInputDevice(device)) { - - switch (state) - { - // handle input device connection - case AudioSystem::DEVICE_STATE_AVAILABLE: { - if (mAvailableInputDevices & device) { - LOGW("setDeviceConnectionState() device already connected: %d", device); - return INVALID_OPERATION; - } - mAvailableInputDevices |= device; - } - break; - - // handle input device disconnection - case AudioSystem::DEVICE_STATE_UNAVAILABLE: { - if (!(mAvailableInputDevices & device)) { - LOGW("setDeviceConnectionState() device not connected: %d", device); - return INVALID_OPERATION; - } - mAvailableInputDevices &= ~device; - } break; - - default: - LOGE("setDeviceConnectionState() invalid state: %x", state); - return BAD_VALUE; - } - - audio_io_handle_t activeInput = getActiveInput(); - if (activeInput != 0) { - AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput); - uint32_t newDevice = getDeviceForInputSource(inputDesc->mInputSource); - if (newDevice != inputDesc->mDevice) { - LOGV("setDeviceConnectionState() changing device from %x to %x for input %d", - inputDesc->mDevice, newDevice, activeInput); - inputDesc->mDevice = newDevice; - AudioParameter param = AudioParameter(); - param.addInt(String8(AudioParameter::keyRouting), (int)newDevice); - mpClientInterface->setParameters(activeInput, param.toString()); - } - } - - return NO_ERROR; - } - - LOGW("setDeviceConnectionState() invalid device: %x", device); - return BAD_VALUE; -} - -AudioSystem::device_connection_state AudioPolicyManagerBase::getDeviceConnectionState(AudioSystem::audio_devices device, - const char *device_address) -{ - AudioSystem::device_connection_state state = AudioSystem::DEVICE_STATE_UNAVAILABLE; - String8 address = String8(device_address); - if (AudioSystem::isOutputDevice(device)) { - if (device & mAvailableOutputDevices) { -#ifdef WITH_A2DP - if (AudioSystem::isA2dpDevice(device) && - address != "" && mA2dpDeviceAddress != address) { - return state; - } -#endif - if (AudioSystem::isBluetoothScoDevice(device) && - address != "" && mScoDeviceAddress != address) { - return state; - } - state = AudioSystem::DEVICE_STATE_AVAILABLE; - } - } else if (AudioSystem::isInputDevice(device)) { - if (device & mAvailableInputDevices) { - state = AudioSystem::DEVICE_STATE_AVAILABLE; - } - } - - return state; -} - -void AudioPolicyManagerBase::setPhoneState(int state) -{ - LOGV("setPhoneState() state %d", state); - uint32_t newDevice = 0; - if (state < 0 || state >= AudioSystem::NUM_MODES) { - LOGW("setPhoneState() invalid state %d", state); - return; - } - - if (state == mPhoneState ) { - LOGW("setPhoneState() setting same state %d", state); - return; - } - - // if leaving call state, handle special case of active streams - // pertaining to sonification strategy see handleIncallSonification() - if (mPhoneState == AudioSystem::MODE_IN_CALL) { - LOGV("setPhoneState() in call state management: new state is %d", state); - for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { - handleIncallSonification(stream, false, true); - } - } - - // store previous phone state for management of sonification strategy below - int oldState = mPhoneState; - mPhoneState = state; - bool force = false; - - // are we entering or starting a call - if ((oldState != AudioSystem::MODE_IN_CALL) && (state == AudioSystem::MODE_IN_CALL)) { - LOGV(" Entering call in setPhoneState()"); - // force routing command to audio hardware when starting a call - // even if no device change is needed - force = true; - } else if ((oldState == AudioSystem::MODE_IN_CALL) && (state != AudioSystem::MODE_IN_CALL)) { - LOGV(" Exiting call in setPhoneState()"); - // force routing command to audio hardware when exiting a call - // even if no device change is needed - force = true; - } - - // check for device and output changes triggered by new phone state - newDevice = getNewDevice(mHardwareOutput, false); -#ifdef WITH_A2DP - checkOutputForAllStrategies(newDevice); - // suspend A2DP output if a SCO device is present. - if (mA2dpOutput != 0 && mScoDeviceAddress != "") { - if (oldState == AudioSystem::MODE_NORMAL) { - mpClientInterface->suspendOutput(mA2dpOutput); - } else if (state == AudioSystem::MODE_NORMAL) { - mpClientInterface->restoreOutput(mA2dpOutput); - } - } -#endif - updateDeviceForStrategy(); - - AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mHardwareOutput); - - // force routing command to audio hardware when ending call - // even if no device change is needed - if (oldState == AudioSystem::MODE_IN_CALL && newDevice == 0) { - newDevice = hwOutputDesc->device(); - } - - // when changing from ring tone to in call mode, mute the ringing tone - // immediately and delay the route change to avoid sending the ring tone - // tail into the earpiece or headset. - int delayMs = 0; - if (state == AudioSystem::MODE_IN_CALL && oldState == AudioSystem::MODE_RINGTONE) { - // delay the device change command by twice the output latency to have some margin - // and be sure that audio buffers not yet affected by the mute are out when - // we actually apply the route change - delayMs = hwOutputDesc->mLatency*2; - setStreamMute(AudioSystem::RING, true, mHardwareOutput); - } - - // change routing is necessary - setOutputDevice(mHardwareOutput, newDevice, force, delayMs); - - // if entering in call state, handle special case of active streams - // pertaining to sonification strategy see handleIncallSonification() - if (state == AudioSystem::MODE_IN_CALL) { - LOGV("setPhoneState() in call state management: new state is %d", state); - // unmute the ringing tone after a sufficient delay if it was muted before - // setting output device above - if (oldState == AudioSystem::MODE_RINGTONE) { - setStreamMute(AudioSystem::RING, false, mHardwareOutput, MUTE_TIME_MS); - } - for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { - handleIncallSonification(stream, true, true); - } - } - - // Flag that ringtone volume must be limited to music volume until we exit MODE_RINGTONE - if (state == AudioSystem::MODE_RINGTONE && - (hwOutputDesc->mRefCount[AudioSystem::MUSIC] || - (systemTime() - mMusicStopTime) < seconds(SONIFICATION_HEADSET_MUSIC_DELAY))) { - mLimitRingtoneVolume = true; - } else { - mLimitRingtoneVolume = false; - } -} - -void AudioPolicyManagerBase::setRingerMode(uint32_t mode, uint32_t mask) -{ - LOGV("setRingerMode() mode %x, mask %x", mode, mask); - - mRingerMode = mode; -} - -void AudioPolicyManagerBase::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) -{ - LOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mPhoneState); - - bool forceVolumeReeval = false; - switch(usage) { - case AudioSystem::FOR_COMMUNICATION: - if (config != AudioSystem::FORCE_SPEAKER && config != AudioSystem::FORCE_BT_SCO && - config != AudioSystem::FORCE_NONE) { - LOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config); - return; - } - mForceUse[usage] = config; - break; - case AudioSystem::FOR_MEDIA: - if (config != AudioSystem::FORCE_HEADPHONES && config != AudioSystem::FORCE_BT_A2DP && - config != AudioSystem::FORCE_WIRED_ACCESSORY && config != AudioSystem::FORCE_NONE) { - LOGW("setForceUse() invalid config %d for FOR_MEDIA", config); - return; - } - mForceUse[usage] = config; - break; - case AudioSystem::FOR_RECORD: - if (config != AudioSystem::FORCE_BT_SCO && config != AudioSystem::FORCE_WIRED_ACCESSORY && - config != AudioSystem::FORCE_NONE) { - LOGW("setForceUse() invalid config %d for FOR_RECORD", config); - return; - } - mForceUse[usage] = config; - break; - case AudioSystem::FOR_DOCK: - if (config != AudioSystem::FORCE_NONE && config != AudioSystem::FORCE_BT_CAR_DOCK && - config != AudioSystem::FORCE_BT_DESK_DOCK && config != AudioSystem::FORCE_WIRED_ACCESSORY) { - LOGW("setForceUse() invalid config %d for FOR_DOCK", config); - } - forceVolumeReeval = true; - mForceUse[usage] = config; - break; - default: - LOGW("setForceUse() invalid usage %d", usage); - break; - } - - // check for device and output changes triggered by new phone state - uint32_t newDevice = getNewDevice(mHardwareOutput, false); -#ifdef WITH_A2DP - checkOutputForAllStrategies(newDevice); -#endif - updateDeviceForStrategy(); - setOutputDevice(mHardwareOutput, newDevice); - if (forceVolumeReeval) { - applyStreamVolumes(mHardwareOutput, newDevice); - } -} - -AudioSystem::forced_config AudioPolicyManagerBase::getForceUse(AudioSystem::force_use usage) -{ - return mForceUse[usage]; -} - -void AudioPolicyManagerBase::setSystemProperty(const char* property, const char* value) -{ - LOGV("setSystemProperty() property %s, value %s", property, value); - if (strcmp(property, "ro.camera.sound.forced") == 0) { - if (atoi(value)) { - LOGV("ENFORCED_AUDIBLE cannot be muted"); - mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = false; - } else { - LOGV("ENFORCED_AUDIBLE can be muted"); - mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = true; - } - } -} - -audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type stream, - uint32_t samplingRate, - uint32_t format, - uint32_t channels, - AudioSystem::output_flags flags) -{ - audio_io_handle_t output = 0; - uint32_t latency = 0; - routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream); - uint32_t device = getDeviceForStrategy(strategy); - LOGV("getOutput() stream %d, samplingRate %d, format %d, channels %x, flags %x", stream, samplingRate, format, channels, flags); - -#ifdef AUDIO_POLICY_TEST - if (mCurOutput != 0) { - LOGV("getOutput() test output mCurOutput %d, samplingRate %d, format %d, channels %x, mDirectOutput %d", - mCurOutput, mTestSamplingRate, mTestFormat, mTestChannels, mDirectOutput); - - if (mTestOutputs[mCurOutput] == 0) { - LOGV("getOutput() opening test output"); - AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(); - outputDesc->mDevice = mTestDevice; - outputDesc->mSamplingRate = mTestSamplingRate; - outputDesc->mFormat = mTestFormat; - outputDesc->mChannels = mTestChannels; - outputDesc->mLatency = mTestLatencyMs; - outputDesc->mFlags = (AudioSystem::output_flags)(mDirectOutput ? AudioSystem::OUTPUT_FLAG_DIRECT : 0); - outputDesc->mRefCount[stream] = 0; - mTestOutputs[mCurOutput] = mpClientInterface->openOutput(&outputDesc->mDevice, - &outputDesc->mSamplingRate, - &outputDesc->mFormat, - &outputDesc->mChannels, - &outputDesc->mLatency, - outputDesc->mFlags); - if (mTestOutputs[mCurOutput]) { - AudioParameter outputCmd = AudioParameter(); - outputCmd.addInt(String8("set_id"),mCurOutput); - mpClientInterface->setParameters(mTestOutputs[mCurOutput],outputCmd.toString()); - addOutput(mTestOutputs[mCurOutput], outputDesc); - } - } - return mTestOutputs[mCurOutput]; - } -#endif //AUDIO_POLICY_TEST - - // open a direct output if required by specified parameters - if (needsDirectOuput(stream, samplingRate, format, channels, flags, device)) { - - LOGV("getOutput() opening direct output device %x", device); - AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(); - outputDesc->mDevice = device; - outputDesc->mSamplingRate = samplingRate; - outputDesc->mFormat = format; - outputDesc->mChannels = channels; - outputDesc->mLatency = 0; - outputDesc->mFlags = (AudioSystem::output_flags)(flags | AudioSystem::OUTPUT_FLAG_DIRECT); - outputDesc->mRefCount[stream] = 0; - output = mpClientInterface->openOutput(&outputDesc->mDevice, - &outputDesc->mSamplingRate, - &outputDesc->mFormat, - &outputDesc->mChannels, - &outputDesc->mLatency, - outputDesc->mFlags); - - // only accept an output with the requeted parameters - if (output == 0 || - (samplingRate != 0 && samplingRate != outputDesc->mSamplingRate) || - (format != 0 && format != outputDesc->mFormat) || - (channels != 0 && channels != outputDesc->mChannels)) { - LOGV("getOutput() failed opening direct output: samplingRate %d, format %d, channels %d", - samplingRate, format, channels); - if (output != 0) { - mpClientInterface->closeOutput(output); - } - delete outputDesc; - return 0; - } - addOutput(output, outputDesc); - return output; - } - - if (channels != 0 && channels != AudioSystem::CHANNEL_OUT_MONO && - channels != AudioSystem::CHANNEL_OUT_STEREO) { - return 0; - } - // open a non direct output - - // get which output is suitable for the specified stream. The actual routing change will happen - // when startOutput() will be called - uint32_t a2dpDevice = device & AudioSystem::DEVICE_OUT_ALL_A2DP; - if (AudioSystem::popCount((AudioSystem::audio_devices)device) == 2) { -#ifdef WITH_A2DP - if (a2dpUsedForSonification() && a2dpDevice != 0) { - // if playing on 2 devices among which one is A2DP, use duplicated output - LOGV("getOutput() using duplicated output"); - LOGW_IF((mA2dpOutput == 0), "getOutput() A2DP device in multiple %x selected but A2DP output not opened", device); - output = mDuplicatedOutput; - } else -#endif - { - // if playing on 2 devices among which none is A2DP, use hardware output - output = mHardwareOutput; - } - LOGV("getOutput() using output %d for 2 devices %x", output, device); - } else { -#ifdef WITH_A2DP - if (a2dpDevice != 0) { - // if playing on A2DP device, use a2dp output - LOGW_IF((mA2dpOutput == 0), "getOutput() A2DP device %x selected but A2DP output not opened", device); - output = mA2dpOutput; - } else -#endif - { - // if playing on not A2DP device, use hardware output - output = mHardwareOutput; - } - } - - - LOGW_IF((output ==0), "getOutput() could not find output for stream %d, samplingRate %d, format %d, channels %x, flags %x", - stream, samplingRate, format, channels, flags); - - return output; -} - -status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream) -{ - LOGV("startOutput() output %d, stream %d", output, stream); - ssize_t index = mOutputs.indexOfKey(output); - if (index < 0) { - LOGW("startOutput() unknow output %d", output); - return BAD_VALUE; - } - - AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); - routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream); - -#ifdef WITH_A2DP - if (mA2dpOutput != 0 && !a2dpUsedForSonification() && strategy == STRATEGY_SONIFICATION) { - setStrategyMute(STRATEGY_MEDIA, true, mA2dpOutput); - } -#endif - - // incremenent usage count for this stream on the requested output: - // NOTE that the usage count is the same for duplicated output and hardware output which is - // necassary for a correct control of hardware output routing by startOutput() and stopOutput() - outputDesc->changeRefCount(stream, 1); - - setOutputDevice(output, getNewDevice(output)); - - // handle special case for sonification while in call - if (mPhoneState == AudioSystem::MODE_IN_CALL) { - handleIncallSonification(stream, true, false); - } - - // apply volume rules for current stream and device if necessary - checkAndSetVolume(stream, mStreams[stream].mIndexCur, output, outputDesc->device()); - - return NO_ERROR; -} - -status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream) -{ - LOGV("stopOutput() output %d, stream %d", output, stream); - ssize_t index = mOutputs.indexOfKey(output); - if (index < 0) { - LOGW("stopOutput() unknow output %d", output); - return BAD_VALUE; - } - - AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); - routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream); - - // handle special case for sonification while in call - if (mPhoneState == AudioSystem::MODE_IN_CALL) { - handleIncallSonification(stream, false, false); - } - - if (outputDesc->mRefCount[stream] > 0) { - // decrement usage count of this stream on the output - outputDesc->changeRefCount(stream, -1); - // store time at which the last music track was stopped - see computeVolume() - if (stream == AudioSystem::MUSIC) { - mMusicStopTime = systemTime(); - } - - setOutputDevice(output, getNewDevice(output)); - -#ifdef WITH_A2DP - if (mA2dpOutput != 0 && !a2dpUsedForSonification() && strategy == STRATEGY_SONIFICATION) { - setStrategyMute(STRATEGY_MEDIA, false, mA2dpOutput, mOutputs.valueFor(mHardwareOutput)->mLatency*2); - } -#endif - if (output != mHardwareOutput) { - setOutputDevice(mHardwareOutput, getNewDevice(mHardwareOutput), true); - } - return NO_ERROR; - } else { - LOGW("stopOutput() refcount is already 0 for output %d", output); - return INVALID_OPERATION; - } -} - -void AudioPolicyManagerBase::releaseOutput(audio_io_handle_t output) -{ - LOGV("releaseOutput() %d", output); - ssize_t index = mOutputs.indexOfKey(output); - if (index < 0) { - LOGW("releaseOutput() releasing unknown output %d", output); - return; - } - -#ifdef AUDIO_POLICY_TEST - int testIndex = testOutputIndex(output); - if (testIndex != 0) { - AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); - if (outputDesc->refCount() == 0) { - mpClientInterface->closeOutput(output); - delete mOutputs.valueAt(index); - mOutputs.removeItem(output); - mTestOutputs[testIndex] = 0; - } - return; - } -#endif //AUDIO_POLICY_TEST - - if (mOutputs.valueAt(index)->mFlags & AudioSystem::OUTPUT_FLAG_DIRECT) { - mpClientInterface->closeOutput(output); - delete mOutputs.valueAt(index); - mOutputs.removeItem(output); - } -} - -audio_io_handle_t AudioPolicyManagerBase::getInput(int inputSource, - uint32_t samplingRate, - uint32_t format, - uint32_t channels, - AudioSystem::audio_in_acoustics acoustics) -{ - audio_io_handle_t input = 0; - uint32_t device = getDeviceForInputSource(inputSource); - - LOGV("getInput() inputSource %d, samplingRate %d, format %d, channels %x, acoustics %x", inputSource, samplingRate, format, channels, acoustics); - - if (device == 0) { - return 0; - } - - // adapt channel selection to input source - switch(inputSource) { - case AUDIO_SOURCE_VOICE_UPLINK: - channels = AudioSystem::CHANNEL_IN_VOICE_UPLINK; - break; - case AUDIO_SOURCE_VOICE_DOWNLINK: - channels = AudioSystem::CHANNEL_IN_VOICE_DNLINK; - break; - case AUDIO_SOURCE_VOICE_CALL: - channels = (AudioSystem::CHANNEL_IN_VOICE_UPLINK | AudioSystem::CHANNEL_IN_VOICE_DNLINK); - break; - default: - break; - } - - AudioInputDescriptor *inputDesc = new AudioInputDescriptor(); - - inputDesc->mInputSource = inputSource; - inputDesc->mDevice = device; - inputDesc->mSamplingRate = samplingRate; - inputDesc->mFormat = format; - inputDesc->mChannels = channels; - inputDesc->mAcoustics = acoustics; - inputDesc->mRefCount = 0; - input = mpClientInterface->openInput(&inputDesc->mDevice, - &inputDesc->mSamplingRate, - &inputDesc->mFormat, - &inputDesc->mChannels, - inputDesc->mAcoustics); - - // only accept input with the exact requested set of parameters - if (input == 0 || - (samplingRate != inputDesc->mSamplingRate) || - (format != inputDesc->mFormat) || - (channels != inputDesc->mChannels)) { - LOGV("getInput() failed opening input: samplingRate %d, format %d, channels %d", - samplingRate, format, channels); - if (input != 0) { - mpClientInterface->closeInput(input); - } - delete inputDesc; - return 0; - } - mInputs.add(input, inputDesc); - return input; -} - -status_t AudioPolicyManagerBase::startInput(audio_io_handle_t input) -{ - LOGV("startInput() input %d", input); - ssize_t index = mInputs.indexOfKey(input); - if (index < 0) { - LOGW("startInput() unknow input %d", input); - return BAD_VALUE; - } - AudioInputDescriptor *inputDesc = mInputs.valueAt(index); - -#ifdef AUDIO_POLICY_TEST - if (mTestInput == 0) -#endif //AUDIO_POLICY_TEST - { - // refuse 2 active AudioRecord clients at the same time - if (getActiveInput() != 0) { - LOGW("startInput() input %d failed: other input already started", input); - return INVALID_OPERATION; - } - } - - AudioParameter param = AudioParameter(); - param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice); - - // use Voice Recognition mode or not for this input based on input source - int vr_enabled = inputDesc->mInputSource == AUDIO_SOURCE_VOICE_RECOGNITION ? 1 : 0; - param.addInt(String8("vr_mode"), vr_enabled); - LOGV("AudioPolicyManager::startInput(%d), setting vr_mode to %d", inputDesc->mInputSource, vr_enabled); - - mpClientInterface->setParameters(input, param.toString()); - - inputDesc->mRefCount = 1; - return NO_ERROR; -} - -status_t AudioPolicyManagerBase::stopInput(audio_io_handle_t input) -{ - LOGV("stopInput() input %d", input); - ssize_t index = mInputs.indexOfKey(input); - if (index < 0) { - LOGW("stopInput() unknow input %d", input); - return BAD_VALUE; - } - AudioInputDescriptor *inputDesc = mInputs.valueAt(index); - - if (inputDesc->mRefCount == 0) { - LOGW("stopInput() input %d already stopped", input); - return INVALID_OPERATION; - } else { - AudioParameter param = AudioParameter(); - param.addInt(String8(AudioParameter::keyRouting), 0); - mpClientInterface->setParameters(input, param.toString()); - inputDesc->mRefCount = 0; - return NO_ERROR; - } -} - -void AudioPolicyManagerBase::releaseInput(audio_io_handle_t input) -{ - LOGV("releaseInput() %d", input); - ssize_t index = mInputs.indexOfKey(input); - if (index < 0) { - LOGW("releaseInput() releasing unknown input %d", input); - return; - } - mpClientInterface->closeInput(input); - delete mInputs.valueAt(index); - mInputs.removeItem(input); - LOGV("releaseInput() exit"); -} - -void AudioPolicyManagerBase::initStreamVolume(AudioSystem::stream_type stream, - int indexMin, - int indexMax) -{ - LOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax); - if (indexMin < 0 || indexMin >= indexMax) { - LOGW("initStreamVolume() invalid index limits for stream %d, min %d, max %d", stream , indexMin, indexMax); - return; - } - mStreams[stream].mIndexMin = indexMin; - mStreams[stream].mIndexMax = indexMax; -} - -status_t AudioPolicyManagerBase::setStreamVolumeIndex(AudioSystem::stream_type stream, int index) -{ - - if ((index < mStreams[stream].mIndexMin) || (index > mStreams[stream].mIndexMax)) { - return BAD_VALUE; - } - - // Force max volume if stream cannot be muted - if (!mStreams[stream].mCanBeMuted) index = mStreams[stream].mIndexMax; - - LOGV("setStreamVolumeIndex() stream %d, index %d", stream, index); - mStreams[stream].mIndexCur = index; - - // compute and apply stream volume on all outputs according to connected device - status_t status = NO_ERROR; - for (size_t i = 0; i < mOutputs.size(); i++) { - status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), mOutputs.valueAt(i)->device()); - if (volStatus != NO_ERROR) { - status = volStatus; - } - } - return status; -} - -status_t AudioPolicyManagerBase::getStreamVolumeIndex(AudioSystem::stream_type stream, int *index) -{ - if (index == 0) { - return BAD_VALUE; - } - LOGV("getStreamVolumeIndex() stream %d", stream); - *index = mStreams[stream].mIndexCur; - return NO_ERROR; -} - -status_t AudioPolicyManagerBase::dump(int fd) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - - snprintf(buffer, SIZE, "\nAudioPolicyManager Dump: %p\n", this); - result.append(buffer); - snprintf(buffer, SIZE, " Hardware Output: %d\n", mHardwareOutput); - result.append(buffer); -#ifdef WITH_A2DP - snprintf(buffer, SIZE, " A2DP Output: %d\n", mA2dpOutput); - result.append(buffer); - snprintf(buffer, SIZE, " Duplicated Output: %d\n", mDuplicatedOutput); - result.append(buffer); - snprintf(buffer, SIZE, " A2DP device address: %s\n", mA2dpDeviceAddress.string()); - result.append(buffer); -#endif - snprintf(buffer, SIZE, " SCO device address: %s\n", mScoDeviceAddress.string()); - result.append(buffer); - snprintf(buffer, SIZE, " Output devices: %08x\n", mAvailableOutputDevices); - result.append(buffer); - snprintf(buffer, SIZE, " Input devices: %08x\n", mAvailableInputDevices); - result.append(buffer); - snprintf(buffer, SIZE, " Phone state: %d\n", mPhoneState); - result.append(buffer); - snprintf(buffer, SIZE, " Ringer mode: %d\n", mRingerMode); - result.append(buffer); - snprintf(buffer, SIZE, " Force use for communications %d\n", mForceUse[AudioSystem::FOR_COMMUNICATION]); - result.append(buffer); - snprintf(buffer, SIZE, " Force use for media %d\n", mForceUse[AudioSystem::FOR_MEDIA]); - result.append(buffer); - snprintf(buffer, SIZE, " Force use for record %d\n", mForceUse[AudioSystem::FOR_RECORD]); - result.append(buffer); - snprintf(buffer, SIZE, " Force use for dock %d\n", mForceUse[AudioSystem::FOR_DOCK]); - result.append(buffer); - write(fd, result.string(), result.size()); - - snprintf(buffer, SIZE, "\nOutputs dump:\n"); - write(fd, buffer, strlen(buffer)); - for (size_t i = 0; i < mOutputs.size(); i++) { - snprintf(buffer, SIZE, "- Output %d dump:\n", mOutputs.keyAt(i)); - write(fd, buffer, strlen(buffer)); - mOutputs.valueAt(i)->dump(fd); - } - - snprintf(buffer, SIZE, "\nInputs dump:\n"); - write(fd, buffer, strlen(buffer)); - for (size_t i = 0; i < mInputs.size(); i++) { - snprintf(buffer, SIZE, "- Input %d dump:\n", mInputs.keyAt(i)); - write(fd, buffer, strlen(buffer)); - mInputs.valueAt(i)->dump(fd); - } - - snprintf(buffer, SIZE, "\nStreams dump:\n"); - write(fd, buffer, strlen(buffer)); - snprintf(buffer, SIZE, " Stream Index Min Index Max Index Cur Can be muted\n"); - write(fd, buffer, strlen(buffer)); - for (size_t i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) { - snprintf(buffer, SIZE, " %02d", i); - mStreams[i].dump(buffer + 3, SIZE); - write(fd, buffer, strlen(buffer)); - } - - return NO_ERROR; -} - -// ---------------------------------------------------------------------------- -// AudioPolicyManagerBase -// ---------------------------------------------------------------------------- - -AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface) - : -#ifdef AUDIO_POLICY_TEST - Thread(false), -#endif //AUDIO_POLICY_TEST - mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0), mMusicStopTime(0), mLimitRingtoneVolume(false) -{ - mpClientInterface = clientInterface; - - for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) { - mForceUse[i] = AudioSystem::FORCE_NONE; - } - - // devices available by default are speaker, ear piece and microphone - mAvailableOutputDevices = AudioSystem::DEVICE_OUT_EARPIECE | - AudioSystem::DEVICE_OUT_SPEAKER; - mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC; - -#ifdef WITH_A2DP - mA2dpOutput = 0; - mDuplicatedOutput = 0; - mA2dpDeviceAddress = String8(""); -#endif - mScoDeviceAddress = String8(""); - - // open hardware output - AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(); - outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER; - mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice, - &outputDesc->mSamplingRate, - &outputDesc->mFormat, - &outputDesc->mChannels, - &outputDesc->mLatency, - outputDesc->mFlags); - - if (mHardwareOutput == 0) { - LOGE("Failed to initialize hardware output stream, samplingRate: %d, format %d, channels %d", - outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels); - } else { - addOutput(mHardwareOutput, outputDesc); - setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER, true); - } - - updateDeviceForStrategy(); -#ifdef AUDIO_POLICY_TEST - AudioParameter outputCmd = AudioParameter(); - outputCmd.addInt(String8("set_id"), 0); - mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString()); - - mTestDevice = AudioSystem::DEVICE_OUT_SPEAKER; - mTestSamplingRate = 44100; - mTestFormat = AudioSystem::PCM_16_BIT; - mTestChannels = AudioSystem::CHANNEL_OUT_STEREO; - mTestLatencyMs = 0; - mCurOutput = 0; - mDirectOutput = false; - for (int i = 0; i < NUM_TEST_OUTPUTS; i++) { - mTestOutputs[i] = 0; - } - - const size_t SIZE = 256; - char buffer[SIZE]; - snprintf(buffer, SIZE, "AudioPolicyManagerTest"); - run(buffer, ANDROID_PRIORITY_AUDIO); -#endif //AUDIO_POLICY_TEST -} - -AudioPolicyManagerBase::~AudioPolicyManagerBase() -{ -#ifdef AUDIO_POLICY_TEST - exit(); -#endif //AUDIO_POLICY_TEST - for (size_t i = 0; i < mOutputs.size(); i++) { - mpClientInterface->closeOutput(mOutputs.keyAt(i)); - delete mOutputs.valueAt(i); - } - mOutputs.clear(); - for (size_t i = 0; i < mInputs.size(); i++) { - mpClientInterface->closeInput(mInputs.keyAt(i)); - delete mInputs.valueAt(i); - } - mInputs.clear(); -} - -#ifdef AUDIO_POLICY_TEST -bool AudioPolicyManagerBase::threadLoop() -{ - LOGV("entering threadLoop()"); - while (!exitPending()) - { - String8 command; - int valueInt; - String8 value; - - Mutex::Autolock _l(mLock); - mWaitWorkCV.waitRelative(mLock, milliseconds(50)); - - command = mpClientInterface->getParameters(0, String8("test_cmd_policy")); - AudioParameter param = AudioParameter(command); - - if (param.getInt(String8("test_cmd_policy"), valueInt) == NO_ERROR && - valueInt != 0) { - LOGV("Test command %s received", command.string()); - String8 target; - if (param.get(String8("target"), target) != NO_ERROR) { - target = "Manager"; - } - if (param.getInt(String8("test_cmd_policy_output"), valueInt) == NO_ERROR) { - param.remove(String8("test_cmd_policy_output")); - mCurOutput = valueInt; - } - if (param.get(String8("test_cmd_policy_direct"), value) == NO_ERROR) { - param.remove(String8("test_cmd_policy_direct")); - if (value == "false") { - mDirectOutput = false; - } else if (value == "true") { - mDirectOutput = true; - } - } - if (param.getInt(String8("test_cmd_policy_input"), valueInt) == NO_ERROR) { - param.remove(String8("test_cmd_policy_input")); - mTestInput = valueInt; - } - - if (param.get(String8("test_cmd_policy_format"), value) == NO_ERROR) { - param.remove(String8("test_cmd_policy_format")); - int format = AudioSystem::INVALID_FORMAT; - if (value == "PCM 16 bits") { - format = AudioSystem::PCM_16_BIT; - } else if (value == "PCM 8 bits") { - format = AudioSystem::PCM_8_BIT; - } else if (value == "Compressed MP3") { - format = AudioSystem::MP3; - } - if (format != AudioSystem::INVALID_FORMAT) { - if (target == "Manager") { - mTestFormat = format; - } else if (mTestOutputs[mCurOutput] != 0) { - AudioParameter outputParam = AudioParameter(); - outputParam.addInt(String8("format"), format); - mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString()); - } - } - } - if (param.get(String8("test_cmd_policy_channels"), value) == NO_ERROR) { - param.remove(String8("test_cmd_policy_channels")); - int channels = 0; - - if (value == "Channels Stereo") { - channels = AudioSystem::CHANNEL_OUT_STEREO; - } else if (value == "Channels Mono") { - channels = AudioSystem::CHANNEL_OUT_MONO; - } - if (channels != 0) { - if (target == "Manager") { - mTestChannels = channels; - } else if (mTestOutputs[mCurOutput] != 0) { - AudioParameter outputParam = AudioParameter(); - outputParam.addInt(String8("channels"), channels); - mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString()); - } - } - } - if (param.getInt(String8("test_cmd_policy_sampleRate"), valueInt) == NO_ERROR) { - param.remove(String8("test_cmd_policy_sampleRate")); - if (valueInt >= 0 && valueInt <= 96000) { - int samplingRate = valueInt; - if (target == "Manager") { - mTestSamplingRate = samplingRate; - } else if (mTestOutputs[mCurOutput] != 0) { - AudioParameter outputParam = AudioParameter(); - outputParam.addInt(String8("sampling_rate"), samplingRate); - mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString()); - } - } - } - - if (param.get(String8("test_cmd_policy_reopen"), value) == NO_ERROR) { - param.remove(String8("test_cmd_policy_reopen")); - - mpClientInterface->closeOutput(mHardwareOutput); - delete mOutputs.valueFor(mHardwareOutput); - mOutputs.removeItem(mHardwareOutput); - - AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(); - outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER; - mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice, - &outputDesc->mSamplingRate, - &outputDesc->mFormat, - &outputDesc->mChannels, - &outputDesc->mLatency, - outputDesc->mFlags); - if (mHardwareOutput == 0) { - LOGE("Failed to reopen hardware output stream, samplingRate: %d, format %d, channels %d", - outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels); - } else { - AudioParameter outputCmd = AudioParameter(); - outputCmd.addInt(String8("set_id"), 0); - mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString()); - addOutput(mHardwareOutput, outputDesc); - } - } - - - mpClientInterface->setParameters(0, String8("test_cmd_policy=")); - } - } - return false; -} - -void AudioPolicyManagerBase::exit() -{ - { - AutoMutex _l(mLock); - requestExit(); - mWaitWorkCV.signal(); - } - requestExitAndWait(); -} - -int AudioPolicyManagerBase::testOutputIndex(audio_io_handle_t output) -{ - for (int i = 0; i < NUM_TEST_OUTPUTS; i++) { - if (output == mTestOutputs[i]) return i; - } - return 0; -} -#endif //AUDIO_POLICY_TEST - -// --- - -void AudioPolicyManagerBase::addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc) -{ - outputDesc->mId = id; - mOutputs.add(id, outputDesc); -} - - -#ifdef WITH_A2DP -status_t AudioPolicyManagerBase::handleA2dpConnection(AudioSystem::audio_devices device, - const char *device_address) -{ - // when an A2DP device is connected, open an A2DP and a duplicated output - LOGV("opening A2DP output for device %s", device_address); - AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(); - outputDesc->mDevice = device; - mA2dpOutput = mpClientInterface->openOutput(&outputDesc->mDevice, - &outputDesc->mSamplingRate, - &outputDesc->mFormat, - &outputDesc->mChannels, - &outputDesc->mLatency, - outputDesc->mFlags); - if (mA2dpOutput) { - // add A2DP output descriptor - addOutput(mA2dpOutput, outputDesc); - // set initial stream volume for A2DP device - applyStreamVolumes(mA2dpOutput, device); - if (a2dpUsedForSonification()) { - mDuplicatedOutput = mpClientInterface->openDuplicateOutput(mA2dpOutput, mHardwareOutput); - } - if (mDuplicatedOutput != 0 || - !a2dpUsedForSonification()) { - // If both A2DP and duplicated outputs are open, send device address to A2DP hardware - // interface - AudioParameter param; - param.add(String8("a2dp_sink_address"), String8(device_address)); - mpClientInterface->setParameters(mA2dpOutput, param.toString()); - mA2dpDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN); - - if (a2dpUsedForSonification()) { - // add duplicated output descriptor - AudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor(); - dupOutputDesc->mOutput1 = mOutputs.valueFor(mHardwareOutput); - dupOutputDesc->mOutput2 = mOutputs.valueFor(mA2dpOutput); - dupOutputDesc->mSamplingRate = outputDesc->mSamplingRate; - dupOutputDesc->mFormat = outputDesc->mFormat; - dupOutputDesc->mChannels = outputDesc->mChannels; - dupOutputDesc->mLatency = outputDesc->mLatency; - addOutput(mDuplicatedOutput, dupOutputDesc); - applyStreamVolumes(mDuplicatedOutput, device); - } - } else { - LOGW("getOutput() could not open duplicated output for %d and %d", - mHardwareOutput, mA2dpOutput); - mpClientInterface->closeOutput(mA2dpOutput); - mOutputs.removeItem(mA2dpOutput); - mA2dpOutput = 0; - delete outputDesc; - return NO_INIT; - } - } else { - LOGW("setDeviceConnectionState() could not open A2DP output for device %x", device); - delete outputDesc; - return NO_INIT; - } - AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mHardwareOutput); - - if (mScoDeviceAddress != "") { - // It is normal to suspend twice if we are both in call, - // and have the hardware audio output routed to BT SCO - if (mPhoneState != AudioSystem::MODE_NORMAL) { - mpClientInterface->suspendOutput(mA2dpOutput); - } - if (AudioSystem::isBluetoothScoDevice((AudioSystem::audio_devices)hwOutputDesc->device())) { - mpClientInterface->suspendOutput(mA2dpOutput); - } - } - - if (!a2dpUsedForSonification()) { - // mute music on A2DP output if a notification or ringtone is playing - uint32_t refCount = hwOutputDesc->strategyRefCount(STRATEGY_SONIFICATION); - for (uint32_t i = 0; i < refCount; i++) { - setStrategyMute(STRATEGY_MEDIA, true, mA2dpOutput); - } - } - return NO_ERROR; -} - -status_t AudioPolicyManagerBase::handleA2dpDisconnection(AudioSystem::audio_devices device, - const char *device_address) -{ - if (mA2dpOutput == 0) { - LOGW("setDeviceConnectionState() disconnecting A2DP and no A2DP output!"); - return INVALID_OPERATION; - } - - if (mA2dpDeviceAddress != device_address) { - LOGW("setDeviceConnectionState() disconnecting unknow A2DP sink address %s", device_address); - return INVALID_OPERATION; - } - - // mute media strategy to avoid outputting sound on hardware output while music stream - // is switched from A2DP output and before music is paused by music application - setStrategyMute(STRATEGY_MEDIA, true, mHardwareOutput); - setStrategyMute(STRATEGY_MEDIA, false, mHardwareOutput, MUTE_TIME_MS); - - if (!a2dpUsedForSonification()) { - // unmute music on A2DP output if a notification or ringtone is playing - uint32_t refCount = mOutputs.valueFor(mHardwareOutput)->strategyRefCount(STRATEGY_SONIFICATION); - for (uint32_t i = 0; i < refCount; i++) { - setStrategyMute(STRATEGY_MEDIA, false, mA2dpOutput); - } - } - mA2dpDeviceAddress = ""; - return NO_ERROR; -} - -void AudioPolicyManagerBase::closeA2dpOutputs() -{ - LOGV("setDeviceConnectionState() closing A2DP and duplicated output!"); - - if (mDuplicatedOutput != 0) { - AudioOutputDescriptor *dupOutputDesc = mOutputs.valueFor(mDuplicatedOutput); - AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mHardwareOutput); - // As all active tracks on duplicated output will be deleted, - // and as they were also referenced on hardware output, the reference - // count for their stream type must be adjusted accordingly on - // hardware output. - for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { - int refCount = dupOutputDesc->mRefCount[i]; - hwOutputDesc->changeRefCount((AudioSystem::stream_type)i,-refCount); - } - - mpClientInterface->closeOutput(mDuplicatedOutput); - delete mOutputs.valueFor(mDuplicatedOutput); - mOutputs.removeItem(mDuplicatedOutput); - mDuplicatedOutput = 0; - } - if (mA2dpOutput != 0) { - AudioParameter param; - param.add(String8("closing"), String8("true")); - mpClientInterface->setParameters(mA2dpOutput, param.toString()); - mpClientInterface->closeOutput(mA2dpOutput); - delete mOutputs.valueFor(mA2dpOutput); - mOutputs.removeItem(mA2dpOutput); - mA2dpOutput = 0; - } -} - -void AudioPolicyManagerBase::checkOutputForStrategy(routing_strategy strategy, uint32_t &newDevice) -{ - uint32_t prevDevice = getDeviceForStrategy(strategy); - uint32_t curDevice = getDeviceForStrategy(strategy, false); - bool a2dpWasUsed = AudioSystem::isA2dpDevice((AudioSystem::audio_devices)(prevDevice & ~AudioSystem::DEVICE_OUT_SPEAKER)); - bool a2dpIsUsed = AudioSystem::isA2dpDevice((AudioSystem::audio_devices)(curDevice & ~AudioSystem::DEVICE_OUT_SPEAKER)); - AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mHardwareOutput); - AudioOutputDescriptor *a2dpOutputDesc; - - if (a2dpWasUsed && !a2dpIsUsed) { - bool dupUsed = a2dpUsedForSonification() && a2dpWasUsed && (AudioSystem::popCount(prevDevice) == 2); - - if (dupUsed) { - LOGV("checkOutputForStrategy() moving strategy %d to duplicated", strategy); - a2dpOutputDesc = mOutputs.valueFor(mDuplicatedOutput); - } else { - LOGV("checkOutputForStrategy() moving strategy %d to a2dp", strategy); - a2dpOutputDesc = mOutputs.valueFor(mA2dpOutput); - } - - for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { - if (getStrategy((AudioSystem::stream_type)i) == strategy) { - mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, mHardwareOutput); - } - } - // do not change newDevice if it was already set before this call by a previous call to - // getNewDevice() or checkOutputForStrategy() for a strategy with higher priority - if (newDevice == 0 && hwOutputDesc->isUsedByStrategy(strategy)) { - newDevice = getDeviceForStrategy(strategy, false); - } - } - if (a2dpIsUsed && !a2dpWasUsed) { - bool dupUsed = a2dpUsedForSonification() && a2dpIsUsed && (AudioSystem::popCount(curDevice) == 2); - audio_io_handle_t a2dpOutput; - - if (dupUsed) { - LOGV("checkOutputForStrategy() moving strategy %d from duplicated", strategy); - a2dpOutputDesc = mOutputs.valueFor(mDuplicatedOutput); - a2dpOutput = mDuplicatedOutput; - } else { - LOGV("checkOutputForStrategy() moving strategy %d from a2dp", strategy); - a2dpOutputDesc = mOutputs.valueFor(mA2dpOutput); - a2dpOutput = mA2dpOutput; - } - - for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { - if (getStrategy((AudioSystem::stream_type)i) == strategy) { - mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, a2dpOutput); - } - } - } -} - -void AudioPolicyManagerBase::checkOutputForAllStrategies(uint32_t &newDevice) -{ - // Check strategies in order of priority so that once newDevice is set - // for a given strategy it is not modified by subsequent calls to - // checkOutputForStrategy() - checkOutputForStrategy(STRATEGY_PHONE, newDevice); - checkOutputForStrategy(STRATEGY_SONIFICATION, newDevice); - checkOutputForStrategy(STRATEGY_MEDIA, newDevice); - checkOutputForStrategy(STRATEGY_DTMF, newDevice); -} - -#endif - -uint32_t AudioPolicyManagerBase::getNewDevice(audio_io_handle_t output, bool fromCache) -{ - uint32_t device = 0; - - AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); - // check the following by order of priority to request a routing change if necessary: - // 1: we are in call or the strategy phone is active on the hardware output: - // use device for strategy phone - // 2: the strategy sonification is active on the hardware output: - // use device for strategy sonification - // 3: the strategy media is active on the hardware output: - // use device for strategy media - // 4: the strategy DTMF is active on the hardware output: - // use device for strategy DTMF - if (mPhoneState == AudioSystem::MODE_IN_CALL || - outputDesc->isUsedByStrategy(STRATEGY_PHONE)) { - device = getDeviceForStrategy(STRATEGY_PHONE, fromCache); - } else if (outputDesc->isUsedByStrategy(STRATEGY_SONIFICATION)) { - device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache); - } else if (outputDesc->isUsedByStrategy(STRATEGY_MEDIA)) { - device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache); - } else if (outputDesc->isUsedByStrategy(STRATEGY_DTMF)) { - device = getDeviceForStrategy(STRATEGY_DTMF, fromCache); - } - - LOGV("getNewDevice() selected device %x", device); - return device; -} - -AudioPolicyManagerBase::routing_strategy AudioPolicyManagerBase::getStrategy(AudioSystem::stream_type stream) -{ - // stream to strategy mapping - switch (stream) { - case AudioSystem::VOICE_CALL: - case AudioSystem::BLUETOOTH_SCO: - return STRATEGY_PHONE; - case AudioSystem::RING: - case AudioSystem::NOTIFICATION: - case AudioSystem::ALARM: - case AudioSystem::ENFORCED_AUDIBLE: - return STRATEGY_SONIFICATION; - case AudioSystem::DTMF: - return STRATEGY_DTMF; - default: - LOGE("unknown stream type"); - case AudioSystem::SYSTEM: - // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs - // while key clicks are played produces a poor result - case AudioSystem::TTS: - case AudioSystem::MUSIC: - return STRATEGY_MEDIA; - } -} - -uint32_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy, bool fromCache) -{ - uint32_t device = 0; - - if (fromCache) { - LOGV("getDeviceForStrategy() from cache strategy %d, device %x", strategy, mDeviceForStrategy[strategy]); - return mDeviceForStrategy[strategy]; - } - - switch (strategy) { - case STRATEGY_DTMF: - if (mPhoneState != AudioSystem::MODE_IN_CALL) { - // when off call, DTMF strategy follows the same rules as MEDIA strategy - device = getDeviceForStrategy(STRATEGY_MEDIA, false); - break; - } - // when in call, DTMF and PHONE strategies follow the same rules - // FALL THROUGH - - case STRATEGY_PHONE: - // for phone strategy, we first consider the forced use and then the available devices by order - // of priority - switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) { - case AudioSystem::FORCE_BT_SCO: - if (mPhoneState != AudioSystem::MODE_IN_CALL || strategy != STRATEGY_DTMF) { - device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT; - if (device) break; - } - device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET; - if (device) break; - device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO; - if (device) break; - // if SCO device is requested but no SCO device is available, fall back to default case - // FALL THROUGH - - default: // FORCE_NONE - device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE; - if (device) break; - device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET; - if (device) break; -#ifdef WITH_A2DP - // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP - if (mPhoneState != AudioSystem::MODE_IN_CALL) { - device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP; - if (device) break; - device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; - if (device) break; - } -#endif - device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_EARPIECE; - if (device == 0) { - LOGE("getDeviceForStrategy() earpiece device not found"); - } - break; - - case AudioSystem::FORCE_SPEAKER: - if (mPhoneState != AudioSystem::MODE_IN_CALL || strategy != STRATEGY_DTMF) { - device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT; - if (device) break; - } -#ifdef WITH_A2DP - // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to - // A2DP speaker when forcing to speaker output - if (mPhoneState != AudioSystem::MODE_IN_CALL) { - device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; - if (device) break; - } -#endif - device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER; - if (device == 0) { - LOGE("getDeviceForStrategy() speaker device not found"); - } - break; - } - break; - - case STRATEGY_SONIFICATION: - - // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by - // handleIncallSonification(). - if (mPhoneState == AudioSystem::MODE_IN_CALL) { - device = getDeviceForStrategy(STRATEGY_PHONE, false); - break; - } - device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER; - if (device == 0) { - LOGE("getDeviceForStrategy() speaker device not found"); - } - // The second device used for sonification is the same as the device used by media strategy - // FALL THROUGH - - case STRATEGY_MEDIA: { - uint32_t device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL; - if (device2 == 0) { - device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE; - } - if (device2 == 0) { - device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET; - } -#ifdef WITH_A2DP - if (mA2dpOutput != 0) { - if (strategy == STRATEGY_SONIFICATION && !a2dpUsedForSonification()) { - break; - } - if (device2 == 0) { - device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP; - } - if (device2 == 0) { - device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; - } - if (device2 == 0) { - device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; - } - } -#endif - if (device2 == 0) { - device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER; - } - - // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION, 0 otherwise - device |= device2; - if (device == 0) { - LOGE("getDeviceForStrategy() speaker device not found"); - } - } break; - - default: - LOGW("getDeviceForStrategy() unknown strategy: %d", strategy); - break; - } - - LOGV("getDeviceForStrategy() strategy %d, device %x", strategy, device); - return device; -} - -void AudioPolicyManagerBase::updateDeviceForStrategy() -{ - for (int i = 0; i < NUM_STRATEGIES; i++) { - mDeviceForStrategy[i] = getDeviceForStrategy((routing_strategy)i, false); - } -} - -void AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, uint32_t device, bool force, int delayMs) -{ - LOGV("setOutputDevice() output %d device %x delayMs %d", output, device, delayMs); - AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); - - - if (outputDesc->isDuplicated()) { - setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs); - setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs); - return; - } -#ifdef WITH_A2DP - // filter devices according to output selected - if (output == mA2dpOutput) { - device &= AudioSystem::DEVICE_OUT_ALL_A2DP; - } else { - device &= ~AudioSystem::DEVICE_OUT_ALL_A2DP; - } -#endif - - uint32_t prevDevice = (uint32_t)outputDesc->device(); - // Do not change the routing if: - // - the requestede device is 0 - // - the requested device is the same as current device and force is not specified. - // Doing this check here allows the caller to call setOutputDevice() without conditions - if ((device == 0 || device == prevDevice) && !force) { - LOGV("setOutputDevice() setting same device %x or null device for output %d", device, output); - return; - } - - outputDesc->mDevice = device; - // mute media streams if both speaker and headset are selected - if (output == mHardwareOutput && AudioSystem::popCount(device) == 2) { - setStrategyMute(STRATEGY_MEDIA, true, output); - // wait for the PCM output buffers to empty before proceeding with the rest of the command - usleep(outputDesc->mLatency*2*1000); - } -#ifdef WITH_A2DP - // suspend A2DP output if SCO device is selected - if (AudioSystem::isBluetoothScoDevice((AudioSystem::audio_devices)device)) { - if (mA2dpOutput != 0) { - mpClientInterface->suspendOutput(mA2dpOutput); - } - } -#endif - // do the routing - AudioParameter param = AudioParameter(); - param.addInt(String8(AudioParameter::keyRouting), (int)device); - mpClientInterface->setParameters(mHardwareOutput, param.toString(), delayMs); - // update stream volumes according to new device - applyStreamVolumes(output, device, delayMs); - -#ifdef WITH_A2DP - // if disconnecting SCO device, restore A2DP output - if (AudioSystem::isBluetoothScoDevice((AudioSystem::audio_devices)prevDevice)) { - if (mA2dpOutput != 0) { - LOGV("restore A2DP output"); - mpClientInterface->restoreOutput(mA2dpOutput); - } - } -#endif - // if changing from a combined headset + speaker route, unmute media streams - if (output == mHardwareOutput && AudioSystem::popCount(prevDevice) == 2) { - setStrategyMute(STRATEGY_MEDIA, false, output, delayMs); - } -} - -uint32_t AudioPolicyManagerBase::getDeviceForInputSource(int inputSource) -{ - uint32_t device; - - switch(inputSource) { - case AUDIO_SOURCE_DEFAULT: - case AUDIO_SOURCE_MIC: - case AUDIO_SOURCE_VOICE_RECOGNITION: - if (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO && - mAvailableInputDevices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET) { - device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET; - } else if (mAvailableInputDevices & AudioSystem::DEVICE_IN_WIRED_HEADSET) { - device = AudioSystem::DEVICE_IN_WIRED_HEADSET; - } else { - device = AudioSystem::DEVICE_IN_BUILTIN_MIC; - } - break; - case AUDIO_SOURCE_CAMCORDER: - if (hasBackMicrophone()) { - device = AudioSystem::DEVICE_IN_BACK_MIC; - } else { - device = AudioSystem::DEVICE_IN_BUILTIN_MIC; - } - break; - case AUDIO_SOURCE_VOICE_UPLINK: - case AUDIO_SOURCE_VOICE_DOWNLINK: - case AUDIO_SOURCE_VOICE_CALL: - device = AudioSystem::DEVICE_IN_VOICE_CALL; - break; - default: - LOGW("getInput() invalid input source %d", inputSource); - device = 0; - break; - } - LOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device); - return device; -} - -audio_io_handle_t AudioPolicyManagerBase::getActiveInput() -{ - for (size_t i = 0; i < mInputs.size(); i++) { - if (mInputs.valueAt(i)->mRefCount > 0) { - return mInputs.keyAt(i); - } - } - return 0; -} - -float AudioPolicyManagerBase::computeVolume(int stream, int index, audio_io_handle_t output, uint32_t device) -{ - float volume = 1.0; - AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); - StreamDescriptor &streamDesc = mStreams[stream]; - - if (device == 0) { - device = outputDesc->device(); - } - - int volInt = (100 * (index - streamDesc.mIndexMin)) / (streamDesc.mIndexMax - streamDesc.mIndexMin); - volume = AudioSystem::linearToLog(volInt); - - // if a headset is connected, apply the following rules to ring tones and notifications - // to avoid sound level bursts in user's ears: - // - always attenuate ring tones and notifications volume by 6dB - // - if music is playing, always limit the volume to current music volume, - // with a minimum threshold at -36dB so that notification is always perceived. - if ((device & - (AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP | - AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - AudioSystem::DEVICE_OUT_WIRED_HEADSET | - AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) && - (getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) && - streamDesc.mCanBeMuted) { - volume *= SONIFICATION_HEADSET_VOLUME_FACTOR; - // when the phone is ringing we must consider that music could have been paused just before - // by the music application and behave as if music was active if the last music track was - // just stopped - if (outputDesc->mRefCount[AudioSystem::MUSIC] || mLimitRingtoneVolume) { - float musicVol = computeVolume(AudioSystem::MUSIC, mStreams[AudioSystem::MUSIC].mIndexCur, output, device); - float minVol = (musicVol > SONIFICATION_HEADSET_VOLUME_MIN) ? musicVol : SONIFICATION_HEADSET_VOLUME_MIN; - if (volume > minVol) { - volume = minVol; - LOGV("computeVolume limiting volume to %f musicVol %f", minVol, musicVol); - } - } - } - - return volume; -} - -status_t AudioPolicyManagerBase::checkAndSetVolume(int stream, int index, audio_io_handle_t output, uint32_t device, int delayMs, bool force) -{ - - // do not change actual stream volume if the stream is muted - if (mOutputs.valueFor(output)->mMuteCount[stream] != 0) { - LOGV("checkAndSetVolume() stream %d muted count %d", stream, mOutputs.valueFor(output)->mMuteCount[stream]); - return NO_ERROR; - } - - // do not change in call volume if bluetooth is connected and vice versa - if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) || - (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) { - LOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm", - stream, mForceUse[AudioSystem::FOR_COMMUNICATION]); - return INVALID_OPERATION; - } - - float volume = computeVolume(stream, index, output, device); - // do not set volume if the float value did not change - if (volume != mOutputs.valueFor(output)->mCurVolume[stream] || force) { - mOutputs.valueFor(output)->mCurVolume[stream] = volume; - LOGV("setStreamVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs); - if (stream == AudioSystem::VOICE_CALL || - stream == AudioSystem::DTMF || - stream == AudioSystem::BLUETOOTH_SCO) { - float voiceVolume = -1.0; - // offset value to reflect actual hardware volume that never reaches 0 - // 1% corresponds roughly to first step in VOICE_CALL stream volume setting (see AudioService.java) - volume = 0.01 + 0.99 * volume; - if (stream == AudioSystem::VOICE_CALL) { - voiceVolume = (float)index/(float)mStreams[stream].mIndexMax; - } else if (stream == AudioSystem::BLUETOOTH_SCO) { - voiceVolume = 1.0; - } - if (voiceVolume >= 0 && output == mHardwareOutput) { - mpClientInterface->setVoiceVolume(voiceVolume, delayMs); - } - } - mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs); - } - - return NO_ERROR; -} - -void AudioPolicyManagerBase::applyStreamVolumes(audio_io_handle_t output, uint32_t device, int delayMs) -{ - LOGV("applyStreamVolumes() for output %d and device %x", output, device); - - for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { - checkAndSetVolume(stream, mStreams[stream].mIndexCur, output, device, delayMs); - } -} - -void AudioPolicyManagerBase::setStrategyMute(routing_strategy strategy, bool on, audio_io_handle_t output, int delayMs) -{ - LOGV("setStrategyMute() strategy %d, mute %d, output %d", strategy, on, output); - for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { - if (getStrategy((AudioSystem::stream_type)stream) == strategy) { - setStreamMute(stream, on, output, delayMs); - } - } -} - -void AudioPolicyManagerBase::setStreamMute(int stream, bool on, audio_io_handle_t output, int delayMs) -{ - StreamDescriptor &streamDesc = mStreams[stream]; - AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); - - LOGV("setStreamMute() stream %d, mute %d, output %d, mMuteCount %d", stream, on, output, outputDesc->mMuteCount[stream]); - - if (on) { - if (outputDesc->mMuteCount[stream] == 0) { - if (streamDesc.mCanBeMuted) { - checkAndSetVolume(stream, 0, output, outputDesc->device(), delayMs); - } - } - // increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored - outputDesc->mMuteCount[stream]++; - } else { - if (outputDesc->mMuteCount[stream] == 0) { - LOGW("setStreamMute() unmuting non muted stream!"); - return; - } - if (--outputDesc->mMuteCount[stream] == 0) { - checkAndSetVolume(stream, streamDesc.mIndexCur, output, outputDesc->device(), delayMs); - } - } -} - -void AudioPolicyManagerBase::handleIncallSonification(int stream, bool starting, bool stateChange) -{ - // if the stream pertains to sonification strategy and we are in call we must - // mute the stream if it is low visibility. If it is high visibility, we must play a tone - // in the device used for phone strategy and play the tone if the selected device does not - // interfere with the device used for phone strategy - // if stateChange is true, we are called from setPhoneState() and we must mute or unmute as - // many times as there are active tracks on the output - - if (getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) { - AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mHardwareOutput); - LOGV("handleIncallSonification() stream %d starting %d device %x stateChange %d", - stream, starting, outputDesc->mDevice, stateChange); - if (outputDesc->mRefCount[stream]) { - int muteCount = 1; - if (stateChange) { - muteCount = outputDesc->mRefCount[stream]; - } - if (AudioSystem::isLowVisibility((AudioSystem::stream_type)stream)) { - LOGV("handleIncallSonification() low visibility, muteCount %d", muteCount); - for (int i = 0; i < muteCount; i++) { - setStreamMute(stream, starting, mHardwareOutput); - } - } else { - LOGV("handleIncallSonification() high visibility"); - if (outputDesc->device() & getDeviceForStrategy(STRATEGY_PHONE)) { - LOGV("handleIncallSonification() high visibility muted, muteCount %d", muteCount); - for (int i = 0; i < muteCount; i++) { - setStreamMute(stream, starting, mHardwareOutput); - } - } - if (starting) { - mpClientInterface->startTone(ToneGenerator::TONE_SUP_CALL_WAITING, AudioSystem::VOICE_CALL); - } else { - mpClientInterface->stopTone(); - } - } - } - } -} - -bool AudioPolicyManagerBase::needsDirectOuput(AudioSystem::stream_type stream, - uint32_t samplingRate, - uint32_t format, - uint32_t channels, - AudioSystem::output_flags flags, - uint32_t device) -{ - return ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) || - (format !=0 && !AudioSystem::isLinearPCM(format))); -} - -// --- AudioOutputDescriptor class implementation - -AudioPolicyManagerBase::AudioOutputDescriptor::AudioOutputDescriptor() - : mId(0), mSamplingRate(0), mFormat(0), mChannels(0), mLatency(0), - mFlags((AudioSystem::output_flags)0), mDevice(0), mOutput1(0), mOutput2(0) -{ - // clear usage count for all stream types - for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) { - mRefCount[i] = 0; - mCurVolume[i] = -1.0; - mMuteCount[i] = 0; - } -} - -uint32_t AudioPolicyManagerBase::AudioOutputDescriptor::device() -{ - uint32_t device = 0; - if (isDuplicated()) { - device = mOutput1->mDevice | mOutput2->mDevice; - } else { - device = mDevice; - } - return device; -} - -void AudioPolicyManagerBase::AudioOutputDescriptor::changeRefCount(AudioSystem::stream_type stream, int delta) -{ - // forward usage count change to attached outputs - if (isDuplicated()) { - mOutput1->changeRefCount(stream, delta); - mOutput2->changeRefCount(stream, delta); - } - if ((delta + (int)mRefCount[stream]) < 0) { - LOGW("changeRefCount() invalid delta %d for stream %d, refCount %d", delta, stream, mRefCount[stream]); - mRefCount[stream] = 0; - return; - } - mRefCount[stream] += delta; - LOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]); -} - -uint32_t AudioPolicyManagerBase::AudioOutputDescriptor::refCount() -{ - uint32_t refcount = 0; - for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { - refcount += mRefCount[i]; - } - return refcount; -} - -uint32_t AudioPolicyManagerBase::AudioOutputDescriptor::strategyRefCount(routing_strategy strategy) -{ - uint32_t refCount = 0; - for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { - if (getStrategy((AudioSystem::stream_type)i) == strategy) { - refCount += mRefCount[i]; - } - } - return refCount; -} - - -status_t AudioPolicyManagerBase::AudioOutputDescriptor::dump(int fd) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - - snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate); - result.append(buffer); - snprintf(buffer, SIZE, " Format: %d\n", mFormat); - result.append(buffer); - snprintf(buffer, SIZE, " Channels: %08x\n", mChannels); - result.append(buffer); - snprintf(buffer, SIZE, " Latency: %d\n", mLatency); - result.append(buffer); - snprintf(buffer, SIZE, " Flags %08x\n", mFlags); - result.append(buffer); - snprintf(buffer, SIZE, " Devices %08x\n", device()); - result.append(buffer); - snprintf(buffer, SIZE, " Stream volume refCount muteCount\n"); - result.append(buffer); - for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) { - snprintf(buffer, SIZE, " %02d %.03f %02d %02d\n", i, mCurVolume[i], mRefCount[i], mMuteCount[i]); - result.append(buffer); - } - write(fd, result.string(), result.size()); - - return NO_ERROR; -} - -// --- AudioInputDescriptor class implementation - -AudioPolicyManagerBase::AudioInputDescriptor::AudioInputDescriptor() - : mSamplingRate(0), mFormat(0), mChannels(0), - mAcoustics((AudioSystem::audio_in_acoustics)0), mDevice(0), mRefCount(0) -{ -} - -status_t AudioPolicyManagerBase::AudioInputDescriptor::dump(int fd) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - - snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate); - result.append(buffer); - snprintf(buffer, SIZE, " Format: %d\n", mFormat); - result.append(buffer); - snprintf(buffer, SIZE, " Channels: %08x\n", mChannels); - result.append(buffer); - snprintf(buffer, SIZE, " Acoustics %08x\n", mAcoustics); - result.append(buffer); - snprintf(buffer, SIZE, " Devices %08x\n", mDevice); - result.append(buffer); - snprintf(buffer, SIZE, " Ref Count %d\n", mRefCount); - result.append(buffer); - write(fd, result.string(), result.size()); - - return NO_ERROR; -} - -// --- StreamDescriptor class implementation - -void AudioPolicyManagerBase::StreamDescriptor::dump(char* buffer, size_t size) -{ - snprintf(buffer, size, " %02d %02d %02d %d\n", - mIndexMin, - mIndexMax, - mIndexCur, - mCanBeMuted); -} - - -}; // namespace android diff --git a/libs/audioflinger/AudioPolicyService.cpp b/libs/audioflinger/AudioPolicyService.cpp deleted file mode 100644 index bb3905c..0000000 --- a/libs/audioflinger/AudioPolicyService.cpp +++ /dev/null @@ -1,924 +0,0 @@ -/* - * Copyright (C) 2009 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. - */ - -#define LOG_TAG "AudioPolicyService" -//#define LOG_NDEBUG 0 - -#undef __STRICT_ANSI__ -#define __STDINT_LIMITS -#define __STDC_LIMIT_MACROS -#include <stdint.h> - -#include <sys/time.h> -#include <binder/IServiceManager.h> -#include <utils/Log.h> -#include <cutils/properties.h> -#include <binder/IPCThreadState.h> -#include <utils/String16.h> -#include <utils/threads.h> -#include "AudioPolicyService.h" -#include <hardware_legacy/AudioPolicyManagerBase.h> -#include <cutils/properties.h> -#include <dlfcn.h> -#include <hardware_legacy/power.h> - -// ---------------------------------------------------------------------------- -// the sim build doesn't have gettid - -#ifndef HAVE_GETTID -# define gettid getpid -#endif - -namespace android { - - -static const char *kDeadlockedString = "AudioPolicyService may be deadlocked\n"; -static const char *kCmdDeadlockedString = "AudioPolicyService command thread may be deadlocked\n"; - -static const int kDumpLockRetries = 50; -static const int kDumpLockSleep = 20000; - -static bool checkPermission() { -#ifndef HAVE_ANDROID_OS - return true; -#endif - if (getpid() == IPCThreadState::self()->getCallingPid()) return true; - bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS")); - if (!ok) LOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS"); - return ok; -} - -// ---------------------------------------------------------------------------- - -AudioPolicyService::AudioPolicyService() - : BnAudioPolicyService() , mpPolicyManager(NULL) -{ - char value[PROPERTY_VALUE_MAX]; - - // start tone playback thread - mTonePlaybackThread = new AudioCommandThread(String8("")); - // start audio commands thread - mAudioCommandThread = new AudioCommandThread(String8("ApmCommandThread")); - -#if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST) - mpPolicyManager = new AudioPolicyManagerBase(this); - LOGV("build for GENERIC_AUDIO - using generic audio policy"); -#else - // if running in emulation - use the emulator driver - if (property_get("ro.kernel.qemu", value, 0)) { - LOGV("Running in emulation - using generic audio policy"); - mpPolicyManager = new AudioPolicyManagerBase(this); - } - else { - LOGV("Using hardware specific audio policy"); - mpPolicyManager = createAudioPolicyManager(this); - } -#endif - - // load properties - property_get("ro.camera.sound.forced", value, "0"); - mpPolicyManager->setSystemProperty("ro.camera.sound.forced", value); -} - -AudioPolicyService::~AudioPolicyService() -{ - mTonePlaybackThread->exit(); - mTonePlaybackThread.clear(); - mAudioCommandThread->exit(); - mAudioCommandThread.clear(); - - if (mpPolicyManager) { - delete mpPolicyManager; - } -} - - -status_t AudioPolicyService::setDeviceConnectionState(AudioSystem::audio_devices device, - AudioSystem::device_connection_state state, - const char *device_address) -{ - if (mpPolicyManager == NULL) { - return NO_INIT; - } - if (!checkPermission()) { - return PERMISSION_DENIED; - } - if (!AudioSystem::isOutputDevice(device) && !AudioSystem::isInputDevice(device)) { - return BAD_VALUE; - } - if (state != AudioSystem::DEVICE_STATE_AVAILABLE && state != AudioSystem::DEVICE_STATE_UNAVAILABLE) { - return BAD_VALUE; - } - - LOGV("setDeviceConnectionState() tid %d", gettid()); - Mutex::Autolock _l(mLock); - return mpPolicyManager->setDeviceConnectionState(device, state, device_address); -} - -AudioSystem::device_connection_state AudioPolicyService::getDeviceConnectionState(AudioSystem::audio_devices device, - const char *device_address) -{ - if (mpPolicyManager == NULL) { - return AudioSystem::DEVICE_STATE_UNAVAILABLE; - } - if (!checkPermission()) { - return AudioSystem::DEVICE_STATE_UNAVAILABLE; - } - return mpPolicyManager->getDeviceConnectionState(device, device_address); -} - -status_t AudioPolicyService::setPhoneState(int state) -{ - if (mpPolicyManager == NULL) { - return NO_INIT; - } - if (!checkPermission()) { - return PERMISSION_DENIED; - } - if (state < 0 || state >= AudioSystem::NUM_MODES) { - return BAD_VALUE; - } - - LOGV("setPhoneState() tid %d", gettid()); - - // TODO: check if it is more appropriate to do it in platform specific policy manager - AudioSystem::setMode(state); - - Mutex::Autolock _l(mLock); - mpPolicyManager->setPhoneState(state); - return NO_ERROR; -} - -status_t AudioPolicyService::setRingerMode(uint32_t mode, uint32_t mask) -{ - if (mpPolicyManager == NULL) { - return NO_INIT; - } - if (!checkPermission()) { - return PERMISSION_DENIED; - } - - mpPolicyManager->setRingerMode(mode, mask); - return NO_ERROR; -} - -status_t AudioPolicyService::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) -{ - if (mpPolicyManager == NULL) { - return NO_INIT; - } - if (!checkPermission()) { - return PERMISSION_DENIED; - } - if (usage < 0 || usage >= AudioSystem::NUM_FORCE_USE) { - return BAD_VALUE; - } - if (config < 0 || config >= AudioSystem::NUM_FORCE_CONFIG) { - return BAD_VALUE; - } - LOGV("setForceUse() tid %d", gettid()); - Mutex::Autolock _l(mLock); - mpPolicyManager->setForceUse(usage, config); - return NO_ERROR; -} - -AudioSystem::forced_config AudioPolicyService::getForceUse(AudioSystem::force_use usage) -{ - if (mpPolicyManager == NULL) { - return AudioSystem::FORCE_NONE; - } - if (!checkPermission()) { - return AudioSystem::FORCE_NONE; - } - if (usage < 0 || usage >= AudioSystem::NUM_FORCE_USE) { - return AudioSystem::FORCE_NONE; - } - return mpPolicyManager->getForceUse(usage); -} - -audio_io_handle_t AudioPolicyService::getOutput(AudioSystem::stream_type stream, - uint32_t samplingRate, - uint32_t format, - uint32_t channels, - AudioSystem::output_flags flags) -{ - if (mpPolicyManager == NULL) { - return 0; - } - LOGV("getOutput() tid %d", gettid()); - Mutex::Autolock _l(mLock); - return mpPolicyManager->getOutput(stream, samplingRate, format, channels, flags); -} - -status_t AudioPolicyService::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream) -{ - if (mpPolicyManager == NULL) { - return NO_INIT; - } - LOGV("startOutput() tid %d", gettid()); - Mutex::Autolock _l(mLock); - return mpPolicyManager->startOutput(output, stream); -} - -status_t AudioPolicyService::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream) -{ - if (mpPolicyManager == NULL) { - return NO_INIT; - } - LOGV("stopOutput() tid %d", gettid()); - Mutex::Autolock _l(mLock); - return mpPolicyManager->stopOutput(output, stream); -} - -void AudioPolicyService::releaseOutput(audio_io_handle_t output) -{ - if (mpPolicyManager == NULL) { - return; - } - LOGV("releaseOutput() tid %d", gettid()); - Mutex::Autolock _l(mLock); - mpPolicyManager->releaseOutput(output); -} - -audio_io_handle_t AudioPolicyService::getInput(int inputSource, - uint32_t samplingRate, - uint32_t format, - uint32_t channels, - AudioSystem::audio_in_acoustics acoustics) -{ - if (mpPolicyManager == NULL) { - return 0; - } - Mutex::Autolock _l(mLock); - return mpPolicyManager->getInput(inputSource, samplingRate, format, channels, acoustics); -} - -status_t AudioPolicyService::startInput(audio_io_handle_t input) -{ - if (mpPolicyManager == NULL) { - return NO_INIT; - } - Mutex::Autolock _l(mLock); - return mpPolicyManager->startInput(input); -} - -status_t AudioPolicyService::stopInput(audio_io_handle_t input) -{ - if (mpPolicyManager == NULL) { - return NO_INIT; - } - Mutex::Autolock _l(mLock); - return mpPolicyManager->stopInput(input); -} - -void AudioPolicyService::releaseInput(audio_io_handle_t input) -{ - if (mpPolicyManager == NULL) { - return; - } - Mutex::Autolock _l(mLock); - mpPolicyManager->releaseInput(input); -} - -status_t AudioPolicyService::initStreamVolume(AudioSystem::stream_type stream, - int indexMin, - int indexMax) -{ - if (mpPolicyManager == NULL) { - return NO_INIT; - } - if (!checkPermission()) { - return PERMISSION_DENIED; - } - if (stream < 0 || stream >= AudioSystem::NUM_STREAM_TYPES) { - return BAD_VALUE; - } - mpPolicyManager->initStreamVolume(stream, indexMin, indexMax); - return NO_ERROR; -} - -status_t AudioPolicyService::setStreamVolumeIndex(AudioSystem::stream_type stream, int index) -{ - if (mpPolicyManager == NULL) { - return NO_INIT; - } - if (!checkPermission()) { - return PERMISSION_DENIED; - } - if (stream < 0 || stream >= AudioSystem::NUM_STREAM_TYPES) { - return BAD_VALUE; - } - - return mpPolicyManager->setStreamVolumeIndex(stream, index); -} - -status_t AudioPolicyService::getStreamVolumeIndex(AudioSystem::stream_type stream, int *index) -{ - if (mpPolicyManager == NULL) { - return NO_INIT; - } - if (!checkPermission()) { - return PERMISSION_DENIED; - } - if (stream < 0 || stream >= AudioSystem::NUM_STREAM_TYPES) { - return BAD_VALUE; - } - return mpPolicyManager->getStreamVolumeIndex(stream, index); -} - -void AudioPolicyService::binderDied(const wp<IBinder>& who) { - LOGW("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid()); -} - -static bool tryLock(Mutex& mutex) -{ - bool locked = false; - for (int i = 0; i < kDumpLockRetries; ++i) { - if (mutex.tryLock() == NO_ERROR) { - locked = true; - break; - } - usleep(kDumpLockSleep); - } - return locked; -} - -status_t AudioPolicyService::dumpInternals(int fd) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - - snprintf(buffer, SIZE, "PolicyManager Interface: %p\n", mpPolicyManager); - result.append(buffer); - snprintf(buffer, SIZE, "Command Thread: %p\n", mAudioCommandThread.get()); - result.append(buffer); - snprintf(buffer, SIZE, "Tones Thread: %p\n", mTonePlaybackThread.get()); - result.append(buffer); - - write(fd, result.string(), result.size()); - return NO_ERROR; -} - -status_t AudioPolicyService::dump(int fd, const Vector<String16>& args) -{ - if (checkCallingPermission(String16("android.permission.DUMP")) == false) { - dumpPermissionDenial(fd); - } else { - bool locked = tryLock(mLock); - if (!locked) { - String8 result(kDeadlockedString); - write(fd, result.string(), result.size()); - } - - dumpInternals(fd); - if (mAudioCommandThread != NULL) { - mAudioCommandThread->dump(fd); - } - if (mTonePlaybackThread != NULL) { - mTonePlaybackThread->dump(fd); - } - - if (mpPolicyManager) { - mpPolicyManager->dump(fd); - } - - if (locked) mLock.unlock(); - } - return NO_ERROR; -} - -status_t AudioPolicyService::dumpPermissionDenial(int fd) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - snprintf(buffer, SIZE, "Permission Denial: " - "can't dump AudioPolicyService from pid=%d, uid=%d\n", - IPCThreadState::self()->getCallingPid(), - IPCThreadState::self()->getCallingUid()); - result.append(buffer); - write(fd, result.string(), result.size()); - return NO_ERROR; -} - -status_t AudioPolicyService::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - return BnAudioPolicyService::onTransact(code, data, reply, flags); -} - - -// ---------------------------------------------------------------------------- -void AudioPolicyService::instantiate() { - defaultServiceManager()->addService( - String16("media.audio_policy"), new AudioPolicyService()); -} - - -// ---------------------------------------------------------------------------- -// AudioPolicyClientInterface implementation -// ---------------------------------------------------------------------------- - - -audio_io_handle_t AudioPolicyService::openOutput(uint32_t *pDevices, - uint32_t *pSamplingRate, - uint32_t *pFormat, - uint32_t *pChannels, - uint32_t *pLatencyMs, - AudioSystem::output_flags flags) -{ - sp<IAudioFlinger> af = AudioSystem::get_audio_flinger(); - if (af == 0) { - LOGW("openOutput() could not get AudioFlinger"); - return 0; - } - - return af->openOutput(pDevices, pSamplingRate, (uint32_t *)pFormat, pChannels, pLatencyMs, flags); -} - -audio_io_handle_t AudioPolicyService::openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2) -{ - sp<IAudioFlinger> af = AudioSystem::get_audio_flinger(); - if (af == 0) { - LOGW("openDuplicateOutput() could not get AudioFlinger"); - return 0; - } - return af->openDuplicateOutput(output1, output2); -} - -status_t AudioPolicyService::closeOutput(audio_io_handle_t output) -{ - sp<IAudioFlinger> af = AudioSystem::get_audio_flinger(); - if (af == 0) return PERMISSION_DENIED; - - return af->closeOutput(output); -} - - -status_t AudioPolicyService::suspendOutput(audio_io_handle_t output) -{ - sp<IAudioFlinger> af = AudioSystem::get_audio_flinger(); - if (af == 0) { - LOGW("suspendOutput() could not get AudioFlinger"); - return PERMISSION_DENIED; - } - - return af->suspendOutput(output); -} - -status_t AudioPolicyService::restoreOutput(audio_io_handle_t output) -{ - sp<IAudioFlinger> af = AudioSystem::get_audio_flinger(); - if (af == 0) { - LOGW("restoreOutput() could not get AudioFlinger"); - return PERMISSION_DENIED; - } - - return af->restoreOutput(output); -} - -audio_io_handle_t AudioPolicyService::openInput(uint32_t *pDevices, - uint32_t *pSamplingRate, - uint32_t *pFormat, - uint32_t *pChannels, - uint32_t acoustics) -{ - sp<IAudioFlinger> af = AudioSystem::get_audio_flinger(); - if (af == 0) { - LOGW("openInput() could not get AudioFlinger"); - return 0; - } - - return af->openInput(pDevices, pSamplingRate, (uint32_t *)pFormat, pChannels, acoustics); -} - -status_t AudioPolicyService::closeInput(audio_io_handle_t input) -{ - sp<IAudioFlinger> af = AudioSystem::get_audio_flinger(); - if (af == 0) return PERMISSION_DENIED; - - return af->closeInput(input); -} - -status_t AudioPolicyService::setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output, int delayMs) -{ - return mAudioCommandThread->volumeCommand((int)stream, volume, (int)output, delayMs); -} - -status_t AudioPolicyService::setStreamOutput(AudioSystem::stream_type stream, audio_io_handle_t output) -{ - sp<IAudioFlinger> af = AudioSystem::get_audio_flinger(); - if (af == 0) return PERMISSION_DENIED; - - return af->setStreamOutput(stream, output); -} - - -void AudioPolicyService::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs) -{ - mAudioCommandThread->parametersCommand((int)ioHandle, keyValuePairs, delayMs); -} - -String8 AudioPolicyService::getParameters(audio_io_handle_t ioHandle, const String8& keys) -{ - String8 result = AudioSystem::getParameters(ioHandle, keys); - return result; -} - -status_t AudioPolicyService::startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream) -{ - mTonePlaybackThread->startToneCommand(tone, stream); - return NO_ERROR; -} - -status_t AudioPolicyService::stopTone() -{ - mTonePlaybackThread->stopToneCommand(); - return NO_ERROR; -} - -status_t AudioPolicyService::setVoiceVolume(float volume, int delayMs) -{ - return mAudioCommandThread->voiceVolumeCommand(volume, delayMs); -} - -// ----------- AudioPolicyService::AudioCommandThread implementation ---------- - -AudioPolicyService::AudioCommandThread::AudioCommandThread(String8 name) - : Thread(false), mName(name) -{ - mpToneGenerator = NULL; -} - - -AudioPolicyService::AudioCommandThread::~AudioCommandThread() -{ - if (mName != "" && !mAudioCommands.isEmpty()) { - release_wake_lock(mName.string()); - } - mAudioCommands.clear(); - if (mpToneGenerator != NULL) delete mpToneGenerator; -} - -void AudioPolicyService::AudioCommandThread::onFirstRef() -{ - if (mName != "") { - run(mName.string(), ANDROID_PRIORITY_AUDIO); - } else { - run("AudioCommandThread", ANDROID_PRIORITY_AUDIO); - } -} - -bool AudioPolicyService::AudioCommandThread::threadLoop() -{ - nsecs_t waitTime = INT64_MAX; - - mLock.lock(); - while (!exitPending()) - { - while(!mAudioCommands.isEmpty()) { - nsecs_t curTime = systemTime(); - // commands are sorted by increasing time stamp: execute them from index 0 and up - if (mAudioCommands[0]->mTime <= curTime) { - AudioCommand *command = mAudioCommands[0]; - mAudioCommands.removeAt(0); - mLastCommand = *command; - - switch (command->mCommand) { - case START_TONE: { - mLock.unlock(); - ToneData *data = (ToneData *)command->mParam; - LOGV("AudioCommandThread() processing start tone %d on stream %d", - data->mType, data->mStream); - if (mpToneGenerator != NULL) - delete mpToneGenerator; - mpToneGenerator = new ToneGenerator(data->mStream, 1.0); - mpToneGenerator->startTone(data->mType); - delete data; - mLock.lock(); - }break; - case STOP_TONE: { - mLock.unlock(); - LOGV("AudioCommandThread() processing stop tone"); - if (mpToneGenerator != NULL) { - mpToneGenerator->stopTone(); - delete mpToneGenerator; - mpToneGenerator = NULL; - } - mLock.lock(); - }break; - case SET_VOLUME: { - VolumeData *data = (VolumeData *)command->mParam; - LOGV("AudioCommandThread() processing set volume stream %d, volume %f, output %d", data->mStream, data->mVolume, data->mIO); - command->mStatus = AudioSystem::setStreamVolume(data->mStream, data->mVolume, data->mIO); - if (command->mWaitStatus) { - command->mCond.signal(); - mWaitWorkCV.wait(mLock); - } - delete data; - }break; - case SET_PARAMETERS: { - ParametersData *data = (ParametersData *)command->mParam; - LOGV("AudioCommandThread() processing set parameters string %s, io %d", data->mKeyValuePairs.string(), data->mIO); - command->mStatus = AudioSystem::setParameters(data->mIO, data->mKeyValuePairs); - if (command->mWaitStatus) { - command->mCond.signal(); - mWaitWorkCV.wait(mLock); - } - delete data; - }break; - case SET_VOICE_VOLUME: { - VoiceVolumeData *data = (VoiceVolumeData *)command->mParam; - LOGV("AudioCommandThread() processing set voice volume volume %f", data->mVolume); - command->mStatus = AudioSystem::setVoiceVolume(data->mVolume); - if (command->mWaitStatus) { - command->mCond.signal(); - mWaitWorkCV.wait(mLock); - } - delete data; - }break; - default: - LOGW("AudioCommandThread() unknown command %d", command->mCommand); - } - delete command; - waitTime = INT64_MAX; - } else { - waitTime = mAudioCommands[0]->mTime - curTime; - break; - } - } - // release delayed commands wake lock - if (mName != "" && mAudioCommands.isEmpty()) { - release_wake_lock(mName.string()); - } - LOGV("AudioCommandThread() going to sleep"); - mWaitWorkCV.waitRelative(mLock, waitTime); - LOGV("AudioCommandThread() waking up"); - } - mLock.unlock(); - return false; -} - -status_t AudioPolicyService::AudioCommandThread::dump(int fd) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - - snprintf(buffer, SIZE, "AudioCommandThread %p Dump\n", this); - result.append(buffer); - write(fd, result.string(), result.size()); - - bool locked = tryLock(mLock); - if (!locked) { - String8 result2(kCmdDeadlockedString); - write(fd, result2.string(), result2.size()); - } - - snprintf(buffer, SIZE, "- Commands:\n"); - result = String8(buffer); - result.append(" Command Time Wait pParam\n"); - for (int i = 0; i < (int)mAudioCommands.size(); i++) { - mAudioCommands[i]->dump(buffer, SIZE); - result.append(buffer); - } - result.append(" Last Command\n"); - mLastCommand.dump(buffer, SIZE); - result.append(buffer); - - write(fd, result.string(), result.size()); - - if (locked) mLock.unlock(); - - return NO_ERROR; -} - -void AudioPolicyService::AudioCommandThread::startToneCommand(int type, int stream) -{ - AudioCommand *command = new AudioCommand(); - command->mCommand = START_TONE; - ToneData *data = new ToneData(); - data->mType = type; - data->mStream = stream; - command->mParam = (void *)data; - command->mWaitStatus = false; - Mutex::Autolock _l(mLock); - insertCommand_l(command); - LOGV("AudioCommandThread() adding tone start type %d, stream %d", type, stream); - mWaitWorkCV.signal(); -} - -void AudioPolicyService::AudioCommandThread::stopToneCommand() -{ - AudioCommand *command = new AudioCommand(); - command->mCommand = STOP_TONE; - command->mParam = NULL; - command->mWaitStatus = false; - Mutex::Autolock _l(mLock); - insertCommand_l(command); - LOGV("AudioCommandThread() adding tone stop"); - mWaitWorkCV.signal(); -} - -status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float volume, int output, int delayMs) -{ - status_t status = NO_ERROR; - - AudioCommand *command = new AudioCommand(); - command->mCommand = SET_VOLUME; - VolumeData *data = new VolumeData(); - data->mStream = stream; - data->mVolume = volume; - data->mIO = output; - command->mParam = data; - if (delayMs == 0) { - command->mWaitStatus = true; - } else { - command->mWaitStatus = false; - } - Mutex::Autolock _l(mLock); - insertCommand_l(command, delayMs); - LOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %d", stream, volume, output); - mWaitWorkCV.signal(); - if (command->mWaitStatus) { - command->mCond.wait(mLock); - status = command->mStatus; - mWaitWorkCV.signal(); - } - return status; -} - -status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle, const String8& keyValuePairs, int delayMs) -{ - status_t status = NO_ERROR; - - AudioCommand *command = new AudioCommand(); - command->mCommand = SET_PARAMETERS; - ParametersData *data = new ParametersData(); - data->mIO = ioHandle; - data->mKeyValuePairs = keyValuePairs; - command->mParam = data; - if (delayMs == 0) { - command->mWaitStatus = true; - } else { - command->mWaitStatus = false; - } - Mutex::Autolock _l(mLock); - insertCommand_l(command, delayMs); - LOGV("AudioCommandThread() adding set parameter string %s, io %d ,delay %d", keyValuePairs.string(), ioHandle, delayMs); - mWaitWorkCV.signal(); - if (command->mWaitStatus) { - command->mCond.wait(mLock); - status = command->mStatus; - mWaitWorkCV.signal(); - } - return status; -} - -status_t AudioPolicyService::AudioCommandThread::voiceVolumeCommand(float volume, int delayMs) -{ - status_t status = NO_ERROR; - - AudioCommand *command = new AudioCommand(); - command->mCommand = SET_VOICE_VOLUME; - VoiceVolumeData *data = new VoiceVolumeData(); - data->mVolume = volume; - command->mParam = data; - if (delayMs == 0) { - command->mWaitStatus = true; - } else { - command->mWaitStatus = false; - } - Mutex::Autolock _l(mLock); - insertCommand_l(command, delayMs); - LOGV("AudioCommandThread() adding set voice volume volume %f", volume); - mWaitWorkCV.signal(); - if (command->mWaitStatus) { - command->mCond.wait(mLock); - status = command->mStatus; - mWaitWorkCV.signal(); - } - return status; -} - -// insertCommand_l() must be called with mLock held -void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *command, int delayMs) -{ - ssize_t i; - Vector <AudioCommand *> removedCommands; - - command->mTime = systemTime() + milliseconds(delayMs); - - // acquire wake lock to make sure delayed commands are processed - if (mName != "" && mAudioCommands.isEmpty()) { - acquire_wake_lock(PARTIAL_WAKE_LOCK, mName.string()); - } - - // check same pending commands with later time stamps and eliminate them - for (i = mAudioCommands.size()-1; i >= 0; i--) { - AudioCommand *command2 = mAudioCommands[i]; - // commands are sorted by increasing time stamp: no need to scan the rest of mAudioCommands - if (command2->mTime <= command->mTime) break; - if (command2->mCommand != command->mCommand) continue; - - switch (command->mCommand) { - case SET_PARAMETERS: { - ParametersData *data = (ParametersData *)command->mParam; - ParametersData *data2 = (ParametersData *)command2->mParam; - if (data->mIO != data2->mIO) break; - LOGV("Comparing parameter command %s to new command %s", data2->mKeyValuePairs.string(), data->mKeyValuePairs.string()); - AudioParameter param = AudioParameter(data->mKeyValuePairs); - AudioParameter param2 = AudioParameter(data2->mKeyValuePairs); - for (size_t j = 0; j < param.size(); j++) { - String8 key; - String8 value; - param.getAt(j, key, value); - for (size_t k = 0; k < param2.size(); k++) { - String8 key2; - String8 value2; - param2.getAt(k, key2, value2); - if (key2 == key) { - param2.remove(key2); - LOGV("Filtering out parameter %s", key2.string()); - break; - } - } - } - // if all keys have been filtered out, remove the command. - // otherwise, update the key value pairs - if (param2.size() == 0) { - removedCommands.add(command2); - } else { - data2->mKeyValuePairs = param2.toString(); - } - } break; - - case SET_VOLUME: { - VolumeData *data = (VolumeData *)command->mParam; - VolumeData *data2 = (VolumeData *)command2->mParam; - if (data->mIO != data2->mIO) break; - if (data->mStream != data2->mStream) break; - LOGV("Filtering out volume command on output %d for stream %d", data->mIO, data->mStream); - removedCommands.add(command2); - } break; - case START_TONE: - case STOP_TONE: - default: - break; - } - } - - // remove filtered commands - for (size_t j = 0; j < removedCommands.size(); j++) { - // removed commands always have time stamps greater than current command - for (size_t k = i + 1; k < mAudioCommands.size(); k++) { - if (mAudioCommands[k] == removedCommands[j]) { - LOGV("suppressing command: %d", mAudioCommands[k]->mCommand); - mAudioCommands.removeAt(k); - break; - } - } - } - removedCommands.clear(); - - // insert command at the right place according to its time stamp - LOGV("inserting command: %d at index %d, num commands %d", command->mCommand, (int)i+1, mAudioCommands.size()); - mAudioCommands.insertAt(command, i + 1); -} - -void AudioPolicyService::AudioCommandThread::exit() -{ - LOGV("AudioCommandThread::exit"); - { - AutoMutex _l(mLock); - requestExit(); - mWaitWorkCV.signal(); - } - requestExitAndWait(); -} - -void AudioPolicyService::AudioCommandThread::AudioCommand::dump(char* buffer, size_t size) -{ - snprintf(buffer, size, " %02d %06d.%03d %01u %p\n", - mCommand, - (int)ns2s(mTime), - (int)ns2ms(mTime)%1000, - mWaitStatus, - mParam); -} - -}; // namespace android diff --git a/libs/audioflinger/AudioPolicyService.h b/libs/audioflinger/AudioPolicyService.h deleted file mode 100644 index a13d0bd..0000000 --- a/libs/audioflinger/AudioPolicyService.h +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (C) 2009 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. - */ - -#ifndef ANDROID_AUDIOPOLICYSERVICE_H -#define ANDROID_AUDIOPOLICYSERVICE_H - -#include <media/IAudioPolicyService.h> -#include <hardware_legacy/AudioPolicyInterface.h> -#include <media/ToneGenerator.h> -#include <utils/Vector.h> - -namespace android { - -class String8; - -// ---------------------------------------------------------------------------- - -class AudioPolicyService: public BnAudioPolicyService, public AudioPolicyClientInterface, public IBinder::DeathRecipient -{ - -public: - static void instantiate(); - - virtual status_t dump(int fd, const Vector<String16>& args); - - // - // BnAudioPolicyService (see AudioPolicyInterface for method descriptions) - // - - virtual status_t setDeviceConnectionState(AudioSystem::audio_devices device, - AudioSystem::device_connection_state state, - const char *device_address); - virtual AudioSystem::device_connection_state getDeviceConnectionState(AudioSystem::audio_devices device, - const char *device_address); - virtual status_t setPhoneState(int state); - virtual status_t setRingerMode(uint32_t mode, uint32_t mask); - virtual status_t setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config); - virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage); - virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream, - uint32_t samplingRate = 0, - uint32_t format = AudioSystem::FORMAT_DEFAULT, - uint32_t channels = 0, - AudioSystem::output_flags flags = AudioSystem::OUTPUT_FLAG_INDIRECT); - virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream); - virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream); - virtual void releaseOutput(audio_io_handle_t output); - virtual audio_io_handle_t getInput(int inputSource, - uint32_t samplingRate = 0, - uint32_t format = AudioSystem::FORMAT_DEFAULT, - uint32_t channels = 0, - AudioSystem::audio_in_acoustics acoustics = (AudioSystem::audio_in_acoustics)0); - virtual status_t startInput(audio_io_handle_t input); - virtual status_t stopInput(audio_io_handle_t input); - virtual void releaseInput(audio_io_handle_t input); - virtual status_t initStreamVolume(AudioSystem::stream_type stream, - int indexMin, - int indexMax); - virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index); - virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index); - - virtual status_t onTransact( - uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags); - - // IBinder::DeathRecipient - virtual void binderDied(const wp<IBinder>& who); - - // - // AudioPolicyClientInterface - // - virtual audio_io_handle_t openOutput(uint32_t *pDevices, - uint32_t *pSamplingRate, - uint32_t *pFormat, - uint32_t *pChannels, - uint32_t *pLatencyMs, - AudioSystem::output_flags flags); - virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2); - virtual status_t closeOutput(audio_io_handle_t output); - virtual status_t suspendOutput(audio_io_handle_t output); - virtual status_t restoreOutput(audio_io_handle_t output); - virtual audio_io_handle_t openInput(uint32_t *pDevices, - uint32_t *pSamplingRate, - uint32_t *pFormat, - uint32_t *pChannels, - uint32_t acoustics); - virtual status_t closeInput(audio_io_handle_t input); - virtual status_t setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output, int delayMs = 0); - virtual status_t setStreamOutput(AudioSystem::stream_type stream, audio_io_handle_t output); - virtual void setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs = 0); - virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys); - virtual status_t startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream); - virtual status_t stopTone(); - virtual status_t setVoiceVolume(float volume, int delayMs = 0); - -private: - AudioPolicyService(); - virtual ~AudioPolicyService(); - - status_t dumpInternals(int fd); - - // Thread used for tone playback and to send audio config commands to audio flinger - // For tone playback, using a separate thread is necessary to avoid deadlock with mLock because startTone() - // and stopTone() are normally called with mLock locked and requesting a tone start or stop will cause - // calls to AudioPolicyService and an attempt to lock mLock. - // For audio config commands, it is necessary because audio flinger requires that the calling process (user) - // has permission to modify audio settings. - class AudioCommandThread : public Thread { - class AudioCommand; - public: - - // commands for tone AudioCommand - enum { - START_TONE, - STOP_TONE, - SET_VOLUME, - SET_PARAMETERS, - SET_VOICE_VOLUME - }; - - AudioCommandThread (String8 name); - virtual ~AudioCommandThread(); - - status_t dump(int fd); - - // Thread virtuals - virtual void onFirstRef(); - virtual bool threadLoop(); - - void exit(); - void startToneCommand(int type = 0, int stream = 0); - void stopToneCommand(); - status_t volumeCommand(int stream, float volume, int output, int delayMs = 0); - status_t parametersCommand(int ioHandle, const String8& keyValuePairs, int delayMs = 0); - status_t voiceVolumeCommand(float volume, int delayMs = 0); - void insertCommand_l(AudioCommand *command, int delayMs = 0); - - private: - // descriptor for requested tone playback event - class AudioCommand { - - public: - AudioCommand() - : mCommand(-1) {} - - void dump(char* buffer, size_t size); - - int mCommand; // START_TONE, STOP_TONE ... - nsecs_t mTime; // time stamp - Condition mCond; // condition for status return - status_t mStatus; // command status - bool mWaitStatus; // true if caller is waiting for status - void *mParam; // command parameter (ToneData, VolumeData, ParametersData) - }; - - class ToneData { - public: - int mType; // tone type (START_TONE only) - int mStream; // stream type (START_TONE only) - }; - - class VolumeData { - public: - int mStream; - float mVolume; - int mIO; - }; - - class ParametersData { - public: - int mIO; - String8 mKeyValuePairs; - }; - - class VoiceVolumeData { - public: - float mVolume; - }; - - Mutex mLock; - Condition mWaitWorkCV; - Vector <AudioCommand *> mAudioCommands; // list of pending commands - ToneGenerator *mpToneGenerator; // the tone generator - AudioCommand mLastCommand; // last processed command (used by dump) - String8 mName; // string used by wake lock fo delayed commands - }; - - // Internal dump utilities. - status_t dumpPermissionDenial(int fd); - - - Mutex mLock; // prevents concurrent access to AudioPolicy manager functions changing device - // connection stated our routing - AudioPolicyInterface* mpPolicyManager; // the platform specific policy manager - sp <AudioCommandThread> mAudioCommandThread; // audio commands thread - sp <AudioCommandThread> mTonePlaybackThread; // tone playback thread -}; - -}; // namespace android - -#endif // ANDROID_AUDIOPOLICYSERVICE_H - - - - - - - - diff --git a/libs/audioflinger/AudioResampler.cpp b/libs/audioflinger/AudioResampler.cpp deleted file mode 100644 index 5dabacb..0000000 --- a/libs/audioflinger/AudioResampler.cpp +++ /dev/null @@ -1,595 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "AudioResampler" -//#define LOG_NDEBUG 0 - -#include <stdint.h> -#include <stdlib.h> -#include <sys/types.h> -#include <cutils/log.h> -#include <cutils/properties.h> -#include "AudioResampler.h" -#include "AudioResamplerSinc.h" -#include "AudioResamplerCubic.h" - -namespace android { - -#ifdef __ARM_ARCH_5E__ // optimized asm option - #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1 -#endif // __ARM_ARCH_5E__ -// ---------------------------------------------------------------------------- - -class AudioResamplerOrder1 : public AudioResampler { -public: - AudioResamplerOrder1(int bitDepth, int inChannelCount, int32_t sampleRate) : - AudioResampler(bitDepth, inChannelCount, sampleRate), mX0L(0), mX0R(0) { - } - virtual void resample(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider); -private: - // number of bits used in interpolation multiply - 15 bits avoids overflow - static const int kNumInterpBits = 15; - - // bits to shift the phase fraction down to avoid overflow - static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits; - - void init() {} - void resampleMono16(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider); - void resampleStereo16(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider); -#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 - void AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, - size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, - uint32_t &phaseFraction, uint32_t phaseIncrement); - void AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, - size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, - uint32_t &phaseFraction, uint32_t phaseIncrement); -#endif // ASM_ARM_RESAMP1 - - static inline int32_t Interp(int32_t x0, int32_t x1, uint32_t f) { - return x0 + (((x1 - x0) * (int32_t)(f >> kPreInterpShift)) >> kNumInterpBits); - } - static inline void Advance(size_t* index, uint32_t* frac, uint32_t inc) { - *frac += inc; - *index += (size_t)(*frac >> kNumPhaseBits); - *frac &= kPhaseMask; - } - int mX0L; - int mX0R; -}; - -// ---------------------------------------------------------------------------- -AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount, - int32_t sampleRate, int quality) { - - // can only create low quality resample now - AudioResampler* resampler; - - char value[PROPERTY_VALUE_MAX]; - if (property_get("af.resampler.quality", value, 0)) { - quality = atoi(value); - LOGD("forcing AudioResampler quality to %d", quality); - } - - if (quality == DEFAULT) - quality = LOW_QUALITY; - - switch (quality) { - default: - case LOW_QUALITY: - LOGV("Create linear Resampler"); - resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate); - break; - case MED_QUALITY: - LOGV("Create cubic Resampler"); - resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate); - break; - case HIGH_QUALITY: - LOGV("Create sinc Resampler"); - resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate); - break; - } - - // initialize resampler - resampler->init(); - return resampler; -} - -AudioResampler::AudioResampler(int bitDepth, int inChannelCount, - int32_t sampleRate) : - mBitDepth(bitDepth), mChannelCount(inChannelCount), - mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0), - mPhaseFraction(0) { - // sanity check on format - if ((bitDepth != 16) ||(inChannelCount < 1) || (inChannelCount > 2)) { - LOGE("Unsupported sample format, %d bits, %d channels", bitDepth, - inChannelCount); - // LOG_ASSERT(0); - } - - // initialize common members - mVolume[0] = mVolume[1] = 0; - mBuffer.frameCount = 0; - - // save format for quick lookup - if (inChannelCount == 1) { - mFormat = MONO_16_BIT; - } else { - mFormat = STEREO_16_BIT; - } -} - -AudioResampler::~AudioResampler() { -} - -void AudioResampler::setSampleRate(int32_t inSampleRate) { - mInSampleRate = inSampleRate; - mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate); -} - -void AudioResampler::setVolume(int16_t left, int16_t right) { - // TODO: Implement anti-zipper filter - mVolume[0] = left; - mVolume[1] = right; -} - -// ---------------------------------------------------------------------------- - -void AudioResamplerOrder1::resample(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider) { - - // should never happen, but we overflow if it does - // LOG_ASSERT(outFrameCount < 32767); - - // select the appropriate resampler - switch (mChannelCount) { - case 1: - resampleMono16(out, outFrameCount, provider); - break; - case 2: - resampleStereo16(out, outFrameCount, provider); - break; - } -} - -void AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider) { - - int32_t vl = mVolume[0]; - int32_t vr = mVolume[1]; - - size_t inputIndex = mInputIndex; - uint32_t phaseFraction = mPhaseFraction; - uint32_t phaseIncrement = mPhaseIncrement; - size_t outputIndex = 0; - size_t outputSampleCount = outFrameCount * 2; - size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate; - - // LOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n", - // outFrameCount, inputIndex, phaseFraction, phaseIncrement); - - while (outputIndex < outputSampleCount) { - - // buffer is empty, fetch a new one - while (mBuffer.frameCount == 0) { - mBuffer.frameCount = inFrameCount; - provider->getNextBuffer(&mBuffer); - if (mBuffer.raw == NULL) { - goto resampleStereo16_exit; - } - - // LOGE("New buffer fetched: %d frames\n", mBuffer.frameCount); - if (mBuffer.frameCount > inputIndex) break; - - inputIndex -= mBuffer.frameCount; - mX0L = mBuffer.i16[mBuffer.frameCount*2-2]; - mX0R = mBuffer.i16[mBuffer.frameCount*2-1]; - provider->releaseBuffer(&mBuffer); - // mBuffer.frameCount == 0 now so we reload a new buffer - } - - int16_t *in = mBuffer.i16; - - // handle boundary case - while (inputIndex == 0) { - // LOGE("boundary case\n"); - out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction); - out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction); - Advance(&inputIndex, &phaseFraction, phaseIncrement); - if (outputIndex == outputSampleCount) - break; - } - - // process input samples - // LOGE("general case\n"); - -#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 - if (inputIndex + 2 < mBuffer.frameCount) { - int32_t* maxOutPt; - int32_t maxInIdx; - - maxOutPt = out + (outputSampleCount - 2); // 2 because 2 frames per loop - maxInIdx = mBuffer.frameCount - 2; - AsmStereo16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr, - phaseFraction, phaseIncrement); - } -#endif // ASM_ARM_RESAMP1 - - while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) { - out[outputIndex++] += vl * Interp(in[inputIndex*2-2], - in[inputIndex*2], phaseFraction); - out[outputIndex++] += vr * Interp(in[inputIndex*2-1], - in[inputIndex*2+1], phaseFraction); - Advance(&inputIndex, &phaseFraction, phaseIncrement); - } - - // LOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex); - - // if done with buffer, save samples - if (inputIndex >= mBuffer.frameCount) { - inputIndex -= mBuffer.frameCount; - - // LOGE("buffer done, new input index %d", inputIndex); - - mX0L = mBuffer.i16[mBuffer.frameCount*2-2]; - mX0R = mBuffer.i16[mBuffer.frameCount*2-1]; - provider->releaseBuffer(&mBuffer); - - // verify that the releaseBuffer resets the buffer frameCount - // LOG_ASSERT(mBuffer.frameCount == 0); - } - } - - // LOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex); - -resampleStereo16_exit: - // save state - mInputIndex = inputIndex; - mPhaseFraction = phaseFraction; -} - -void AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider) { - - int32_t vl = mVolume[0]; - int32_t vr = mVolume[1]; - - size_t inputIndex = mInputIndex; - uint32_t phaseFraction = mPhaseFraction; - uint32_t phaseIncrement = mPhaseIncrement; - size_t outputIndex = 0; - size_t outputSampleCount = outFrameCount * 2; - size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate; - - // LOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n", - // outFrameCount, inputIndex, phaseFraction, phaseIncrement); - while (outputIndex < outputSampleCount) { - // buffer is empty, fetch a new one - while (mBuffer.frameCount == 0) { - mBuffer.frameCount = inFrameCount; - provider->getNextBuffer(&mBuffer); - if (mBuffer.raw == NULL) { - mInputIndex = inputIndex; - mPhaseFraction = phaseFraction; - goto resampleMono16_exit; - } - // LOGE("New buffer fetched: %d frames\n", mBuffer.frameCount); - if (mBuffer.frameCount > inputIndex) break; - - inputIndex -= mBuffer.frameCount; - mX0L = mBuffer.i16[mBuffer.frameCount-1]; - provider->releaseBuffer(&mBuffer); - // mBuffer.frameCount == 0 now so we reload a new buffer - } - int16_t *in = mBuffer.i16; - - // handle boundary case - while (inputIndex == 0) { - // LOGE("boundary case\n"); - int32_t sample = Interp(mX0L, in[0], phaseFraction); - out[outputIndex++] += vl * sample; - out[outputIndex++] += vr * sample; - Advance(&inputIndex, &phaseFraction, phaseIncrement); - if (outputIndex == outputSampleCount) - break; - } - - // process input samples - // LOGE("general case\n"); - -#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 - if (inputIndex + 2 < mBuffer.frameCount) { - int32_t* maxOutPt; - int32_t maxInIdx; - - maxOutPt = out + (outputSampleCount - 2); - maxInIdx = (int32_t)mBuffer.frameCount - 2; - AsmMono16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr, - phaseFraction, phaseIncrement); - } -#endif // ASM_ARM_RESAMP1 - - while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) { - int32_t sample = Interp(in[inputIndex-1], in[inputIndex], - phaseFraction); - out[outputIndex++] += vl * sample; - out[outputIndex++] += vr * sample; - Advance(&inputIndex, &phaseFraction, phaseIncrement); - } - - - // LOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex); - - // if done with buffer, save samples - if (inputIndex >= mBuffer.frameCount) { - inputIndex -= mBuffer.frameCount; - - // LOGE("buffer done, new input index %d", inputIndex); - - mX0L = mBuffer.i16[mBuffer.frameCount-1]; - provider->releaseBuffer(&mBuffer); - - // verify that the releaseBuffer resets the buffer frameCount - // LOG_ASSERT(mBuffer.frameCount == 0); - } - } - - // LOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex); - -resampleMono16_exit: - // save state - mInputIndex = inputIndex; - mPhaseFraction = phaseFraction; -} - -#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 - -/******************************************************************* -* -* AsmMono16Loop -* asm optimized monotonic loop version; one loop is 2 frames -* Input: -* in : pointer on input samples -* maxOutPt : pointer on first not filled -* maxInIdx : index on first not used -* outputIndex : pointer on current output index -* out : pointer on output buffer -* inputIndex : pointer on current input index -* vl, vr : left and right gain -* phaseFraction : pointer on current phase fraction -* phaseIncrement -* Ouput: -* outputIndex : -* out : updated buffer -* inputIndex : index of next to use -* phaseFraction : phase fraction for next interpolation -* -*******************************************************************/ -void AudioResamplerOrder1::AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, - size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, - uint32_t &phaseFraction, uint32_t phaseIncrement) -{ -#define MO_PARAM5 "36" // offset of parameter 5 (outputIndex) - - asm( - "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n" - // get parameters - " ldr r6, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction - " ldr r6, [r6]\n" // phaseFraction - " ldr r7, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex - " ldr r7, [r7]\n" // inputIndex - " ldr r8, [sp, #" MO_PARAM5 " + 4]\n" // out - " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex - " ldr r0, [r0]\n" // outputIndex - " add r8, r0, asl #2\n" // curOut - " ldr r9, [sp, #" MO_PARAM5 " + 24]\n" // phaseIncrement - " ldr r10, [sp, #" MO_PARAM5 " + 12]\n" // vl - " ldr r11, [sp, #" MO_PARAM5 " + 16]\n" // vr - - // r0 pin, x0, Samp - - // r1 in - // r2 maxOutPt - // r3 maxInIdx - - // r4 x1, i1, i3, Out1 - // r5 out0 - - // r6 frac - // r7 inputIndex - // r8 curOut - - // r9 inc - // r10 vl - // r11 vr - - // r12 - // r13 sp - // r14 - - // the following loop works on 2 frames - - ".Y4L01:\n" - " cmp r8, r2\n" // curOut - maxCurOut - " bcs .Y4L02\n" - -#define MO_ONE_FRAME \ - " add r0, r1, r7, asl #1\n" /* in + inputIndex */\ - " ldrsh r4, [r0]\n" /* in[inputIndex] */\ - " ldr r5, [r8]\n" /* out[outputIndex] */\ - " ldrsh r0, [r0, #-2]\n" /* in[inputIndex-1] */\ - " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\ - " sub r4, r4, r0\n" /* in[inputIndex] - in[inputIndex-1] */\ - " mov r4, r4, lsl #2\n" /* <<2 */\ - " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\ - " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\ - " add r0, r0, r4\n" /* x0 - (..) */\ - " mla r5, r0, r10, r5\n" /* vl*interp + out[] */\ - " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\ - " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\ - " mla r4, r0, r11, r4\n" /* vr*interp + out[] */\ - " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */\ - " str r4, [r8], #4\n" /* out[outputIndex++] = ... */ - - MO_ONE_FRAME // frame 1 - MO_ONE_FRAME // frame 2 - - " cmp r7, r3\n" // inputIndex - maxInIdx - " bcc .Y4L01\n" - ".Y4L02:\n" - - " bic r6, r6, #0xC0000000\n" // phaseFraction & ... - // save modified values - " ldr r0, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction - " str r6, [r0]\n" // phaseFraction - " ldr r0, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex - " str r7, [r0]\n" // inputIndex - " ldr r0, [sp, #" MO_PARAM5 " + 4]\n" // out - " sub r8, r0\n" // curOut - out - " asr r8, #2\n" // new outputIndex - " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex - " str r8, [r0]\n" // save outputIndex - - " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n" - ); -} - -/******************************************************************* -* -* AsmStereo16Loop -* asm optimized stereo loop version; one loop is 2 frames -* Input: -* in : pointer on input samples -* maxOutPt : pointer on first not filled -* maxInIdx : index on first not used -* outputIndex : pointer on current output index -* out : pointer on output buffer -* inputIndex : pointer on current input index -* vl, vr : left and right gain -* phaseFraction : pointer on current phase fraction -* phaseIncrement -* Ouput: -* outputIndex : -* out : updated buffer -* inputIndex : index of next to use -* phaseFraction : phase fraction for next interpolation -* -*******************************************************************/ -void AudioResamplerOrder1::AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, - size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, - uint32_t &phaseFraction, uint32_t phaseIncrement) -{ -#define ST_PARAM5 "40" // offset of parameter 5 (outputIndex) - asm( - "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n" - // get parameters - " ldr r6, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction - " ldr r6, [r6]\n" // phaseFraction - " ldr r7, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex - " ldr r7, [r7]\n" // inputIndex - " ldr r8, [sp, #" ST_PARAM5 " + 4]\n" // out - " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex - " ldr r0, [r0]\n" // outputIndex - " add r8, r0, asl #2\n" // curOut - " ldr r9, [sp, #" ST_PARAM5 " + 24]\n" // phaseIncrement - " ldr r10, [sp, #" ST_PARAM5 " + 12]\n" // vl - " ldr r11, [sp, #" ST_PARAM5 " + 16]\n" // vr - - // r0 pin, x0, Samp - - // r1 in - // r2 maxOutPt - // r3 maxInIdx - - // r4 x1, i1, i3, out1 - // r5 out0 - - // r6 frac - // r7 inputIndex - // r8 curOut - - // r9 inc - // r10 vl - // r11 vr - - // r12 temporary - // r13 sp - // r14 - - ".Y5L01:\n" - " cmp r8, r2\n" // curOut - maxCurOut - " bcs .Y5L02\n" - -#define ST_ONE_FRAME \ - " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\ -\ - " add r0, r1, r7, asl #2\n" /* in + 2*inputIndex */\ -\ - " ldrsh r4, [r0]\n" /* in[2*inputIndex] */\ - " ldr r5, [r8]\n" /* out[outputIndex] */\ - " ldrsh r12, [r0, #-4]\n" /* in[2*inputIndex-2] */\ - " sub r4, r4, r12\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\ - " mov r4, r4, lsl #2\n" /* <<2 */\ - " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\ - " add r12, r12, r4\n" /* x0 - (..) */\ - " mla r5, r12, r10, r5\n" /* vl*interp + out[] */\ - " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\ - " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\ -\ - " ldrsh r12, [r0, #+2]\n" /* in[2*inputIndex+1] */\ - " ldrsh r0, [r0, #-2]\n" /* in[2*inputIndex-1] */\ - " sub r12, r12, r0\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\ - " mov r12, r12, lsl #2\n" /* <<2 */\ - " smulwt r12, r12, r6\n" /* (x1-x0)*.. */\ - " add r12, r0, r12\n" /* x0 - (..) */\ - " mla r4, r12, r11, r4\n" /* vr*interp + out[] */\ - " str r4, [r8], #4\n" /* out[outputIndex++] = ... */\ -\ - " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\ - " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */ - - ST_ONE_FRAME // frame 1 - ST_ONE_FRAME // frame 1 - - " cmp r7, r3\n" // inputIndex - maxInIdx - " bcc .Y5L01\n" - ".Y5L02:\n" - - " bic r6, r6, #0xC0000000\n" // phaseFraction & ... - // save modified values - " ldr r0, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction - " str r6, [r0]\n" // phaseFraction - " ldr r0, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex - " str r7, [r0]\n" // inputIndex - " ldr r0, [sp, #" ST_PARAM5 " + 4]\n" // out - " sub r8, r0\n" // curOut - out - " asr r8, #2\n" // new outputIndex - " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex - " str r8, [r0]\n" // save outputIndex - - " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, pc}\n" - ); -} - -#endif // ASM_ARM_RESAMP1 - - -// ---------------------------------------------------------------------------- -} -; // namespace android - diff --git a/libs/audioflinger/AudioResampler.h b/libs/audioflinger/AudioResampler.h deleted file mode 100644 index 2dfac76..0000000 --- a/libs/audioflinger/AudioResampler.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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. - */ - -#ifndef ANDROID_AUDIO_RESAMPLER_H -#define ANDROID_AUDIO_RESAMPLER_H - -#include <stdint.h> -#include <sys/types.h> - -#include "AudioBufferProvider.h" - -namespace android { -// ---------------------------------------------------------------------------- - -class AudioResampler { -public: - // Determines quality of SRC. - // LOW_QUALITY: linear interpolator (1st order) - // MED_QUALITY: cubic interpolator (3rd order) - // HIGH_QUALITY: fixed multi-tap FIR (e.g. 48KHz->44.1KHz) - // NOTE: high quality SRC will only be supported for - // certain fixed rate conversions. Sample rate cannot be - // changed dynamically. - enum src_quality { - DEFAULT=0, - LOW_QUALITY=1, - MED_QUALITY=2, - HIGH_QUALITY=3 - }; - - static AudioResampler* create(int bitDepth, int inChannelCount, - int32_t sampleRate, int quality=DEFAULT); - - virtual ~AudioResampler(); - - virtual void init() = 0; - virtual void setSampleRate(int32_t inSampleRate); - virtual void setVolume(int16_t left, int16_t right); - - virtual void resample(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider) = 0; - -protected: - // number of bits for phase fraction - 30 bits allows nearly 2x downsampling - static const int kNumPhaseBits = 30; - - // phase mask for fraction - static const uint32_t kPhaseMask = (1LU<<kNumPhaseBits)-1; - - // multiplier to calculate fixed point phase increment - static const double kPhaseMultiplier = 1L << kNumPhaseBits; - - enum format {MONO_16_BIT, STEREO_16_BIT}; - AudioResampler(int bitDepth, int inChannelCount, int32_t sampleRate); - - // prevent copying - AudioResampler(const AudioResampler&); - AudioResampler& operator=(const AudioResampler&); - - int32_t mBitDepth; - int32_t mChannelCount; - int32_t mSampleRate; - int32_t mInSampleRate; - AudioBufferProvider::Buffer mBuffer; - union { - int16_t mVolume[2]; - uint32_t mVolumeRL; - }; - int16_t mTargetVolume[2]; - format mFormat; - size_t mInputIndex; - int32_t mPhaseIncrement; - uint32_t mPhaseFraction; -}; - -// ---------------------------------------------------------------------------- -} -; // namespace android - -#endif // ANDROID_AUDIO_RESAMPLER_H diff --git a/libs/audioflinger/AudioResamplerCubic.cpp b/libs/audioflinger/AudioResamplerCubic.cpp deleted file mode 100644 index 1d247bd..0000000 --- a/libs/audioflinger/AudioResamplerCubic.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* - * 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 <string.h> -#include <sys/types.h> -#include <cutils/log.h> - -#include "AudioResampler.h" -#include "AudioResamplerCubic.h" - -#define LOG_TAG "AudioSRC" - -namespace android { -// ---------------------------------------------------------------------------- - -void AudioResamplerCubic::init() { - memset(&left, 0, sizeof(state)); - memset(&right, 0, sizeof(state)); -} - -void AudioResamplerCubic::resample(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider) { - - // should never happen, but we overflow if it does - // LOG_ASSERT(outFrameCount < 32767); - - // select the appropriate resampler - switch (mChannelCount) { - case 1: - resampleMono16(out, outFrameCount, provider); - break; - case 2: - resampleStereo16(out, outFrameCount, provider); - break; - } -} - -void AudioResamplerCubic::resampleStereo16(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider) { - - int32_t vl = mVolume[0]; - int32_t vr = mVolume[1]; - - size_t inputIndex = mInputIndex; - uint32_t phaseFraction = mPhaseFraction; - uint32_t phaseIncrement = mPhaseIncrement; - size_t outputIndex = 0; - size_t outputSampleCount = outFrameCount * 2; - size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate; - - // fetch first buffer - if (mBuffer.frameCount == 0) { - mBuffer.frameCount = inFrameCount; - provider->getNextBuffer(&mBuffer); - if (mBuffer.raw == NULL) - return; - // LOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount); - } - int16_t *in = mBuffer.i16; - - while (outputIndex < outputSampleCount) { - int32_t sample; - int32_t x; - - // calculate output sample - x = phaseFraction >> kPreInterpShift; - out[outputIndex++] += vl * interp(&left, x); - out[outputIndex++] += vr * interp(&right, x); - // out[outputIndex++] += vr * in[inputIndex*2]; - - // increment phase - phaseFraction += phaseIncrement; - uint32_t indexIncrement = (phaseFraction >> kNumPhaseBits); - phaseFraction &= kPhaseMask; - - // time to fetch another sample - while (indexIncrement--) { - - inputIndex++; - if (inputIndex == mBuffer.frameCount) { - inputIndex = 0; - provider->releaseBuffer(&mBuffer); - mBuffer.frameCount = inFrameCount; - provider->getNextBuffer(&mBuffer); - if (mBuffer.raw == NULL) - goto save_state; // ugly, but efficient - in = mBuffer.i16; - // LOGW("New buffer: offset=%p, frames=%d\n", mBuffer.raw, mBuffer.frameCount); - } - - // advance sample state - advance(&left, in[inputIndex*2]); - advance(&right, in[inputIndex*2+1]); - } - } - -save_state: - // LOGW("Done: index=%d, fraction=%u", inputIndex, phaseFraction); - mInputIndex = inputIndex; - mPhaseFraction = phaseFraction; -} - -void AudioResamplerCubic::resampleMono16(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider) { - - int32_t vl = mVolume[0]; - int32_t vr = mVolume[1]; - - size_t inputIndex = mInputIndex; - uint32_t phaseFraction = mPhaseFraction; - uint32_t phaseIncrement = mPhaseIncrement; - size_t outputIndex = 0; - size_t outputSampleCount = outFrameCount * 2; - size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate; - - // fetch first buffer - if (mBuffer.frameCount == 0) { - mBuffer.frameCount = inFrameCount; - provider->getNextBuffer(&mBuffer); - if (mBuffer.raw == NULL) - return; - // LOGW("New buffer: offset=%p, frames=%d\n", mBuffer.raw, mBuffer.frameCount); - } - int16_t *in = mBuffer.i16; - - while (outputIndex < outputSampleCount) { - int32_t sample; - int32_t x; - - // calculate output sample - x = phaseFraction >> kPreInterpShift; - sample = interp(&left, x); - out[outputIndex++] += vl * sample; - out[outputIndex++] += vr * sample; - - // increment phase - phaseFraction += phaseIncrement; - uint32_t indexIncrement = (phaseFraction >> kNumPhaseBits); - phaseFraction &= kPhaseMask; - - // time to fetch another sample - while (indexIncrement--) { - - inputIndex++; - if (inputIndex == mBuffer.frameCount) { - inputIndex = 0; - provider->releaseBuffer(&mBuffer); - mBuffer.frameCount = inFrameCount; - provider->getNextBuffer(&mBuffer); - if (mBuffer.raw == NULL) - goto save_state; // ugly, but efficient - // LOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount); - in = mBuffer.i16; - } - - // advance sample state - advance(&left, in[inputIndex]); - } - } - -save_state: - // LOGW("Done: index=%d, fraction=%u", inputIndex, phaseFraction); - mInputIndex = inputIndex; - mPhaseFraction = phaseFraction; -} - -// ---------------------------------------------------------------------------- -} -; // namespace android - diff --git a/libs/audioflinger/AudioResamplerCubic.h b/libs/audioflinger/AudioResamplerCubic.h deleted file mode 100644 index b72b62a..0000000 --- a/libs/audioflinger/AudioResamplerCubic.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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. - */ - -#ifndef ANDROID_AUDIO_RESAMPLER_CUBIC_H -#define ANDROID_AUDIO_RESAMPLER_CUBIC_H - -#include <stdint.h> -#include <sys/types.h> -#include <cutils/log.h> - -#include "AudioResampler.h" - -namespace android { -// ---------------------------------------------------------------------------- - -class AudioResamplerCubic : public AudioResampler { -public: - AudioResamplerCubic(int bitDepth, int inChannelCount, int32_t sampleRate) : - AudioResampler(bitDepth, inChannelCount, sampleRate) { - } - virtual void resample(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider); -private: - // number of bits used in interpolation multiply - 14 bits avoids overflow - static const int kNumInterpBits = 14; - - // bits to shift the phase fraction down to avoid overflow - static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits; - typedef struct { - int32_t a, b, c, y0, y1, y2, y3; - } state; - void init(); - void resampleMono16(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider); - void resampleStereo16(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider); - static inline int32_t interp(state* p, int32_t x) { - return (((((p->a * x >> 14) + p->b) * x >> 14) + p->c) * x >> 14) + p->y1; - } - static inline void advance(state* p, int16_t in) { - p->y0 = p->y1; - p->y1 = p->y2; - p->y2 = p->y3; - p->y3 = in; - p->a = (3 * (p->y1 - p->y2) - p->y0 + p->y3) >> 1; - p->b = (p->y2 << 1) + p->y0 - (((5 * p->y1 + p->y3)) >> 1); - p->c = (p->y2 - p->y0) >> 1; - } - state left, right; -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif /*ANDROID_AUDIO_RESAMPLER_CUBIC_H*/ diff --git a/libs/audioflinger/AudioResamplerSinc.cpp b/libs/audioflinger/AudioResamplerSinc.cpp deleted file mode 100644 index 9e5e254..0000000 --- a/libs/audioflinger/AudioResamplerSinc.cpp +++ /dev/null @@ -1,358 +0,0 @@ -/* - * 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 <string.h> -#include "AudioResamplerSinc.h" - -namespace android { -// ---------------------------------------------------------------------------- - - -/* - * These coeficients are computed with the "fir" utility found in - * tools/resampler_tools - * TODO: A good optimization would be to transpose this matrix, to take - * better advantage of the data-cache. - */ -const int32_t AudioResamplerSinc::mFirCoefsUp[] = { - 0x7fffffff, 0x7f15d078, 0x7c5e0da6, 0x77ecd867, 0x71e2e251, 0x6a6c304a, 0x61be7269, 0x58170412, 0x4db8ab05, 0x42e92ea6, 0x37eee214, 0x2d0e3bb1, 0x22879366, 0x18951e95, 0x0f693d0d, 0x072d2621, - 0x00000000, 0xf9f66655, 0xf51a5fd7, 0xf16bbd84, 0xeee0d9ac, 0xed67a922, 0xece70de6, 0xed405897, 0xee50e505, 0xeff3be30, 0xf203370f, 0xf45a6741, 0xf6d67d53, 0xf957db66, 0xfbc2f647, 0xfe00f2b9, - 0x00000000, 0x01b37218, 0x0313a0c6, 0x041d930d, 0x04d28057, 0x053731b0, 0x05534dff, 0x05309bfd, 0x04da440d, 0x045c1aee, 0x03c1fcdd, 0x03173ef5, 0x02663ae8, 0x01b7f736, 0x0113ec79, 0x007fe6a9, - 0x00000000, 0xff96b229, 0xff44f99f, 0xff0a86be, 0xfee5f803, 0xfed518fd, 0xfed521fd, 0xfee2f4fd, 0xfefb54f8, 0xff1b159b, 0xff3f4203, 0xff6539e0, 0xff8ac502, 0xffae1ddd, 0xffcdf3f9, 0xffe96798, - 0x00000000, 0x00119de6, 0x001e6b7e, 0x0026cb7a, 0x002b4830, 0x002c83d6, 0x002b2a82, 0x0027e67a, 0x002356f9, 0x001e098e, 0x001875e4, 0x0012fbbe, 0x000de2d1, 0x00095c10, 0x00058414, 0x00026636, - 0x00000000, 0xfffe44a9, 0xfffd206d, 0xfffc7b7f, 0xfffc3c8f, 0xfffc4ac2, 0xfffc8f2b, 0xfffcf5c4, 0xfffd6df3, 0xfffdeab2, 0xfffe6275, 0xfffececf, 0xffff2c07, 0xffff788c, 0xffffb471, 0xffffe0f2, - 0x00000000, 0x000013e6, 0x00001f03, 0x00002396, 0x00002399, 0x000020b6, 0x00001c3c, 0x00001722, 0x00001216, 0x00000d81, 0x0000099c, 0x0000067c, 0x00000419, 0x0000025f, 0x00000131, 0x00000070, - 0x00000000, 0xffffffc7, 0xffffffb3, 0xffffffb3, 0xffffffbe, 0xffffffcd, 0xffffffdb, 0xffffffe7, 0xfffffff0, 0xfffffff7, 0xfffffffb, 0xfffffffe, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000 // this one is needed for lerping the last coefficient -}; - -/* - * These coefficients are optimized for 48KHz -> 44.1KHz (stop-band at 22.050KHz) - * It's possible to use the above coefficient for any down-sampling - * at the expense of a slower processing loop (we can interpolate - * these coefficient from the above by "Stretching" them in time). - */ -const int32_t AudioResamplerSinc::mFirCoefsDown[] = { - 0x7fffffff, 0x7f55e46d, 0x7d5b4c60, 0x7a1b4b98, 0x75a7fb14, 0x7019f0bd, 0x698f875a, 0x622bfd59, 0x5a167256, 0x5178cc54, 0x487e8e6c, 0x3f53aae8, 0x36235ad4, 0x2d17047b, 0x245539ab, 0x1c00d540, - 0x14383e57, 0x0d14d5ca, 0x06aa910b, 0x0107c38b, 0xfc351654, 0xf835abae, 0xf5076b45, 0xf2a37202, 0xf0fe9faa, 0xf00a3bbd, 0xefb4aa81, 0xefea2b05, 0xf0959716, 0xf1a11e83, 0xf2f6f7a0, 0xf481fff4, - 0xf62e48ce, 0xf7e98ca5, 0xf9a38b4c, 0xfb4e4bfa, 0xfcde456f, 0xfe4a6d30, 0xff8c2fdf, 0x009f5555, 0x0181d393, 0x0233940f, 0x02b62f06, 0x030ca07d, 0x033afa62, 0x03461725, 0x03334f83, 0x030835fa, - 0x02ca59cc, 0x027f12d1, 0x022b570d, 0x01d39a49, 0x017bb78f, 0x0126e414, 0x00d7aaaf, 0x008feec7, 0x0050f584, 0x001b73e3, 0xffefa063, 0xffcd46ed, 0xffb3ddcd, 0xffa29aaa, 0xff988691, 0xff949066, - 0xff959d24, 0xff9a959e, 0xffa27195, 0xffac4011, 0xffb72d2b, 0xffc28569, 0xffcdb706, 0xffd85171, 0xffe20364, 0xffea97e9, 0xfff1f2b2, 0xfff80c06, 0xfffcec92, 0x0000a955, 0x00035fd8, 0x000532cf, - 0x00064735, 0x0006c1f9, 0x0006c62d, 0x000673ba, 0x0005e68f, 0x00053630, 0x000475a3, 0x0003b397, 0x0002fac1, 0x00025257, 0x0001be9e, 0x0001417a, 0x0000dafd, 0x000089eb, 0x00004c28, 0x00001f1d, - 0x00000000, 0xffffec10, 0xffffe0be, 0xffffdbc5, 0xffffdb39, 0xffffdd8b, 0xffffe182, 0xffffe638, 0xffffeb0a, 0xffffef8f, 0xfffff38b, 0xfffff6e3, 0xfffff993, 0xfffffba6, 0xfffffd30, 0xfffffe4a, - 0xffffff09, 0xffffff85, 0xffffffd1, 0xfffffffb, 0x0000000f, 0x00000016, 0x00000015, 0x00000012, 0x0000000d, 0x00000009, 0x00000006, 0x00000003, 0x00000002, 0x00000001, 0x00000000, 0x00000000, - 0x00000000 // this one is needed for lerping the last coefficient -}; - -// ---------------------------------------------------------------------------- - -static inline -int32_t mulRL(int left, int32_t in, uint32_t vRL) -{ -#if defined(__arm__) && !defined(__thumb__) - int32_t out; - if (left) { - asm( "smultb %[out], %[in], %[vRL] \n" - : [out]"=r"(out) - : [in]"%r"(in), [vRL]"r"(vRL) - : ); - } else { - asm( "smultt %[out], %[in], %[vRL] \n" - : [out]"=r"(out) - : [in]"%r"(in), [vRL]"r"(vRL) - : ); - } - return out; -#else - if (left) { - return int16_t(in>>16) * int16_t(vRL&0xFFFF); - } else { - return int16_t(in>>16) * int16_t(vRL>>16); - } -#endif -} - -static inline -int32_t mulAdd(int16_t in, int32_t v, int32_t a) -{ -#if defined(__arm__) && !defined(__thumb__) - int32_t out; - asm( "smlawb %[out], %[v], %[in], %[a] \n" - : [out]"=r"(out) - : [in]"%r"(in), [v]"r"(v), [a]"r"(a) - : ); - return out; -#else - return a + in * (v>>16); - // improved precision - // return a + in * (v>>16) + ((in * (v & 0xffff)) >> 16); -#endif -} - -static inline -int32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a) -{ -#if defined(__arm__) && !defined(__thumb__) - int32_t out; - if (left) { - asm( "smlawb %[out], %[v], %[inRL], %[a] \n" - : [out]"=r"(out) - : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a) - : ); - } else { - asm( "smlawt %[out], %[v], %[inRL], %[a] \n" - : [out]"=r"(out) - : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a) - : ); - } - return out; -#else - if (left) { - return a + (int16_t(inRL&0xFFFF) * (v>>16)); - //improved precision - // return a + (int16_t(inRL&0xFFFF) * (v>>16)) + ((int16_t(inRL&0xFFFF) * (v & 0xffff)) >> 16); - } else { - return a + (int16_t(inRL>>16) * (v>>16)); - } -#endif -} - -// ---------------------------------------------------------------------------- - -AudioResamplerSinc::AudioResamplerSinc(int bitDepth, - int inChannelCount, int32_t sampleRate) - : AudioResampler(bitDepth, inChannelCount, sampleRate), - mState(0) -{ - /* - * Layout of the state buffer for 32 tap: - * - * "present" sample beginning of 2nd buffer - * v v - * 0 01 2 23 3 - * 0 F0 0 F0 F - * [pppppppppppppppInnnnnnnnnnnnnnnnpppppppppppppppInnnnnnnnnnnnnnnn] - * ^ ^ head - * - * p = past samples, convoluted with the (p)ositive side of sinc() - * n = future samples, convoluted with the (n)egative side of sinc() - * r = extra space for implementing the ring buffer - * - */ - - const size_t numCoefs = 2*halfNumCoefs; - const size_t stateSize = numCoefs * inChannelCount * 2; - mState = new int16_t[stateSize]; - memset(mState, 0, sizeof(int16_t)*stateSize); - mImpulse = mState + (halfNumCoefs-1)*inChannelCount; - mRingFull = mImpulse + (numCoefs+1)*inChannelCount; -} - -AudioResamplerSinc::~AudioResamplerSinc() -{ - delete [] mState; -} - -void AudioResamplerSinc::init() { -} - -void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider) -{ - mFirCoefs = (mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown; - - // select the appropriate resampler - switch (mChannelCount) { - case 1: - resample<1>(out, outFrameCount, provider); - break; - case 2: - resample<2>(out, outFrameCount, provider); - break; - } -} - - -template<int CHANNELS> -void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider) -{ - int16_t* impulse = mImpulse; - uint32_t vRL = mVolumeRL; - size_t inputIndex = mInputIndex; - uint32_t phaseFraction = mPhaseFraction; - uint32_t phaseIncrement = mPhaseIncrement; - size_t outputIndex = 0; - size_t outputSampleCount = outFrameCount * 2; - size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate; - - AudioBufferProvider::Buffer& buffer(mBuffer); - while (outputIndex < outputSampleCount) { - // buffer is empty, fetch a new one - while (buffer.frameCount == 0) { - buffer.frameCount = inFrameCount; - provider->getNextBuffer(&buffer); - if (buffer.raw == NULL) { - goto resample_exit; - } - const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits; - if (phaseIndex == 1) { - // read one frame - read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex); - } else if (phaseIndex == 2) { - // read 2 frames - read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex); - inputIndex++; - if (inputIndex >= mBuffer.frameCount) { - inputIndex -= mBuffer.frameCount; - provider->releaseBuffer(&buffer); - } else { - read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex); - } - } - } - int16_t *in = buffer.i16; - const size_t frameCount = buffer.frameCount; - - // Always read-in the first samples from the input buffer - int16_t* head = impulse + halfNumCoefs*CHANNELS; - head[0] = in[inputIndex*CHANNELS + 0]; - if (CHANNELS == 2) - head[1] = in[inputIndex*CHANNELS + 1]; - - // handle boundary case - int32_t l, r; - while (outputIndex < outputSampleCount) { - filterCoefficient<CHANNELS>(l, r, phaseFraction, impulse); - out[outputIndex++] += 2 * mulRL(1, l, vRL); - out[outputIndex++] += 2 * mulRL(0, r, vRL); - - phaseFraction += phaseIncrement; - const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits; - if (phaseIndex == 1) { - inputIndex++; - if (inputIndex >= frameCount) - break; // need a new buffer - read<CHANNELS>(impulse, phaseFraction, in, inputIndex); - } else if(phaseIndex == 2) { // maximum value - inputIndex++; - if (inputIndex >= frameCount) - break; // 0 frame available, 2 frames needed - // read first frame - read<CHANNELS>(impulse, phaseFraction, in, inputIndex); - inputIndex++; - if (inputIndex >= frameCount) - break; // 0 frame available, 1 frame needed - // read second frame - read<CHANNELS>(impulse, phaseFraction, in, inputIndex); - } - } - - // if done with buffer, save samples - if (inputIndex >= frameCount) { - inputIndex -= frameCount; - provider->releaseBuffer(&buffer); - } - } - -resample_exit: - mImpulse = impulse; - mInputIndex = inputIndex; - mPhaseFraction = phaseFraction; -} - -template<int CHANNELS> -/*** -* read() -* -* This function reads only one frame from input buffer and writes it in -* state buffer -* -**/ -void AudioResamplerSinc::read( - int16_t*& impulse, uint32_t& phaseFraction, - int16_t const* in, size_t inputIndex) -{ - const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits; - impulse += CHANNELS; - phaseFraction -= 1LU<<kNumPhaseBits; - if (impulse >= mRingFull) { - const size_t stateSize = (halfNumCoefs*2)*CHANNELS; - memcpy(mState, mState+stateSize, sizeof(int16_t)*stateSize); - impulse -= stateSize; - } - int16_t* head = impulse + halfNumCoefs*CHANNELS; - head[0] = in[inputIndex*CHANNELS + 0]; - if (CHANNELS == 2) - head[1] = in[inputIndex*CHANNELS + 1]; -} - -template<int CHANNELS> -void AudioResamplerSinc::filterCoefficient( - int32_t& l, int32_t& r, uint32_t phase, int16_t const *samples) -{ - // compute the index of the coefficient on the positive side and - // negative side - uint32_t indexP = (phase & cMask) >> cShift; - uint16_t lerpP = (phase & pMask) >> pShift; - uint32_t indexN = (-phase & cMask) >> cShift; - uint16_t lerpN = (-phase & pMask) >> pShift; - if ((indexP == 0) && (lerpP == 0)) { - indexN = cMask >> cShift; - lerpN = pMask >> pShift; - } - - l = 0; - r = 0; - int32_t const* coefs = mFirCoefs; - int16_t const *sP = samples; - int16_t const *sN = samples+CHANNELS; - for (unsigned int i=0 ; i<halfNumCoefs/4 ; i++) { - interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP); - interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN); - sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits; - interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP); - interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN); - sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits; - interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP); - interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN); - sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits; - interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP); - interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN); - sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits; - } -} - -template<int CHANNELS> -void AudioResamplerSinc::interpolate( - int32_t& l, int32_t& r, - int32_t const* coefs, int16_t lerp, int16_t const* samples) -{ - int32_t c0 = coefs[0]; - int32_t c1 = coefs[1]; - int32_t sinc = mulAdd(lerp, (c1-c0)<<1, c0); - if (CHANNELS == 2) { - uint32_t rl = *reinterpret_cast<uint32_t const*>(samples); - l = mulAddRL(1, rl, sinc, l); - r = mulAddRL(0, rl, sinc, r); - } else { - r = l = mulAdd(samples[0], sinc, l); - } -} - -// ---------------------------------------------------------------------------- -}; // namespace android - diff --git a/libs/audioflinger/AudioResamplerSinc.h b/libs/audioflinger/AudioResamplerSinc.h deleted file mode 100644 index e6cb90b..0000000 --- a/libs/audioflinger/AudioResamplerSinc.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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. - */ - -#ifndef ANDROID_AUDIO_RESAMPLER_SINC_H -#define ANDROID_AUDIO_RESAMPLER_SINC_H - -#include <stdint.h> -#include <sys/types.h> -#include <cutils/log.h> - -#include "AudioResampler.h" - -namespace android { - -// ---------------------------------------------------------------------------- - -class AudioResamplerSinc : public AudioResampler { -public: - AudioResamplerSinc(int bitDepth, int inChannelCount, int32_t sampleRate); - - ~AudioResamplerSinc(); - - virtual void resample(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider); -private: - void init(); - - template<int CHANNELS> - void resample(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider); - - template<int CHANNELS> - inline void filterCoefficient( - int32_t& l, int32_t& r, uint32_t phase, int16_t const *samples); - - template<int CHANNELS> - inline void interpolate( - int32_t& l, int32_t& r, - int32_t const* coefs, int16_t lerp, int16_t const* samples); - - template<int CHANNELS> - inline void read(int16_t*& impulse, uint32_t& phaseFraction, - int16_t const* in, size_t inputIndex); - - int16_t *mState; - int16_t *mImpulse; - int16_t *mRingFull; - - int32_t const * mFirCoefs; - static const int32_t mFirCoefsDown[]; - static const int32_t mFirCoefsUp[]; - - // ---------------------------------------------------------------------------- - static const int32_t RESAMPLE_FIR_NUM_COEF = 8; - static const int32_t RESAMPLE_FIR_LERP_INT_BITS = 4; - - // we have 16 coefs samples per zero-crossing - static const int coefsBits = RESAMPLE_FIR_LERP_INT_BITS; // 4 - static const int cShift = kNumPhaseBits - coefsBits; // 26 - static const uint32_t cMask = ((1<<coefsBits)-1) << cShift; // 0xf<<26 = 3c00 0000 - - // and we use 15 bits to interpolate between these samples - // this cannot change because the mul below rely on it. - static const int pLerpBits = 15; - static const int pShift = kNumPhaseBits - coefsBits - pLerpBits; // 11 - static const uint32_t pMask = ((1<<pLerpBits)-1) << pShift; // 0x7fff << 11 - - // number of zero-crossing on each side - static const unsigned int halfNumCoefs = RESAMPLE_FIR_NUM_COEF; -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif /*ANDROID_AUDIO_RESAMPLER_SINC_H*/ diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk deleted file mode 100644 index a14bfb5..0000000 --- a/libs/surfaceflinger/Android.mk +++ /dev/null @@ -1,52 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - clz.cpp.arm \ - DisplayHardware/DisplayHardware.cpp \ - DisplayHardware/DisplayHardwareBase.cpp \ - BlurFilter.cpp.arm \ - GLExtensions.cpp \ - Layer.cpp \ - LayerBase.cpp \ - LayerBuffer.cpp \ - LayerBlur.cpp \ - LayerDim.cpp \ - MessageQueue.cpp \ - SurfaceFlinger.cpp \ - TextureManager.cpp \ - Transform.cpp - -LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\" -LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES - -ifeq ($(TARGET_BOARD_PLATFORM), omap3) - LOCAL_CFLAGS += -DNO_RGBX_8888 -endif - -# need "-lrt" on Linux simulator to pick up clock_gettime -ifeq ($(TARGET_SIMULATOR),true) - ifeq ($(HOST_OS),linux) - LOCAL_LDLIBS += -lrt -lpthread - endif -endif - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libpixelflinger \ - libhardware \ - libutils \ - libEGL \ - libGLESv1_CM \ - libbinder \ - libui \ - libsurfaceflinger_client - -LOCAL_C_INCLUDES := \ - $(call include-path-for, corecg graphics) - -LOCAL_C_INCLUDES += hardware/libhardware/modules/gralloc - -LOCAL_MODULE:= libsurfaceflinger - -include $(BUILD_SHARED_LIBRARY) diff --git a/libs/surfaceflinger/Barrier.h b/libs/surfaceflinger/Barrier.h deleted file mode 100644 index 6f8507e..0000000 --- a/libs/surfaceflinger/Barrier.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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. - */ - -#ifndef ANDROID_BARRIER_H -#define ANDROID_BARRIER_H - -#include <stdint.h> -#include <sys/types.h> -#include <utils/threads.h> - -namespace android { - -class Barrier -{ -public: - inline Barrier() : state(CLOSED) { } - inline ~Barrier() { } - void open() { - Mutex::Autolock _l(lock); - state = OPENED; - cv.broadcast(); - } - void close() { - Mutex::Autolock _l(lock); - state = CLOSED; - } - void wait() const { - Mutex::Autolock _l(lock); - while (state == CLOSED) { - cv.wait(lock); - } - } -private: - enum { OPENED, CLOSED }; - mutable Mutex lock; - mutable Condition cv; - volatile int state; -}; - -}; // namespace android - -#endif // ANDROID_BARRIER_H diff --git a/libs/surfaceflinger/BlurFilter.cpp b/libs/surfaceflinger/BlurFilter.cpp deleted file mode 100644 index 1ffbd5b..0000000 --- a/libs/surfaceflinger/BlurFilter.cpp +++ /dev/null @@ -1,376 +0,0 @@ -/* -** -** Copyright 2006, 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 <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <stdint.h> -#include <utils/Errors.h> - -#include <pixelflinger/pixelflinger.h> - -#include "clz.h" - -#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) -#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) - -namespace android { - -#if BYTE_ORDER == LITTLE_ENDIAN -inline uint32_t BLUR_RGBA_TO_HOST(uint32_t v) { - return v; -} -inline uint32_t BLUR_HOST_TO_RGBA(uint32_t v) { - return v; -} -#else -inline uint32_t BLUR_RGBA_TO_HOST(uint32_t v) { - return (v<<24) | (v>>24) | ((v<<8)&0xff0000) | ((v>>8)&0xff00); -} -inline uint32_t BLUR_HOST_TO_RGBA(uint32_t v) { - return (v<<24) | (v>>24) | ((v<<8)&0xff0000) | ((v>>8)&0xff00); -} -#endif - -const int BLUR_DITHER_BITS = 6; // dither weights stored on 6 bits -const int BLUR_DITHER_ORDER_SHIFT= 3; -const int BLUR_DITHER_ORDER = (1<<BLUR_DITHER_ORDER_SHIFT); -const int BLUR_DITHER_SIZE = BLUR_DITHER_ORDER * BLUR_DITHER_ORDER; -const int BLUR_DITHER_MASK = BLUR_DITHER_ORDER-1; - -static const uint8_t gDitherMatrix[BLUR_DITHER_SIZE] = { - 0, 32, 8, 40, 2, 34, 10, 42, - 48, 16, 56, 24, 50, 18, 58, 26, - 12, 44, 4, 36, 14, 46, 6, 38, - 60, 28, 52, 20, 62, 30, 54, 22, - 3, 35, 11, 43, 1, 33, 9, 41, - 51, 19, 59, 27, 49, 17, 57, 25, - 15, 47, 7, 39, 13, 45, 5, 37, - 63, 31, 55, 23, 61, 29, 53, 21 -}; - - -template <int FACTOR = 0> -struct BlurColor565 -{ - typedef uint16_t type; - int r, g, b; - inline BlurColor565() { } - inline BlurColor565(uint16_t v) { - r = v >> 11; - g = (v >> 5) & 0x3E; - b = v & 0x1F; - } - inline void clear() { r=g=b=0; } - inline uint16_t to(int shift, int last, int dither) const { - int R = r; - int G = g; - int B = b; - if (UNLIKELY(last)) { - if (FACTOR>0) { - int L = (R+G+B)>>1; - R += (((L>>1) - R) * FACTOR) >> 8; - G += (((L ) - G) * FACTOR) >> 8; - B += (((L>>1) - B) * FACTOR) >> 8; - } - R += (dither << shift) >> BLUR_DITHER_BITS; - G += (dither << shift) >> BLUR_DITHER_BITS; - B += (dither << shift) >> BLUR_DITHER_BITS; - } - R >>= shift; - G >>= shift; - B >>= shift; - return (R<<11) | (G<<5) | B; - } - inline BlurColor565& operator += (const BlurColor565& rhs) { - r += rhs.r; - g += rhs.g; - b += rhs.b; - return *this; - } - inline BlurColor565& operator -= (const BlurColor565& rhs) { - r -= rhs.r; - g -= rhs.g; - b -= rhs.b; - return *this; - } -}; - -template <int FACTOR = 0> -struct BlurColor888X -{ - typedef uint32_t type; - int r, g, b; - inline BlurColor888X() { } - inline BlurColor888X(uint32_t v) { - v = BLUR_RGBA_TO_HOST(v); - r = v & 0xFF; - g = (v >> 8) & 0xFF; - b = (v >> 16) & 0xFF; - } - inline void clear() { r=g=b=0; } - inline uint32_t to(int shift, int last, int dither) const { - int R = r; - int G = g; - int B = b; - if (UNLIKELY(last)) { - if (FACTOR>0) { - int L = (R+G+G+B)>>2; - R += ((L - R) * FACTOR) >> 8; - G += ((L - G) * FACTOR) >> 8; - B += ((L - B) * FACTOR) >> 8; - } - } - R >>= shift; - G >>= shift; - B >>= shift; - return BLUR_HOST_TO_RGBA((0xFF<<24) | (B<<16) | (G<<8) | R); - } - inline BlurColor888X& operator += (const BlurColor888X& rhs) { - r += rhs.r; - g += rhs.g; - b += rhs.b; - return *this; - } - inline BlurColor888X& operator -= (const BlurColor888X& rhs) { - r -= rhs.r; - g -= rhs.g; - b -= rhs.b; - return *this; - } -}; - -struct BlurGray565 -{ - typedef uint16_t type; - int l; - inline BlurGray565() { } - inline BlurGray565(uint16_t v) { - int r = v >> 11; - int g = (v >> 5) & 0x3F; - int b = v & 0x1F; - l = (r + g + b + 1)>>1; - } - inline void clear() { l=0; } - inline uint16_t to(int shift, int last, int dither) const { - int L = l; - if (UNLIKELY(last)) { - L += (dither << shift) >> BLUR_DITHER_BITS; - } - L >>= shift; - return ((L>>1)<<11) | (L<<5) | (L>>1); - } - inline BlurGray565& operator += (const BlurGray565& rhs) { - l += rhs.l; - return *this; - } - inline BlurGray565& operator -= (const BlurGray565& rhs) { - l -= rhs.l; - return *this; - } -}; - -struct BlurGray8888 -{ - typedef uint32_t type; - int l, a; - inline BlurGray8888() { } - inline BlurGray8888(uint32_t v) { - v = BLUR_RGBA_TO_HOST(v); - int r = v & 0xFF; - int g = (v >> 8) & 0xFF; - int b = (v >> 16) & 0xFF; - a = v >> 24; - l = r + g + g + b; - } - inline void clear() { l=a=0; } - inline uint32_t to(int shift, int last, int dither) const { - int L = l; - int A = a; - if (UNLIKELY(last)) { - L += (dither << (shift+2)) >> BLUR_DITHER_BITS; - A += (dither << shift) >> BLUR_DITHER_BITS; - } - L >>= (shift+2); - A >>= shift; - return BLUR_HOST_TO_RGBA((A<<24) | (L<<16) | (L<<8) | L); - } - inline BlurGray8888& operator += (const BlurGray8888& rhs) { - l += rhs.l; - a += rhs.a; - return *this; - } - inline BlurGray8888& operator -= (const BlurGray8888& rhs) { - l -= rhs.l; - a -= rhs.a; - return *this; - } -}; - - -template<typename PIXEL> -static status_t blurFilter( - GGLSurface const* dst, - GGLSurface const* src, - int kernelSizeUser, - int repeat) -{ - typedef typename PIXEL::type TYPE; - - const int shift = 31 - clz(kernelSizeUser); - const int areaShift = shift*2; - const int kernelSize = 1<<shift; - const int kernelHalfSize = kernelSize/2; - const int mask = kernelSize-1; - const int w = src->width; - const int h = src->height; - const uint8_t* ditherMatrix = gDitherMatrix; - - // we need a temporary buffer to store one line of blurred columns - // as well as kernelSize lines of source pixels organized as a ring buffer. - void* const temporary_buffer = malloc( - (w + kernelSize) * sizeof(PIXEL) + - (src->stride * kernelSize) * sizeof(TYPE)); - if (!temporary_buffer) - return NO_MEMORY; - - PIXEL* const sums = (PIXEL*)temporary_buffer; - TYPE* const scratch = (TYPE*)(sums + w + kernelSize); - - // Apply the blur 'repeat' times, this is used to approximate - // gaussian blurs. 3 times gives good results. - for (int k=0 ; k<repeat ; k++) { - - // Clear the columns sums for this round - memset(sums, 0, (w + kernelSize) * sizeof(PIXEL)); - TYPE* head; - TYPE pixel; - PIXEL current; - - // Since we're going to override the source data we need - // to copy it in a temporary buffer. Only kernelSize lines are - // required. But since we start in the center of the kernel, - // we only copy half of the data, and fill the rest with zeros - // (assuming black/transparent pixels). - memcpy( scratch + src->stride*kernelHalfSize, - src->data, - src->stride*kernelHalfSize*sizeof(TYPE)); - - // sum half of each column, because we assume the first half is - // zeros (black/transparent). - for (int y=0 ; y<kernelHalfSize ; y++) { - head = (TYPE*)src->data + y*src->stride; - for (int x=0 ; x<w ; x++) - sums[x] += PIXEL( *head++ ); - } - - for (int y=0 ; y<h ; y++) { - TYPE* fb = (TYPE*)dst->data + y*dst->stride; - - // compute the dither matrix line - uint8_t const * ditherY = ditherMatrix - + (y & BLUR_DITHER_MASK)*BLUR_DITHER_ORDER; - - // Horizontal blur pass on the columns sums - int count, dither, x=0; - PIXEL const * out= sums; - PIXEL const * in = sums; - current.clear(); - - count = kernelHalfSize; - do { - current += *in; - in++; - } while (--count); - - count = kernelHalfSize; - do { - current += *in; - dither = *(ditherY + ((x++)&BLUR_DITHER_MASK)); - *fb++ = current.to(areaShift, k==repeat-1, dither); - in++; - } while (--count); - - count = w-kernelSize; - do { - current += *in; - current -= *out; - dither = *(ditherY + ((x++)&BLUR_DITHER_MASK)); - *fb++ = current.to(areaShift, k==repeat-1, dither); - in++, out++; - } while (--count); - - count = kernelHalfSize; - do { - current -= *out; - dither = *(ditherY + ((x++)&BLUR_DITHER_MASK)); - *fb++ = current.to(areaShift, k==repeat-1, dither); - out++; - } while (--count); - - // vertical blur pass, subtract the oldest line from each columns - // and add a new line. Subtract or add zeros at the top - // and bottom edges. - TYPE* const tail = scratch + (y & mask) * src->stride; - if (y >= kernelHalfSize) { - for (int x=0 ; x<w ; x++) - sums[x] -= PIXEL( tail[x] ); - } - if (y < h-kernelSize) { - memcpy( tail, - (TYPE*)src->data + (y+kernelHalfSize)*src->stride, - src->stride*sizeof(TYPE)); - for (int x=0 ; x<w ; x++) - sums[x] += PIXEL( tail[x] ); - } - } - - // The subsequent passes are always done in-place. - src = dst; - } - - free(temporary_buffer); - - return NO_ERROR; -} - -template status_t blurFilter< BlurColor565<0x80> >( - GGLSurface const* dst, - GGLSurface const* src, - int kernelSizeUser, - int repeat); - -status_t blurFilter( - GGLSurface const* image, - int kernelSizeUser, - int repeat) -{ - status_t err = BAD_VALUE; - if (image->format == GGL_PIXEL_FORMAT_RGB_565) { - err = blurFilter< BlurColor565<0x80> >(image, image, kernelSizeUser, repeat); - } else if (image->format == GGL_PIXEL_FORMAT_RGBX_8888) { - err = blurFilter< BlurColor888X<0x80> >(image, image, kernelSizeUser, repeat); - } - return err; -} - -} // namespace android - -//err = blur< BlurColor565<0x80> >(dst, src, kernelSizeUser, repeat); -//err = blur<BlurGray565>(dst, src, kernelSizeUser, repeat); -//err = blur<BlurGray8888>(dst, src, kernelSizeUser, repeat); diff --git a/libs/surfaceflinger/BlurFilter.h b/libs/surfaceflinger/BlurFilter.h deleted file mode 100644 index 294db43..0000000 --- a/libs/surfaceflinger/BlurFilter.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -** -** Copyright 2006, 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. -*/ - -#ifndef ANDROID_BLUR_FILTER_H -#define ANDROID_BLUR_FILTER_H - -#include <stdint.h> -#include <utils/Errors.h> - -#include <pixelflinger/pixelflinger.h> - -namespace android { - -status_t blurFilter( - GGLSurface const* image, - int kernelSizeUser, - int repeat); - -} // namespace android - -#endif // ANDROID_BLUR_FILTER_H diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp deleted file mode 100644 index 2eac0a8..0000000 --- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp +++ /dev/null @@ -1,336 +0,0 @@ -/* - * 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 <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <math.h> - -#include <cutils/properties.h> - -#include <utils/RefBase.h> -#include <utils/Log.h> - -#include <ui/PixelFormat.h> -#include <ui/FramebufferNativeWindow.h> -#include <ui/EGLUtils.h> - -#include <GLES/gl.h> -#include <EGL/egl.h> -#include <EGL/eglext.h> - -#include <pixelflinger/pixelflinger.h> - -#include "DisplayHardware/DisplayHardware.h" - -#include <hardware/copybit.h> -#include <hardware/overlay.h> -#include <hardware/gralloc.h> - -#include "GLExtensions.h" - -using namespace android; - - -static __attribute__((noinline)) -void checkGLErrors() -{ - do { - // there could be more than one error flag - GLenum error = glGetError(); - if (error == GL_NO_ERROR) - break; - LOGE("GL error 0x%04x", int(error)); - } while(true); -} - -static __attribute__((noinline)) -void checkEGLErrors(const char* token) -{ - EGLint error = eglGetError(); - if (error && error != EGL_SUCCESS) { - LOGE("%s: EGL error 0x%04x (%s)", - token, int(error), EGLUtils::strerror(error)); - } -} - -/* - * Initialize the display to the specified values. - * - */ - -DisplayHardware::DisplayHardware( - const sp<SurfaceFlinger>& flinger, - uint32_t dpy) - : DisplayHardwareBase(flinger, dpy), - mFlags(0) -{ - init(dpy); -} - -DisplayHardware::~DisplayHardware() -{ - fini(); -} - -float DisplayHardware::getDpiX() const { return mDpiX; } -float DisplayHardware::getDpiY() const { return mDpiY; } -float DisplayHardware::getDensity() const { return mDensity; } -float DisplayHardware::getRefreshRate() const { return mRefreshRate; } -int DisplayHardware::getWidth() const { return mWidth; } -int DisplayHardware::getHeight() const { return mHeight; } -PixelFormat DisplayHardware::getFormat() const { return mFormat; } -uint32_t DisplayHardware::getMaxTextureSize() const { return mMaxTextureSize; } -uint32_t DisplayHardware::getMaxViewportDims() const { return mMaxViewportDims; } - -void DisplayHardware::init(uint32_t dpy) -{ - mNativeWindow = new FramebufferNativeWindow(); - framebuffer_device_t const * fbDev = mNativeWindow->getDevice(); - mDpiX = mNativeWindow->xdpi; - mDpiY = mNativeWindow->ydpi; - mRefreshRate = fbDev->fps; - - mOverlayEngine = NULL; - hw_module_t const* module; - if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) { - overlay_control_open(module, &mOverlayEngine); - } - - EGLint w, h, dummy; - EGLint numConfigs=0; - EGLSurface surface; - EGLContext context; - - // initialize EGL - EGLint attribs[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_NONE, 0, - EGL_NONE - }; - - // debug: disable h/w rendering - char property[PROPERTY_VALUE_MAX]; - if (property_get("debug.sf.hw", property, NULL) > 0) { - if (atoi(property) == 0) { - LOGW("H/W composition disabled"); - attribs[2] = EGL_CONFIG_CAVEAT; - attribs[3] = EGL_SLOW_CONFIG; - } - } - - // TODO: all the extensions below should be queried through - // eglGetProcAddress(). - - EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - eglInitialize(display, NULL, NULL); - eglGetConfigs(display, NULL, 0, &numConfigs); - - EGLConfig config; - status_t err = EGLUtils::selectConfigForNativeWindow( - display, attribs, mNativeWindow.get(), &config); - LOGE_IF(err, "couldn't find an EGLConfig matching the screen format"); - - EGLint r,g,b,a; - eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); - eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); - eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); - eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); - - if (mNativeWindow->isUpdateOnDemand()) { - mFlags |= PARTIAL_UPDATES; - } - - if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) { - if (dummy == EGL_SLOW_CONFIG) - mFlags |= SLOW_CONFIG; - } - - /* - * Create our main surface - */ - - surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL); - eglQuerySurface(display, surface, EGL_WIDTH, &mWidth); - eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight); - - if (mFlags & PARTIAL_UPDATES) { - // if we have partial updates, we definitely don't need to - // preserve the backbuffer, which may be costly. - eglSurfaceAttrib(display, surface, - EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED); - } - - if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) { - if (dummy == EGL_BUFFER_PRESERVED) { - mFlags |= BUFFER_PRESERVED; - } - } - - /* Read density from build-specific ro.sf.lcd_density property - * except if it is overridden by qemu.sf.lcd_density. - */ - if (property_get("qemu.sf.lcd_density", property, NULL) <= 0) { - if (property_get("ro.sf.lcd_density", property, NULL) <= 0) { - LOGW("ro.sf.lcd_density not defined, using 160 dpi by default."); - strcpy(property, "160"); - } - } else { - /* for the emulator case, reset the dpi values too */ - mDpiX = mDpiY = atoi(property); - } - mDensity = atoi(property) * (1.0f/160.0f); - - - /* - * Create our OpenGL ES context - */ - - context = eglCreateContext(display, config, NULL, NULL); - - mDisplay = display; - mConfig = config; - mSurface = surface; - mContext = context; - mFormat = fbDev->format; - mPageFlipCount = 0; - - /* - * Gather OpenGL ES extensions - */ - - eglMakeCurrent(display, surface, surface, context); - - GLExtensions& extensions(GLExtensions::getInstance()); - extensions.initWithGLStrings( - glGetString(GL_VENDOR), - glGetString(GL_RENDERER), - glGetString(GL_VERSION), - glGetString(GL_EXTENSIONS), - eglQueryString(display, EGL_VENDOR), - eglQueryString(display, EGL_VERSION), - eglQueryString(display, EGL_EXTENSIONS)); - - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); - glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &mMaxViewportDims); - - -#ifdef EGL_ANDROID_swap_rectangle - if (extensions.hasExtension("EGL_ANDROID_swap_rectangle")) { - if (eglSetSwapRectangleANDROID(display, surface, - 0, 0, mWidth, mHeight) == EGL_TRUE) { - // This could fail if this extension is not supported by this - // specific surface (of config) - mFlags |= SWAP_RECTANGLE; - } - } - // when we have the choice between PARTIAL_UPDATES and SWAP_RECTANGLE - // choose PARTIAL_UPDATES, which should be more efficient - if (mFlags & PARTIAL_UPDATES) - mFlags &= ~SWAP_RECTANGLE; -#endif - - LOGI("EGL informations:"); - LOGI("# of configs : %d", numConfigs); - LOGI("vendor : %s", extensions.getEglVendor()); - LOGI("version : %s", extensions.getEglVersion()); - LOGI("extensions: %s", extensions.getEglExtension()); - LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); - LOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config); - - LOGI("OpenGL informations:"); - LOGI("vendor : %s", extensions.getVendor()); - LOGI("renderer : %s", extensions.getRenderer()); - LOGI("version : %s", extensions.getVersion()); - LOGI("extensions: %s", extensions.getExtension()); - LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize); - LOGI("GL_MAX_VIEWPORT_DIMS = %d", mMaxViewportDims); - LOGI("flags = %08x", mFlags); - - // Unbind the context from this thread - eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); -} - -/* - * Clean up. Throw out our local state. - * - * (It's entirely possible we'll never get here, since this is meant - * for real hardware, which doesn't restart.) - */ - -void DisplayHardware::fini() -{ - eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglTerminate(mDisplay); - overlay_control_close(mOverlayEngine); -} - -void DisplayHardware::releaseScreen() const -{ - DisplayHardwareBase::releaseScreen(); -} - -void DisplayHardware::acquireScreen() const -{ - DisplayHardwareBase::acquireScreen(); -} - -uint32_t DisplayHardware::getPageFlipCount() const { - return mPageFlipCount; -} - -status_t DisplayHardware::compositionComplete() const { - return mNativeWindow->compositionComplete(); -} - -void DisplayHardware::flip(const Region& dirty) const -{ - checkGLErrors(); - - EGLDisplay dpy = mDisplay; - EGLSurface surface = mSurface; - -#ifdef EGL_ANDROID_swap_rectangle - if (mFlags & SWAP_RECTANGLE) { - const Region newDirty(dirty.intersect(bounds())); - const Rect b(newDirty.getBounds()); - eglSetSwapRectangleANDROID(dpy, surface, - b.left, b.top, b.width(), b.height()); - } -#endif - - if (mFlags & PARTIAL_UPDATES) { - mNativeWindow->setUpdateRectangle(dirty.getBounds()); - } - - mPageFlipCount++; - eglSwapBuffers(dpy, surface); - checkEGLErrors("eglSwapBuffers"); - - // for debugging - //glClearColor(1,0,0,0); - //glClear(GL_COLOR_BUFFER_BIT); -} - -uint32_t DisplayHardware::getFlags() const -{ - return mFlags; -} - -void DisplayHardware::makeCurrent() const -{ - eglMakeCurrent(mDisplay, mSurface, mSurface, mContext); -} diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h deleted file mode 100644 index 66bf521..0000000 --- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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. - */ - -#ifndef ANDROID_DISPLAY_HARDWARE_H -#define ANDROID_DISPLAY_HARDWARE_H - -#include <stdlib.h> - -#include <ui/PixelFormat.h> -#include <ui/Region.h> - -#include <GLES/gl.h> -#include <GLES/glext.h> -#include <EGL/egl.h> -#include <EGL/eglext.h> - -#include <pixelflinger/pixelflinger.h> - -#include "GLExtensions.h" - -#include "DisplayHardware/DisplayHardwareBase.h" - -struct overlay_control_device_t; -struct framebuffer_device_t; -struct copybit_image_t; - -namespace android { - -class FramebufferNativeWindow; - -class DisplayHardware : public DisplayHardwareBase -{ -public: - enum { - COPY_BITS_EXTENSION = 0x00000008, - BUFFER_PRESERVED = 0x00010000, - PARTIAL_UPDATES = 0x00020000, // video driver feature - SLOW_CONFIG = 0x00040000, // software - SWAP_RECTANGLE = 0x00080000, - }; - - DisplayHardware( - const sp<SurfaceFlinger>& flinger, - uint32_t displayIndex); - - ~DisplayHardware(); - - void releaseScreen() const; - void acquireScreen() const; - - // Flip the front and back buffers if the back buffer is "dirty". Might - // be instantaneous, might involve copying the frame buffer around. - void flip(const Region& dirty) const; - - float getDpiX() const; - float getDpiY() const; - float getRefreshRate() const; - float getDensity() const; - int getWidth() const; - int getHeight() const; - PixelFormat getFormat() const; - uint32_t getFlags() const; - void makeCurrent() const; - uint32_t getMaxTextureSize() const; - uint32_t getMaxViewportDims() const; - - uint32_t getPageFlipCount() const; - EGLDisplay getEGLDisplay() const { return mDisplay; } - overlay_control_device_t* getOverlayEngine() const { return mOverlayEngine; } - - status_t compositionComplete() const; - - Rect bounds() const { - return Rect(mWidth, mHeight); - } - -private: - void init(uint32_t displayIndex) __attribute__((noinline)); - void fini() __attribute__((noinline)); - - EGLDisplay mDisplay; - EGLSurface mSurface; - EGLContext mContext; - EGLConfig mConfig; - float mDpiX; - float mDpiY; - float mRefreshRate; - float mDensity; - int mWidth; - int mHeight; - PixelFormat mFormat; - uint32_t mFlags; - mutable uint32_t mPageFlipCount; - GLint mMaxViewportDims; - GLint mMaxTextureSize; - - sp<FramebufferNativeWindow> mNativeWindow; - overlay_control_device_t* mOverlayEngine; -}; - -}; // namespace android - -#endif // ANDROID_DISPLAY_HARDWARE_H diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp deleted file mode 100644 index 1d09f84..0000000 --- a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp +++ /dev/null @@ -1,401 +0,0 @@ -/* - * 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 <assert.h> -#include <errno.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#include <unistd.h> -#include <fcntl.h> -#include <signal.h> -#include <termios.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/resource.h> - -#include <linux/unistd.h> - -#include <utils/Log.h> - -#include "DisplayHardware/DisplayHardwareBase.h" -#include "SurfaceFlinger.h" - -// ---------------------------------------------------------------------------- -// the sim build doesn't have gettid - -#ifndef HAVE_GETTID -# define gettid getpid -#endif - -// ---------------------------------------------------------------------------- -namespace android { - -static char const * kSleepFileName = "/sys/power/wait_for_fb_sleep"; -static char const * kWakeFileName = "/sys/power/wait_for_fb_wake"; -static char const * const kOldSleepFileName = "/sys/android_power/wait_for_fb_sleep"; -static char const * const kOldWakeFileName = "/sys/android_power/wait_for_fb_wake"; - -// This dir exists if the framebuffer console is present, either built into -// the kernel or loaded as a module. -static char const * const kFbconSysDir = "/sys/class/graphics/fbcon"; - -// ---------------------------------------------------------------------------- - -DisplayHardwareBase::DisplayEventThreadBase::DisplayEventThreadBase( - const sp<SurfaceFlinger>& flinger) - : Thread(false), mFlinger(flinger) { -} - -DisplayHardwareBase::DisplayEventThreadBase::~DisplayEventThreadBase() { -} - -// ---------------------------------------------------------------------------- - -DisplayHardwareBase::DisplayEventThread::DisplayEventThread( - const sp<SurfaceFlinger>& flinger) - : DisplayEventThreadBase(flinger) -{ -} - -DisplayHardwareBase::DisplayEventThread::~DisplayEventThread() -{ -} - -bool DisplayHardwareBase::DisplayEventThread::threadLoop() -{ - int err = 0; - char buf; - int fd; - - fd = open(kSleepFileName, O_RDONLY, 0); - do { - err = read(fd, &buf, 1); - } while (err < 0 && errno == EINTR); - close(fd); - LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno)); - if (err >= 0) { - sp<SurfaceFlinger> flinger = mFlinger.promote(); - LOGD("About to give-up screen, flinger = %p", flinger.get()); - if (flinger != 0) { - mBarrier.close(); - flinger->screenReleased(0); - mBarrier.wait(); - } - } - fd = open(kWakeFileName, O_RDONLY, 0); - do { - err = read(fd, &buf, 1); - } while (err < 0 && errno == EINTR); - close(fd); - LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno)); - if (err >= 0) { - sp<SurfaceFlinger> flinger = mFlinger.promote(); - LOGD("Screen about to return, flinger = %p", flinger.get()); - if (flinger != 0) - flinger->screenAcquired(0); - } - return true; -} - -status_t DisplayHardwareBase::DisplayEventThread::releaseScreen() const -{ - mBarrier.open(); - return NO_ERROR; -} - -status_t DisplayHardwareBase::DisplayEventThread::readyToRun() -{ - if (access(kSleepFileName, R_OK) || access(kWakeFileName, R_OK)) { - if (access(kOldSleepFileName, R_OK) || access(kOldWakeFileName, R_OK)) { - LOGE("Couldn't open %s or %s", kSleepFileName, kWakeFileName); - return NO_INIT; - } - kSleepFileName = kOldSleepFileName; - kWakeFileName = kOldWakeFileName; - } - return NO_ERROR; -} - -status_t DisplayHardwareBase::DisplayEventThread::initCheck() const -{ - return (((access(kSleepFileName, R_OK) == 0 && - access(kWakeFileName, R_OK) == 0) || - (access(kOldSleepFileName, R_OK) == 0 && - access(kOldWakeFileName, R_OK) == 0)) && - access(kFbconSysDir, F_OK) != 0) ? NO_ERROR : NO_INIT; -} - -// ---------------------------------------------------------------------------- - -pid_t DisplayHardwareBase::ConsoleManagerThread::sSignalCatcherPid = 0; - -DisplayHardwareBase::ConsoleManagerThread::ConsoleManagerThread( - const sp<SurfaceFlinger>& flinger) - : DisplayEventThreadBase(flinger), consoleFd(-1) -{ - sSignalCatcherPid = 0; - - // create a new console - char const * const ttydev = "/dev/tty0"; - int fd = open(ttydev, O_RDWR | O_SYNC); - if (fd<0) { - LOGE("Can't open %s", ttydev); - this->consoleFd = -errno; - return; - } - - // to make sure that we are in text mode - int res = ioctl(fd, KDSETMODE, (void*) KD_TEXT); - if (res<0) { - LOGE("ioctl(%d, KDSETMODE, ...) failed, res %d (%s)", - fd, res, strerror(errno)); - } - - // get the current console - struct vt_stat vs; - res = ioctl(fd, VT_GETSTATE, &vs); - if (res<0) { - LOGE("ioctl(%d, VT_GETSTATE, ...) failed, res %d (%s)", - fd, res, strerror(errno)); - this->consoleFd = -errno; - return; - } - - // switch to console 7 (which is what X normaly uses) - int vtnum = 7; - do { - res = ioctl(fd, VT_ACTIVATE, (void*)vtnum); - } while(res < 0 && errno == EINTR); - if (res<0) { - LOGE("ioctl(%d, VT_ACTIVATE, ...) failed, %d (%s) for %d", - fd, errno, strerror(errno), vtnum); - this->consoleFd = -errno; - return; - } - - do { - res = ioctl(fd, VT_WAITACTIVE, (void*)vtnum); - } while(res < 0 && errno == EINTR); - if (res<0) { - LOGE("ioctl(%d, VT_WAITACTIVE, ...) failed, %d %d %s for %d", - fd, res, errno, strerror(errno), vtnum); - this->consoleFd = -errno; - return; - } - - // open the new console - close(fd); - fd = open(ttydev, O_RDWR | O_SYNC); - if (fd<0) { - LOGE("Can't open new console %s", ttydev); - this->consoleFd = -errno; - return; - } - - /* disable console line buffer, echo, ... */ - struct termios ttyarg; - ioctl(fd, TCGETS , &ttyarg); - ttyarg.c_iflag = 0; - ttyarg.c_lflag = 0; - ioctl(fd, TCSETS , &ttyarg); - - // set up signals so we're notified when the console changes - // we can't use SIGUSR1 because it's used by the java-vm - vm.mode = VT_PROCESS; - vm.waitv = 0; - vm.relsig = SIGUSR2; - vm.acqsig = SIGUNUSED; - vm.frsig = 0; - - struct sigaction act; - sigemptyset(&act.sa_mask); - act.sa_handler = sigHandler; - act.sa_flags = 0; - sigaction(vm.relsig, &act, NULL); - - sigemptyset(&act.sa_mask); - act.sa_handler = sigHandler; - act.sa_flags = 0; - sigaction(vm.acqsig, &act, NULL); - - sigset_t mask; - sigemptyset(&mask); - sigaddset(&mask, vm.relsig); - sigaddset(&mask, vm.acqsig); - sigprocmask(SIG_BLOCK, &mask, NULL); - - // switch to graphic mode - res = ioctl(fd, KDSETMODE, (void*)KD_GRAPHICS); - LOGW_IF(res<0, - "ioctl(%d, KDSETMODE, KD_GRAPHICS) failed, res %d", fd, res); - - this->prev_vt_num = vs.v_active; - this->vt_num = vtnum; - this->consoleFd = fd; -} - -DisplayHardwareBase::ConsoleManagerThread::~ConsoleManagerThread() -{ - if (this->consoleFd >= 0) { - int fd = this->consoleFd; - int prev_vt_num = this->prev_vt_num; - int res; - ioctl(fd, KDSETMODE, (void*)KD_TEXT); - do { - res = ioctl(fd, VT_ACTIVATE, (void*)prev_vt_num); - } while(res < 0 && errno == EINTR); - do { - res = ioctl(fd, VT_WAITACTIVE, (void*)prev_vt_num); - } while(res < 0 && errno == EINTR); - close(fd); - char const * const ttydev = "/dev/tty0"; - fd = open(ttydev, O_RDWR | O_SYNC); - ioctl(fd, VT_DISALLOCATE, 0); - close(fd); - } -} - -status_t DisplayHardwareBase::ConsoleManagerThread::readyToRun() -{ - if (this->consoleFd >= 0) { - sSignalCatcherPid = gettid(); - - sigset_t mask; - sigemptyset(&mask); - sigaddset(&mask, vm.relsig); - sigaddset(&mask, vm.acqsig); - sigprocmask(SIG_BLOCK, &mask, NULL); - - int res = ioctl(this->consoleFd, VT_SETMODE, &vm); - if (res<0) { - LOGE("ioctl(%d, VT_SETMODE, ...) failed, %d (%s)", - this->consoleFd, errno, strerror(errno)); - } - return NO_ERROR; - } - return this->consoleFd; -} - -void DisplayHardwareBase::ConsoleManagerThread::requestExit() -{ - Thread::requestExit(); - if (sSignalCatcherPid != 0) { - // wake the thread up - kill(sSignalCatcherPid, SIGINT); - // wait for it... - } -} - -void DisplayHardwareBase::ConsoleManagerThread::sigHandler(int sig) -{ - // resend the signal to our signal catcher thread - LOGW("received signal %d in thread %d, resending to %d", - sig, gettid(), sSignalCatcherPid); - - // we absolutely need the delays below because without them - // our main thread never gets a chance to handle the signal. - usleep(10000); - kill(sSignalCatcherPid, sig); - usleep(10000); -} - -status_t DisplayHardwareBase::ConsoleManagerThread::releaseScreen() const -{ - int fd = this->consoleFd; - int err = ioctl(fd, VT_RELDISP, (void*)1); - LOGE_IF(err<0, "ioctl(%d, VT_RELDISP, 1) failed %d (%s)", - fd, errno, strerror(errno)); - return (err<0) ? (-errno) : status_t(NO_ERROR); -} - -bool DisplayHardwareBase::ConsoleManagerThread::threadLoop() -{ - sigset_t mask; - sigemptyset(&mask); - sigaddset(&mask, vm.relsig); - sigaddset(&mask, vm.acqsig); - - int sig = 0; - sigwait(&mask, &sig); - - if (sig == vm.relsig) { - sp<SurfaceFlinger> flinger = mFlinger.promote(); - //LOGD("About to give-up screen, flinger = %p", flinger.get()); - if (flinger != 0) - flinger->screenReleased(0); - } else if (sig == vm.acqsig) { - sp<SurfaceFlinger> flinger = mFlinger.promote(); - //LOGD("Screen about to return, flinger = %p", flinger.get()); - if (flinger != 0) - flinger->screenAcquired(0); - } - - return true; -} - -status_t DisplayHardwareBase::ConsoleManagerThread::initCheck() const -{ - return consoleFd >= 0 ? NO_ERROR : NO_INIT; -} - -// ---------------------------------------------------------------------------- - -DisplayHardwareBase::DisplayHardwareBase(const sp<SurfaceFlinger>& flinger, - uint32_t displayIndex) - : mCanDraw(true) -{ - mDisplayEventThread = new DisplayEventThread(flinger); - if (mDisplayEventThread->initCheck() != NO_ERROR) { - // fall-back on the console - mDisplayEventThread = new ConsoleManagerThread(flinger); - } -} - -DisplayHardwareBase::~DisplayHardwareBase() -{ - // request exit - mDisplayEventThread->requestExitAndWait(); -} - - -bool DisplayHardwareBase::canDraw() const -{ - return mCanDraw; -} - -void DisplayHardwareBase::releaseScreen() const -{ - status_t err = mDisplayEventThread->releaseScreen(); - if (err >= 0) { - //LOGD("screen given-up"); - mCanDraw = false; - } -} - -void DisplayHardwareBase::acquireScreen() const -{ - status_t err = mDisplayEventThread->acquireScreen(); - if (err >= 0) { - //LOGD("screen returned"); - mCanDraw = true; - } -} - -}; // namespace android diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.h deleted file mode 100644 index 8369bb8..0000000 --- a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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. - */ - -#ifndef ANDROID_DISPLAY_HARDWARE_BASE_H -#define ANDROID_DISPLAY_HARDWARE_BASE_H - -#include <stdint.h> -#include <utils/RefBase.h> -#include <utils/threads.h> -#include <linux/kd.h> -#include <linux/vt.h> -#include "Barrier.h" - -namespace android { - -class SurfaceFlinger; - -class DisplayHardwareBase -{ -public: - DisplayHardwareBase( - const sp<SurfaceFlinger>& flinger, - uint32_t displayIndex); - - ~DisplayHardwareBase(); - - // console managment - void releaseScreen() const; - void acquireScreen() const; - bool canDraw() const; - -private: - class DisplayEventThreadBase : public Thread { - protected: - wp<SurfaceFlinger> mFlinger; - public: - DisplayEventThreadBase(const sp<SurfaceFlinger>& flinger); - virtual ~DisplayEventThreadBase(); - virtual void onFirstRef() { - run("DisplayEventThread", PRIORITY_URGENT_DISPLAY); - } - virtual status_t acquireScreen() const { return NO_ERROR; }; - virtual status_t releaseScreen() const { return NO_ERROR; }; - virtual status_t initCheck() const = 0; - }; - - class DisplayEventThread : public DisplayEventThreadBase - { - mutable Barrier mBarrier; - public: - DisplayEventThread(const sp<SurfaceFlinger>& flinger); - virtual ~DisplayEventThread(); - virtual bool threadLoop(); - virtual status_t readyToRun(); - virtual status_t releaseScreen() const; - virtual status_t initCheck() const; - }; - - class ConsoleManagerThread : public DisplayEventThreadBase - { - int consoleFd; - int vt_num; - int prev_vt_num; - vt_mode vm; - static void sigHandler(int sig); - static pid_t sSignalCatcherPid; - public: - ConsoleManagerThread(const sp<SurfaceFlinger>& flinger); - virtual ~ConsoleManagerThread(); - virtual bool threadLoop(); - virtual status_t readyToRun(); - virtual void requestExit(); - virtual status_t releaseScreen() const; - virtual status_t initCheck() const; - }; - - sp<DisplayEventThreadBase> mDisplayEventThread; - mutable int mCanDraw; -}; - -}; // namespace android - -#endif // ANDROID_DISPLAY_HARDWARE_BASE_H diff --git a/libs/surfaceflinger/GLExtensions.cpp b/libs/surfaceflinger/GLExtensions.cpp deleted file mode 100644 index 7f4f9fc..0000000 --- a/libs/surfaceflinger/GLExtensions.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2010 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 <stdlib.h> -#include <stdio.h> -#include <stdint.h> - -#include "GLExtensions.h" - -namespace android { -// --------------------------------------------------------------------------- - -ANDROID_SINGLETON_STATIC_INSTANCE( GLExtensions ) - -GLExtensions::GLExtensions() - : mHaveTextureExternal(false), - mHaveNpot(false), - mHaveDirectTexture(false) -{ -} - -void GLExtensions::initWithGLStrings( - GLubyte const* vendor, - GLubyte const* renderer, - GLubyte const* version, - GLubyte const* extensions, - char const* egl_vendor, - char const* egl_version, - char const* egl_extensions) -{ - mVendor = (char const*)vendor; - mRenderer = (char const*)renderer; - mVersion = (char const*)version; - mExtensions = (char const*)extensions; - mEglVendor = egl_vendor; - mEglVersion = egl_version; - mEglExtensions = egl_extensions; - - char const* curr = (char const*)extensions; - char const* head = curr; - do { - head = strchr(curr, ' '); - String8 s(curr, head ? head-curr : strlen(curr)); - if (s.length()) { - mExtensionList.add(s); - } - curr = head+1; - } while (head); - - curr = egl_extensions; - head = curr; - do { - head = strchr(curr, ' '); - String8 s(curr, head ? head-curr : strlen(curr)); - if (s.length()) { - mExtensionList.add(s); - } - curr = head+1; - } while (head); - -#ifdef EGL_ANDROID_image_native_buffer - if (hasExtension("GL_OES_EGL_image") && - (hasExtension("EGL_KHR_image_base") || hasExtension("EGL_KHR_image")) && - hasExtension("EGL_ANDROID_image_native_buffer")) - { - mHaveDirectTexture = true; - } -#else -#warning "EGL_ANDROID_image_native_buffer not supported" -#endif - - if (hasExtension("GL_ARB_texture_non_power_of_two")) { - mHaveNpot = true; - } - - if (hasExtension("GL_OES_texture_external")) { - mHaveTextureExternal = true; - } else if (strstr(mRenderer.string(), "Adreno")) { - // hack for Adreno 200 - mHaveTextureExternal = true; - } -} - -bool GLExtensions::hasExtension(char const* extension) const -{ - const String8 s(extension); - return mExtensionList.indexOf(s) >= 0; -} - -char const* GLExtensions::getVendor() const { - return mVendor.string(); -} - -char const* GLExtensions::getRenderer() const { - return mRenderer.string(); -} - -char const* GLExtensions::getVersion() const { - return mVersion.string(); -} - -char const* GLExtensions::getExtension() const { - return mExtensions.string(); -} - -char const* GLExtensions::getEglVendor() const { - return mEglVendor.string(); -} - -char const* GLExtensions::getEglVersion() const { - return mEglVersion.string(); -} - -char const* GLExtensions::getEglExtension() const { - return mEglExtensions.string(); -} - - -// --------------------------------------------------------------------------- -}; // namespace android diff --git a/libs/surfaceflinger/GLExtensions.h b/libs/surfaceflinger/GLExtensions.h deleted file mode 100644 index bbb284e..0000000 --- a/libs/surfaceflinger/GLExtensions.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#ifndef ANDROID_SF_GLEXTENSION_H -#define ANDROID_SF_GLEXTENSION_H - -#include <stdint.h> -#include <sys/types.h> - -#include <utils/String8.h> -#include <utils/SortedVector.h> -#include <utils/Singleton.h> - -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <GLES/gl.h> -#include <GLES/glext.h> - -namespace android { -// --------------------------------------------------------------------------- - -class GLExtensions : public Singleton<GLExtensions> -{ - friend class Singleton<GLExtensions>; - - bool mHaveTextureExternal : 1; - bool mHaveNpot : 1; - bool mHaveDirectTexture : 1; - - String8 mVendor; - String8 mRenderer; - String8 mVersion; - String8 mExtensions; - String8 mEglVendor; - String8 mEglVersion; - String8 mEglExtensions; - SortedVector<String8> mExtensionList; - - GLExtensions(const GLExtensions&); - GLExtensions& operator = (const GLExtensions&); - -protected: - GLExtensions(); - -public: - inline bool haveTextureExternal() const { - return mHaveTextureExternal; - } - inline bool haveNpot() const { - return mHaveNpot; - } - inline bool haveDirectTexture() const { - return mHaveDirectTexture; - } - - void initWithGLStrings( - GLubyte const* vendor, - GLubyte const* renderer, - GLubyte const* version, - GLubyte const* extensions, - char const* egl_vendor, - char const* egl_version, - char const* egl_extensions); - - char const* getVendor() const; - char const* getRenderer() const; - char const* getVersion() const; - char const* getExtension() const; - - char const* getEglVendor() const; - char const* getEglVersion() const; - char const* getEglExtension() const; - - bool hasExtension(char const* extension) const; -}; - - -// --------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_SF_GLEXTENSION_H diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp deleted file mode 100644 index 758da4e..0000000 --- a/libs/surfaceflinger/Layer.cpp +++ /dev/null @@ -1,875 +0,0 @@ -/* - * 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 <stdlib.h> -#include <stdint.h> -#include <sys/types.h> - -#include <cutils/properties.h> -#include <cutils/native_handle.h> - -#include <utils/Errors.h> -#include <utils/Log.h> -#include <utils/StopWatch.h> - -#include <ui/GraphicBuffer.h> -#include <ui/PixelFormat.h> - -#include <surfaceflinger/Surface.h> - -#include "clz.h" -#include "GLExtensions.h" -#include "Layer.h" -#include "SurfaceFlinger.h" -#include "DisplayHardware/DisplayHardware.h" - - -#define DEBUG_RESIZE 0 - - -namespace android { - -template <typename T> inline T min(T a, T b) { - return a<b ? a : b; -} - -// --------------------------------------------------------------------------- - -Layer::Layer(SurfaceFlinger* flinger, - DisplayID display, const sp<Client>& client) - : LayerBaseClient(flinger, display, client), - mGLExtensions(GLExtensions::getInstance()), - mNeedsBlending(true), - mNeedsDithering(false), - mSecure(false), - mTextureManager(), - mBufferManager(mTextureManager), - mWidth(0), mHeight(0), mFixedSize(false) -{ -} - -Layer::~Layer() -{ - // FIXME: must be called from the main UI thread - EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); - mBufferManager.destroy(dpy); - - // we can use getUserClientUnsafe here because we know we're - // single-threaded at that point. - sp<UserClient> ourClient(mUserClientRef.getUserClientUnsafe()); - if (ourClient != 0) { - ourClient->detachLayer(this); - } -} - -status_t Layer::setToken(const sp<UserClient>& userClient, - SharedClient* sharedClient, int32_t token) -{ - sp<SharedBufferServer> lcblk = new SharedBufferServer( - sharedClient, token, mBufferManager.getDefaultBufferCount(), - getIdentity()); - - status_t err = mUserClientRef.setToken(userClient, lcblk, token); - - LOGE_IF(err != NO_ERROR, - "ClientRef::setToken(%p, %p, %u) failed", - userClient.get(), lcblk.get(), token); - - if (err == NO_ERROR) { - // we need to free the buffers associated with this surface - } - - return err; -} - -int32_t Layer::getToken() const -{ - return mUserClientRef.getToken(); -} - -sp<UserClient> Layer::getClient() const -{ - return mUserClientRef.getClient(); -} - -// called with SurfaceFlinger::mStateLock as soon as the layer is entered -// in the purgatory list -void Layer::onRemoved() -{ - ClientRef::Access sharedClient(mUserClientRef); - SharedBufferServer* lcblk(sharedClient.get()); - if (lcblk) { - // wake up the condition - lcblk->setStatus(NO_INIT); - } -} - -sp<LayerBaseClient::Surface> Layer::createSurface() const -{ - return mSurface; -} - -status_t Layer::ditch() -{ - // NOTE: Called from the main UI thread - - // the layer is not on screen anymore. free as much resources as possible - mFreezeLock.clear(); - - EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); - mBufferManager.destroy(dpy); - mSurface.clear(); - - Mutex::Autolock _l(mLock); - mWidth = mHeight = 0; - return NO_ERROR; -} - -status_t Layer::setBuffers( uint32_t w, uint32_t h, - PixelFormat format, uint32_t flags) -{ - // this surfaces pixel format - PixelFormatInfo info; - status_t err = getPixelFormatInfo(format, &info); - if (err) return err; - - // the display's pixel format - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - uint32_t const maxSurfaceDims = min( - hw.getMaxTextureSize(), hw.getMaxViewportDims()); - - // never allow a surface larger than what our underlying GL implementation - // can handle. - if ((uint32_t(w)>maxSurfaceDims) || (uint32_t(h)>maxSurfaceDims)) { - return BAD_VALUE; - } - - PixelFormatInfo displayInfo; - getPixelFormatInfo(hw.getFormat(), &displayInfo); - const uint32_t hwFlags = hw.getFlags(); - - mFormat = format; - mReqFormat = format; - mWidth = w; - mHeight = h; - mSecure = (flags & ISurfaceComposer::eSecure) ? true : false; - mNeedsBlending = (info.h_alpha - info.l_alpha) > 0; - - // we use the red index - int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED); - int layerRedsize = info.getSize(PixelFormatInfo::INDEX_RED); - mNeedsDithering = layerRedsize > displayRedSize; - - mSurface = new SurfaceLayer(mFlinger, this); - return NO_ERROR; -} - -void Layer::reloadTexture(const Region& dirty) -{ - sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer()); - if (buffer == NULL) { - // this situation can happen if we ran out of memory for instance. - // not much we can do. continue to use whatever texture was bound - // to this context. - return; - } - - if (mGLExtensions.haveDirectTexture()) { - EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); - if (mBufferManager.initEglImage(dpy, buffer) != NO_ERROR) { - // not sure what we can do here... - goto slowpath; - } - } else { -slowpath: - GGLSurface t; - status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN); - LOGE_IF(res, "error %d (%s) locking buffer %p", - res, strerror(res), buffer.get()); - if (res == NO_ERROR) { - mBufferManager.loadTexture(dirty, t); - buffer->unlock(); - } - } -} - -void Layer::onDraw(const Region& clip) const -{ - Texture tex(mBufferManager.getActiveTexture()); - if (tex.name == -1LU) { - // the texture has not been created yet, this Layer has - // in fact never been drawn into. This happens frequently with - // SurfaceView because the WindowManager can't know when the client - // has drawn the first time. - - // If there is nothing under us, we paint the screen in black, otherwise - // we just skip this update. - - // figure out if there is something below us - Region under; - const SurfaceFlinger::LayerVector& drawingLayers(mFlinger->mDrawingState.layersSortedByZ); - const size_t count = drawingLayers.size(); - for (size_t i=0 ; i<count ; ++i) { - const sp<LayerBase>& layer(drawingLayers[i]); - if (layer.get() == static_cast<LayerBase const*>(this)) - break; - under.orSelf(layer->visibleRegionScreen); - } - // if not everything below us is covered, we plug the holes! - Region holes(clip.subtract(under)); - if (!holes.isEmpty()) { - clearWithOpenGL(holes, 0, 0, 0, 1); - } - return; - } - drawWithOpenGL(clip, tex); -} - -bool Layer::needsFiltering() const -{ - if (!(mFlags & DisplayHardware::SLOW_CONFIG)) { - // NOTE: there is a race here, because mFixedSize is updated in a - // binder transaction. however, it doesn't really matter since it is - // evaluated each time we draw. To be perfectly correct, this flag - // would have to be associated with a buffer. - if (mFixedSize) - return true; - } - return LayerBase::needsFiltering(); -} - - -status_t Layer::setBufferCount(int bufferCount) -{ - ClientRef::Access sharedClient(mUserClientRef); - SharedBufferServer* lcblk(sharedClient.get()); - if (!lcblk) { - // oops, the client is already gone - return DEAD_OBJECT; - } - - // NOTE: lcblk->resize() is protected by an internal lock - status_t err = lcblk->resize(bufferCount); - if (err == NO_ERROR) - mBufferManager.resize(bufferCount); - - return err; -} - -sp<GraphicBuffer> Layer::requestBuffer(int index, - uint32_t reqWidth, uint32_t reqHeight, uint32_t reqFormat, - uint32_t usage) -{ - sp<GraphicBuffer> buffer; - - if (int32_t(reqWidth | reqHeight | reqFormat) < 0) - return buffer; - - if ((!reqWidth && reqHeight) || (reqWidth && !reqHeight)) - return buffer; - - // this ensures our client doesn't go away while we're accessing - // the shared area. - ClientRef::Access sharedClient(mUserClientRef); - SharedBufferServer* lcblk(sharedClient.get()); - if (!lcblk) { - // oops, the client is already gone - return buffer; - } - - /* - * This is called from the client's Surface::dequeue(). This can happen - * at any time, especially while we're in the middle of using the - * buffer 'index' as our front buffer. - * - * Make sure the buffer we're resizing is not the front buffer and has been - * dequeued. Once this condition is asserted, we are guaranteed that this - * buffer cannot become the front buffer under our feet, since we're called - * from Surface::dequeue() - */ - status_t err = lcblk->assertReallocate(index); - LOGE_IF(err, "assertReallocate(%d) failed (%s)", index, strerror(-err)); - if (err != NO_ERROR) { - // the surface may have died - return buffer; - } - - uint32_t w, h, f; - { // scope for the lock - Mutex::Autolock _l(mLock); - const bool fixedSizeChanged = mFixedSize != (reqWidth && reqHeight); - const bool formatChanged = mReqFormat != reqFormat; - mReqWidth = reqWidth; - mReqHeight = reqHeight; - mReqFormat = reqFormat; - mFixedSize = reqWidth && reqHeight; - w = reqWidth ? reqWidth : mWidth; - h = reqHeight ? reqHeight : mHeight; - f = reqFormat ? reqFormat : mFormat; - buffer = mBufferManager.detachBuffer(index); - if (fixedSizeChanged || formatChanged) { - lcblk->reallocateAllExcept(index); - } - } - - const uint32_t effectiveUsage = getEffectiveUsage(usage); - if (buffer!=0 && buffer->getStrongCount() == 1) { - err = buffer->reallocate(w, h, f, effectiveUsage); - } else { - // here we have to reallocate a new buffer because we could have a - // client in our process with a reference to it (eg: status bar), - // and we can't release the handle under its feet. - buffer.clear(); - buffer = new GraphicBuffer(w, h, f, effectiveUsage); - err = buffer->initCheck(); - } - - if (err || buffer->handle == 0) { - LOGE_IF(err || buffer->handle == 0, - "Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d failed (%s)", - this, index, w, h, strerror(-err)); - } else { - LOGD_IF(DEBUG_RESIZE, - "Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d, handle=%p", - this, index, w, h, buffer->handle); - } - - if (err == NO_ERROR && buffer->handle != 0) { - Mutex::Autolock _l(mLock); - mBufferManager.attachBuffer(index, buffer); - } - return buffer; -} - -uint32_t Layer::getEffectiveUsage(uint32_t usage) const -{ - /* - * buffers used for software rendering, but h/w composition - * are allocated with SW_READ_OFTEN | SW_WRITE_OFTEN | HW_TEXTURE - * - * buffers used for h/w rendering and h/w composition - * are allocated with HW_RENDER | HW_TEXTURE - * - * buffers used with h/w rendering and either NPOT or no egl_image_ext - * are allocated with SW_READ_RARELY | HW_RENDER - * - */ - - if (mSecure) { - // secure buffer, don't store it into the GPU - usage = GraphicBuffer::USAGE_SW_READ_OFTEN | - GraphicBuffer::USAGE_SW_WRITE_OFTEN; - } else { - // it's allowed to modify the usage flags here, but generally - // the requested flags should be honored. - // request EGLImage for all buffers - usage |= GraphicBuffer::USAGE_HW_TEXTURE; - } - return usage; -} - -uint32_t Layer::doTransaction(uint32_t flags) -{ - const Layer::State& front(drawingState()); - const Layer::State& temp(currentState()); - - const bool sizeChanged = (front.requested_w != temp.requested_w) || - (front.requested_h != temp.requested_h); - - if (sizeChanged) { - // the size changed, we need to ask our client to request a new buffer - LOGD_IF(DEBUG_RESIZE, - "resize (layer=%p), requested (%dx%d), drawing (%d,%d)", - this, - int(temp.requested_w), int(temp.requested_h), - int(front.requested_w), int(front.requested_h)); - - if (!isFixedSize()) { - // we're being resized and there is a freeze display request, - // acquire a freeze lock, so that the screen stays put - // until we've redrawn at the new size; this is to avoid - // glitches upon orientation changes. - if (mFlinger->hasFreezeRequest()) { - // if the surface is hidden, don't try to acquire the - // freeze lock, since hidden surfaces may never redraw - if (!(front.flags & ISurfaceComposer::eLayerHidden)) { - mFreezeLock = mFlinger->getFreezeLock(); - } - } - - // this will make sure LayerBase::doTransaction doesn't update - // the drawing state's size - Layer::State& editDraw(mDrawingState); - editDraw.requested_w = temp.requested_w; - editDraw.requested_h = temp.requested_h; - - // record the new size, form this point on, when the client request - // a buffer, it'll get the new size. - setBufferSize(temp.requested_w, temp.requested_h); - - ClientRef::Access sharedClient(mUserClientRef); - SharedBufferServer* lcblk(sharedClient.get()); - if (lcblk) { - // all buffers need reallocation - lcblk->reallocateAll(); - } - } else { - // record the new size - setBufferSize(temp.requested_w, temp.requested_h); - } - } - - if (temp.sequence != front.sequence) { - if (temp.flags & ISurfaceComposer::eLayerHidden || temp.alpha == 0) { - // this surface is now hidden, so it shouldn't hold a freeze lock - // (it may never redraw, which is fine if it is hidden) - mFreezeLock.clear(); - } - } - - return LayerBase::doTransaction(flags); -} - -void Layer::setBufferSize(uint32_t w, uint32_t h) { - Mutex::Autolock _l(mLock); - mWidth = w; - mHeight = h; -} - -bool Layer::isFixedSize() const { - Mutex::Autolock _l(mLock); - return mFixedSize; -} - -// ---------------------------------------------------------------------------- -// pageflip handling... -// ---------------------------------------------------------------------------- - -void Layer::lockPageFlip(bool& recomputeVisibleRegions) -{ - ClientRef::Access sharedClient(mUserClientRef); - SharedBufferServer* lcblk(sharedClient.get()); - if (!lcblk) { - // client died - recomputeVisibleRegions = true; - return; - } - - ssize_t buf = lcblk->retireAndLock(); - if (buf == NOT_ENOUGH_DATA) { - // NOTE: This is not an error, it simply means there is nothing to - // retire. The buffer is locked because we will use it - // for composition later in the loop - return; - } - - if (buf < NO_ERROR) { - LOGE("retireAndLock() buffer index (%d) out of range", int(buf)); - mPostedDirtyRegion.clear(); - return; - } - - // we retired a buffer, which becomes the new front buffer - if (mBufferManager.setActiveBufferIndex(buf) < NO_ERROR) { - LOGE("retireAndLock() buffer index (%d) out of range", int(buf)); - mPostedDirtyRegion.clear(); - return; - } - - // get the dirty region - sp<GraphicBuffer> newFrontBuffer(getBuffer(buf)); - if (newFrontBuffer != NULL) { - // compute the posted region - const Region dirty(lcblk->getDirtyRegion(buf)); - mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() ); - - // update the layer size and release freeze-lock - const Layer::State& front(drawingState()); - if (newFrontBuffer->getWidth() == front.requested_w && - newFrontBuffer->getHeight() == front.requested_h) - { - if ((front.w != front.requested_w) || - (front.h != front.requested_h)) - { - // Here we pretend the transaction happened by updating the - // current and drawing states. Drawing state is only accessed - // in this thread, no need to have it locked - Layer::State& editDraw(mDrawingState); - editDraw.w = editDraw.requested_w; - editDraw.h = editDraw.requested_h; - - // We also need to update the current state so that we don't - // end-up doing too much work during the next transaction. - // NOTE: We actually don't need hold the transaction lock here - // because State::w and State::h are only accessed from - // this thread - Layer::State& editTemp(currentState()); - editTemp.w = editDraw.w; - editTemp.h = editDraw.h; - - // recompute visible region - recomputeVisibleRegions = true; - } - - // we now have the correct size, unfreeze the screen - mFreezeLock.clear(); - } - } else { - // this should not happen unless we ran out of memory while - // allocating the buffer. we're hoping that things will get back - // to normal the next time the app tries to draw into this buffer. - // meanwhile, pretend the screen didn't update. - mPostedDirtyRegion.clear(); - } - - if (lcblk->getQueuedCount()) { - // signal an event if we have more buffers waiting - mFlinger->signalEvent(); - } - - /* a buffer was posted, so we need to call reloadTexture(), which - * will update our internal data structures (eg: EGLImageKHR or - * texture names). we need to do this even if mPostedDirtyRegion is - * empty -- it's orthogonal to the fact that a new buffer was posted, - * for instance, a degenerate case could be that the user did an empty - * update but repainted the buffer with appropriate content (after a - * resize for instance). - */ - reloadTexture( mPostedDirtyRegion ); -} - -void Layer::unlockPageFlip( - const Transform& planeTransform, Region& outDirtyRegion) -{ - Region dirtyRegion(mPostedDirtyRegion); - if (!dirtyRegion.isEmpty()) { - mPostedDirtyRegion.clear(); - // The dirty region is given in the layer's coordinate space - // transform the dirty region by the surface's transformation - // and the global transformation. - const Layer::State& s(drawingState()); - const Transform tr(planeTransform * s.transform); - dirtyRegion = tr.transform(dirtyRegion); - - // At this point, the dirty region is in screen space. - // Make sure it's constrained by the visible region (which - // is in screen space as well). - dirtyRegion.andSelf(visibleRegionScreen); - outDirtyRegion.orSelf(dirtyRegion); - } - if (visibleRegionScreen.isEmpty()) { - // an invisible layer should not hold a freeze-lock - // (because it may never be updated and therefore never release it) - mFreezeLock.clear(); - } -} - -void Layer::finishPageFlip() -{ - ClientRef::Access sharedClient(mUserClientRef); - SharedBufferServer* lcblk(sharedClient.get()); - if (lcblk) { - int buf = mBufferManager.getActiveBufferIndex(); - if (buf >= 0) { - status_t err = lcblk->unlock( buf ); - LOGE_IF(err!=NO_ERROR, - "layer %p, buffer=%d wasn't locked!", - this, buf); - } - } -} - - -void Layer::dump(String8& result, char* buffer, size_t SIZE) const -{ - LayerBaseClient::dump(result, buffer, SIZE); - - ClientRef::Access sharedClient(mUserClientRef); - SharedBufferServer* lcblk(sharedClient.get()); - uint32_t totalTime = 0; - if (lcblk) { - SharedBufferStack::Statistics stats = lcblk->getStats(); - totalTime= stats.totalTime; - result.append( lcblk->dump(" ") ); - } - - sp<const GraphicBuffer> buf0(getBuffer(0)); - sp<const GraphicBuffer> buf1(getBuffer(1)); - uint32_t w0=0, h0=0, s0=0; - uint32_t w1=0, h1=0, s1=0; - if (buf0 != 0) { - w0 = buf0->getWidth(); - h0 = buf0->getHeight(); - s0 = buf0->getStride(); - } - if (buf1 != 0) { - w1 = buf1->getWidth(); - h1 = buf1->getHeight(); - s1 = buf1->getStride(); - } - snprintf(buffer, SIZE, - " " - "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u]," - " freezeLock=%p, dq-q-time=%u us\n", - mFormat, w0, h0, s0, w1, h1, s1, - getFreezeLock().get(), totalTime); - - result.append(buffer); -} - -// --------------------------------------------------------------------------- - -Layer::ClientRef::ClientRef() - : mControlBlock(0), mToken(-1) { -} - -Layer::ClientRef::~ClientRef() { -} - -int32_t Layer::ClientRef::getToken() const { - Mutex::Autolock _l(mLock); - return mToken; -} - -sp<UserClient> Layer::ClientRef::getClient() const { - Mutex::Autolock _l(mLock); - return mUserClient.promote(); -} - -status_t Layer::ClientRef::setToken(const sp<UserClient>& uc, - const sp<SharedBufferServer>& sharedClient, int32_t token) { - Mutex::Autolock _l(mLock); - - { // scope for strong mUserClient reference - sp<UserClient> userClient(mUserClient.promote()); - if (mUserClient != 0 && mControlBlock != 0) { - mControlBlock->setStatus(NO_INIT); - } - } - - mUserClient = uc; - mToken = token; - mControlBlock = sharedClient; - return NO_ERROR; -} - -sp<UserClient> Layer::ClientRef::getUserClientUnsafe() const { - return mUserClient.promote(); -} - -// this class gives us access to SharedBufferServer safely -// it makes sure the UserClient (and its associated shared memory) -// won't go away while we're accessing it. -Layer::ClientRef::Access::Access(const ClientRef& ref) - : mControlBlock(0) -{ - Mutex::Autolock _l(ref.mLock); - mUserClientStrongRef = ref.mUserClient.promote(); - if (mUserClientStrongRef != 0) - mControlBlock = ref.mControlBlock; -} - -Layer::ClientRef::Access::~Access() -{ -} - -// --------------------------------------------------------------------------- - -Layer::BufferManager::BufferManager(TextureManager& tm) - : mNumBuffers(NUM_BUFFERS), mTextureManager(tm), - mActiveBuffer(-1), mFailover(false) -{ -} - -Layer::BufferManager::~BufferManager() -{ -} - -status_t Layer::BufferManager::resize(size_t size) -{ - Mutex::Autolock _l(mLock); - mNumBuffers = size; - return NO_ERROR; -} - -// only for debugging -sp<GraphicBuffer> Layer::BufferManager::getBuffer(size_t index) const { - return mBufferData[index].buffer; -} - -status_t Layer::BufferManager::setActiveBufferIndex(size_t index) { - mActiveBuffer = index; - return NO_ERROR; -} - -size_t Layer::BufferManager::getActiveBufferIndex() const { - return mActiveBuffer; -} - -Texture Layer::BufferManager::getActiveTexture() const { - Texture res; - if (mFailover || mActiveBuffer<0) { - res = mFailoverTexture; - } else { - static_cast<Image&>(res) = mBufferData[mActiveBuffer].texture; - } - return res; -} - -sp<GraphicBuffer> Layer::BufferManager::getActiveBuffer() const { - sp<GraphicBuffer> result; - const ssize_t activeBuffer = mActiveBuffer; - if (activeBuffer >= 0) { - BufferData const * const buffers = mBufferData; - Mutex::Autolock _l(mLock); - result = buffers[activeBuffer].buffer; - } - return result; -} - -sp<GraphicBuffer> Layer::BufferManager::detachBuffer(size_t index) -{ - BufferData* const buffers = mBufferData; - sp<GraphicBuffer> buffer; - Mutex::Autolock _l(mLock); - buffer = buffers[index].buffer; - buffers[index].buffer = 0; - return buffer; -} - -status_t Layer::BufferManager::attachBuffer(size_t index, - const sp<GraphicBuffer>& buffer) -{ - BufferData* const buffers = mBufferData; - Mutex::Autolock _l(mLock); - buffers[index].buffer = buffer; - buffers[index].texture.dirty = true; - return NO_ERROR; -} - -status_t Layer::BufferManager::destroy(EGLDisplay dpy) -{ - BufferData* const buffers = mBufferData; - size_t num; - { // scope for the lock - Mutex::Autolock _l(mLock); - num = mNumBuffers; - for (size_t i=0 ; i<num ; i++) { - buffers[i].buffer = 0; - } - } - for (size_t i=0 ; i<num ; i++) { - destroyTexture(&buffers[i].texture, dpy); - } - destroyTexture(&mFailoverTexture, dpy); - return NO_ERROR; -} - -status_t Layer::BufferManager::initEglImage(EGLDisplay dpy, - const sp<GraphicBuffer>& buffer) -{ - status_t err = NO_INIT; - ssize_t index = mActiveBuffer; - if (index >= 0) { - if (!mFailover) { - Image& texture(mBufferData[index].texture); - err = mTextureManager.initEglImage(&texture, dpy, buffer); - // if EGLImage fails, we switch to regular texture mode, and we - // free all resources associated with using EGLImages. - if (err == NO_ERROR) { - mFailover = false; - destroyTexture(&mFailoverTexture, dpy); - } else { - mFailover = true; - const size_t num = mNumBuffers; - for (size_t i=0 ; i<num ; i++) { - destroyTexture(&mBufferData[i].texture, dpy); - } - } - } else { - // we failed once, don't try again - err = BAD_VALUE; - } - } - return err; -} - -status_t Layer::BufferManager::loadTexture( - const Region& dirty, const GGLSurface& t) -{ - return mTextureManager.loadTexture(&mFailoverTexture, dirty, t); -} - -status_t Layer::BufferManager::destroyTexture(Image* tex, EGLDisplay dpy) -{ - if (tex->name != -1U) { - glDeleteTextures(1, &tex->name); - tex->name = -1U; - } - if (tex->image != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(dpy, tex->image); - tex->image = EGL_NO_IMAGE_KHR; - } - return NO_ERROR; -} - -// --------------------------------------------------------------------------- - -Layer::SurfaceLayer::SurfaceLayer(const sp<SurfaceFlinger>& flinger, - const sp<Layer>& owner) - : Surface(flinger, owner->getIdentity(), owner) -{ -} - -Layer::SurfaceLayer::~SurfaceLayer() -{ -} - -sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage) -{ - sp<GraphicBuffer> buffer; - sp<Layer> owner(getOwner()); - if (owner != 0) { - /* - * requestBuffer() cannot be called from the main thread - * as it could cause a dead-lock, since it may have to wait - * on conditions updated my the main thread. - */ - buffer = owner->requestBuffer(index, w, h, format, usage); - } - return buffer; -} - -status_t Layer::SurfaceLayer::setBufferCount(int bufferCount) -{ - status_t err = DEAD_OBJECT; - sp<Layer> owner(getOwner()); - if (owner != 0) { - /* - * setBufferCount() cannot be called from the main thread - * as it could cause a dead-lock, since it may have to wait - * on conditions updated my the main thread. - */ - err = owner->setBufferCount(bufferCount); - } - return err; -} - -// --------------------------------------------------------------------------- - - -}; // namespace android diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h deleted file mode 100644 index e1d283b..0000000 --- a/libs/surfaceflinger/Layer.h +++ /dev/null @@ -1,239 +0,0 @@ -/* - * 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. - */ - -#ifndef ANDROID_LAYER_H -#define ANDROID_LAYER_H - -#include <stdint.h> -#include <sys/types.h> - -#include <ui/GraphicBuffer.h> -#include <ui/PixelFormat.h> -#include <pixelflinger/pixelflinger.h> - -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <GLES/gl.h> -#include <GLES/glext.h> - -#include "LayerBase.h" -#include "Transform.h" -#include "TextureManager.h" - -namespace android { - -// --------------------------------------------------------------------------- - -class FreezeLock; -class Client; -class GLExtensions; -class UserClient; - -// --------------------------------------------------------------------------- - -class Layer : public LayerBaseClient -{ -public: - Layer(SurfaceFlinger* flinger, DisplayID display, - const sp<Client>& client); - - virtual ~Layer(); - - virtual const char* getTypeId() const { return "Layer"; } - - // the this layer's size and format - status_t setBuffers(uint32_t w, uint32_t h, - PixelFormat format, uint32_t flags=0); - - // associate a UserClient to this Layer - status_t setToken(const sp<UserClient>& uc, SharedClient* sc, int32_t idx); - int32_t getToken() const; - sp<UserClient> getClient() const; - - // Set this Layer's buffers size - void setBufferSize(uint32_t w, uint32_t h); - bool isFixedSize() const; - - // LayerBase interface - virtual void onDraw(const Region& clip) const; - virtual uint32_t doTransaction(uint32_t transactionFlags); - virtual void lockPageFlip(bool& recomputeVisibleRegions); - virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion); - virtual void finishPageFlip(); - virtual bool needsBlending() const { return mNeedsBlending; } - virtual bool needsDithering() const { return mNeedsDithering; } - virtual bool needsFiltering() const; - virtual bool isSecure() const { return mSecure; } - virtual sp<Surface> createSurface() const; - virtual status_t ditch(); - virtual void onRemoved(); - - // only for debugging - inline sp<GraphicBuffer> getBuffer(int i) const { - return mBufferManager.getBuffer(i); } - // only for debugging - inline const sp<FreezeLock>& getFreezeLock() const { - return mFreezeLock; } - -protected: - virtual void dump(String8& result, char* scratch, size_t size) const; - -private: - void reloadTexture(const Region& dirty); - uint32_t getEffectiveUsage(uint32_t usage) const; - sp<GraphicBuffer> requestBuffer(int bufferIdx, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage); - status_t setBufferCount(int bufferCount); - - // ----------------------------------------------------------------------- - - class SurfaceLayer : public LayerBaseClient::Surface { - public: - SurfaceLayer(const sp<SurfaceFlinger>& flinger, const sp<Layer>& owner); - ~SurfaceLayer(); - private: - virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage); - virtual status_t setBufferCount(int bufferCount); - sp<Layer> getOwner() const { - return static_cast<Layer*>(Surface::getOwner().get()); - } - }; - friend class SurfaceLayer; - - // ----------------------------------------------------------------------- - - class ClientRef { - ClientRef(const ClientRef& rhs); - ClientRef& operator = (const ClientRef& rhs); - mutable Mutex mLock; - // binder thread, page-flip thread - sp<SharedBufferServer> mControlBlock; - wp<UserClient> mUserClient; - int32_t mToken; - public: - ClientRef(); - ~ClientRef(); - int32_t getToken() const; - sp<UserClient> getClient() const; - status_t setToken(const sp<UserClient>& uc, - const sp<SharedBufferServer>& sharedClient, int32_t token); - sp<UserClient> getUserClientUnsafe() const; - class Access { - Access(const Access& rhs); - Access& operator = (const Access& rhs); - sp<UserClient> mUserClientStrongRef; - sp<SharedBufferServer> mControlBlock; - public: - Access(const ClientRef& ref); - ~Access(); - inline SharedBufferServer* get() const { return mControlBlock.get(); } - }; - friend class Access; - }; - - // ----------------------------------------------------------------------- - - class BufferManager { - static const size_t NUM_BUFFERS = 2; - struct BufferData { - sp<GraphicBuffer> buffer; - Image texture; - }; - // this lock protect mBufferData[].buffer but since there - // is very little contention, we have only one like for - // the whole array, we also use it to protect mNumBuffers. - mutable Mutex mLock; - BufferData mBufferData[SharedBufferStack::NUM_BUFFER_MAX]; - size_t mNumBuffers; - Texture mFailoverTexture; - TextureManager& mTextureManager; - ssize_t mActiveBuffer; - bool mFailover; - static status_t destroyTexture(Image* tex, EGLDisplay dpy); - - public: - static size_t getDefaultBufferCount() { return NUM_BUFFERS; } - BufferManager(TextureManager& tm); - ~BufferManager(); - - // detach/attach buffer from/to given index - sp<GraphicBuffer> detachBuffer(size_t index); - status_t attachBuffer(size_t index, const sp<GraphicBuffer>& buffer); - // resize the number of active buffers - status_t resize(size_t size); - - // ---------------------------------------------- - // must be called from GL thread - - // set/get active buffer index - status_t setActiveBufferIndex(size_t index); - size_t getActiveBufferIndex() const; - // return the active buffer - sp<GraphicBuffer> getActiveBuffer() const; - // return the active texture (or fail-over) - Texture getActiveTexture() const; - // frees resources associated with all buffers - status_t destroy(EGLDisplay dpy); - // load bitmap data into the active buffer - status_t loadTexture(const Region& dirty, const GGLSurface& t); - // make active buffer an EGLImage if needed - status_t initEglImage(EGLDisplay dpy, - const sp<GraphicBuffer>& buffer); - - // ---------------------------------------------- - // only for debugging - sp<GraphicBuffer> getBuffer(size_t index) const; - }; - - // ----------------------------------------------------------------------- - - // thread-safe - ClientRef mUserClientRef; - - // constants - sp<Surface> mSurface; - PixelFormat mFormat; - const GLExtensions& mGLExtensions; - bool mNeedsBlending; - bool mNeedsDithering; - - // page-flip thread (currently main thread) - bool mSecure; - Region mPostedDirtyRegion; - - // page-flip thread and transaction thread (currently main thread) - sp<FreezeLock> mFreezeLock; - - // see threading usage in declaration - TextureManager mTextureManager; - BufferManager mBufferManager; - - // binder thread, transaction thread - mutable Mutex mLock; - uint32_t mWidth; - uint32_t mHeight; - uint32_t mReqWidth; - uint32_t mReqHeight; - uint32_t mReqFormat; - bool mFixedSize; -}; - -// --------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_LAYER_H diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp deleted file mode 100644 index d5aa53f..0000000 --- a/libs/surfaceflinger/LayerBase.cpp +++ /dev/null @@ -1,593 +0,0 @@ -/* - * 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 <stdlib.h> -#include <stdint.h> -#include <sys/types.h> - -#include <utils/Errors.h> -#include <utils/Log.h> -#include <binder/IPCThreadState.h> -#include <binder/IServiceManager.h> - -#include <GLES/gl.h> -#include <GLES/glext.h> - -#include <hardware/hardware.h> - -#include "clz.h" -#include "LayerBase.h" -#include "SurfaceFlinger.h" -#include "DisplayHardware/DisplayHardware.h" -#include "TextureManager.h" - - -namespace android { - -// --------------------------------------------------------------------------- - -LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display) - : dpy(display), contentDirty(false), - mFlinger(flinger), - mNeedsFiltering(false), - mOrientation(0), - mLeft(0), mTop(0), - mTransactionFlags(0), - mPremultipliedAlpha(true), mName("unnamed"), mDebug(false), - mInvalidate(0) -{ - const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware()); - mFlags = hw.getFlags(); -} - -LayerBase::~LayerBase() -{ -} - -void LayerBase::setName(const String8& name) { - mName = name; -} - -String8 LayerBase::getName() const { - return mName; -} - -const GraphicPlane& LayerBase::graphicPlane(int dpy) const -{ - return mFlinger->graphicPlane(dpy); -} - -GraphicPlane& LayerBase::graphicPlane(int dpy) -{ - return mFlinger->graphicPlane(dpy); -} - -void LayerBase::initStates(uint32_t w, uint32_t h, uint32_t flags) -{ - uint32_t layerFlags = 0; - if (flags & ISurfaceComposer::eHidden) - layerFlags = ISurfaceComposer::eLayerHidden; - - if (flags & ISurfaceComposer::eNonPremultiplied) - mPremultipliedAlpha = false; - - mCurrentState.z = 0; - mCurrentState.w = w; - mCurrentState.h = h; - mCurrentState.requested_w = w; - mCurrentState.requested_h = h; - mCurrentState.alpha = 0xFF; - mCurrentState.flags = layerFlags; - mCurrentState.sequence = 0; - mCurrentState.transform.set(0, 0); - - // drawing state & current state are identical - mDrawingState = mCurrentState; -} - -void LayerBase::commitTransaction() { - mDrawingState = mCurrentState; -} -void LayerBase::forceVisibilityTransaction() { - // this can be called without SurfaceFlinger.mStateLock, but if we - // can atomically increment the sequence number, it doesn't matter. - android_atomic_inc(&mCurrentState.sequence); - requestTransaction(); -} -bool LayerBase::requestTransaction() { - int32_t old = setTransactionFlags(eTransactionNeeded); - return ((old & eTransactionNeeded) == 0); -} -uint32_t LayerBase::getTransactionFlags(uint32_t flags) { - return android_atomic_and(~flags, &mTransactionFlags) & flags; -} -uint32_t LayerBase::setTransactionFlags(uint32_t flags) { - return android_atomic_or(flags, &mTransactionFlags); -} - -bool LayerBase::setPosition(int32_t x, int32_t y) { - if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y) - return false; - mCurrentState.sequence++; - mCurrentState.transform.set(x, y); - requestTransaction(); - return true; -} -bool LayerBase::setLayer(uint32_t z) { - if (mCurrentState.z == z) - return false; - mCurrentState.sequence++; - mCurrentState.z = z; - requestTransaction(); - return true; -} -bool LayerBase::setSize(uint32_t w, uint32_t h) { - if (mCurrentState.requested_w == w && mCurrentState.requested_h == h) - return false; - mCurrentState.requested_w = w; - mCurrentState.requested_h = h; - requestTransaction(); - return true; -} -bool LayerBase::setAlpha(uint8_t alpha) { - if (mCurrentState.alpha == alpha) - return false; - mCurrentState.sequence++; - mCurrentState.alpha = alpha; - requestTransaction(); - return true; -} -bool LayerBase::setMatrix(const layer_state_t::matrix22_t& matrix) { - mCurrentState.sequence++; - mCurrentState.transform.set( - matrix.dsdx, matrix.dsdy, matrix.dtdx, matrix.dtdy); - requestTransaction(); - return true; -} -bool LayerBase::setTransparentRegionHint(const Region& transparent) { - mCurrentState.sequence++; - mCurrentState.transparentRegion = transparent; - requestTransaction(); - return true; -} -bool LayerBase::setFlags(uint8_t flags, uint8_t mask) { - const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask); - if (mCurrentState.flags == newFlags) - return false; - mCurrentState.sequence++; - mCurrentState.flags = newFlags; - requestTransaction(); - return true; -} - -Rect LayerBase::visibleBounds() const -{ - return mTransformedBounds; -} - -void LayerBase::setVisibleRegion(const Region& visibleRegion) { - // always called from main thread - visibleRegionScreen = visibleRegion; -} - -void LayerBase::setCoveredRegion(const Region& coveredRegion) { - // always called from main thread - coveredRegionScreen = coveredRegion; -} - -uint32_t LayerBase::doTransaction(uint32_t flags) -{ - const Layer::State& front(drawingState()); - const Layer::State& temp(currentState()); - - if ((front.requested_w != temp.requested_w) || - (front.requested_h != temp.requested_h)) { - // resize the layer, set the physical size to the requested size - Layer::State& editTemp(currentState()); - editTemp.w = temp.requested_w; - editTemp.h = temp.requested_h; - } - - if ((front.w != temp.w) || (front.h != temp.h)) { - // invalidate and recompute the visible regions if needed - flags |= Layer::eVisibleRegion; - } - - if (temp.sequence != front.sequence) { - // invalidate and recompute the visible regions if needed - flags |= eVisibleRegion; - this->contentDirty = true; - - mNeedsFiltering = false; - if (!(mFlags & DisplayHardware::SLOW_CONFIG)) { - // we may use linear filtering, if the matrix scales us - const uint8_t type = temp.transform.getType(); - if (!temp.transform.preserveRects() || (type >= Transform::SCALE)) { - mNeedsFiltering = true; - } - } - } - - // Commit the transaction - commitTransaction(); - return flags; -} - -void LayerBase::validateVisibility(const Transform& planeTransform) -{ - const Layer::State& s(drawingState()); - const Transform tr(planeTransform * s.transform); - const bool transformed = tr.transformed(); - - uint32_t w = s.w; - uint32_t h = s.h; - tr.transform(mVertices[0], 0, 0); - tr.transform(mVertices[1], 0, h); - tr.transform(mVertices[2], w, h); - tr.transform(mVertices[3], w, 0); - if (UNLIKELY(transformed)) { - // NOTE: here we could also punt if we have too many rectangles - // in the transparent region - if (tr.preserveRects()) { - // transform the transparent region - transparentRegionScreen = tr.transform(s.transparentRegion); - } else { - // transformation too complex, can't do the transparent region - // optimization. - transparentRegionScreen.clear(); - } - } else { - transparentRegionScreen = s.transparentRegion; - } - - // cache a few things... - mOrientation = tr.getOrientation(); - mTransformedBounds = tr.makeBounds(w, h); - mLeft = tr.tx(); - mTop = tr.ty(); -} - -void LayerBase::lockPageFlip(bool& recomputeVisibleRegions) -{ -} - -void LayerBase::unlockPageFlip( - const Transform& planeTransform, Region& outDirtyRegion) -{ - if ((android_atomic_and(~1, &mInvalidate)&1) == 1) { - outDirtyRegion.orSelf(visibleRegionScreen); - } -} - -void LayerBase::finishPageFlip() -{ -} - -void LayerBase::invalidate() -{ - if ((android_atomic_or(1, &mInvalidate)&1) == 0) { - mFlinger->signalEvent(); - } -} - -void LayerBase::drawRegion(const Region& reg) const -{ - Region::const_iterator it = reg.begin(); - Region::const_iterator const end = reg.end(); - if (it != end) { - Rect r; - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const int32_t fbWidth = hw.getWidth(); - const int32_t fbHeight = hw.getHeight(); - const GLshort vertices[][2] = { { 0, 0 }, { fbWidth, 0 }, - { fbWidth, fbHeight }, { 0, fbHeight } }; - glVertexPointer(2, GL_SHORT, 0, vertices); - while (it != end) { - const Rect& r = *it++; - const GLint sy = fbHeight - (r.top + r.height()); - glScissor(r.left, sy, r.width(), r.height()); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - } - } -} - -void LayerBase::draw(const Region& inClip) const -{ - // invalidate the region we'll update - Region clip(inClip); // copy-on-write, so no-op most of the time - - // Remove the transparent area from the clipping region - const State& s = drawingState(); - if (LIKELY(!s.transparentRegion.isEmpty())) { - clip.subtract(transparentRegionScreen); - if (clip.isEmpty()) { - // usually this won't happen because this should be taken care of - // by SurfaceFlinger::computeVisibleRegions() - return; - } - } - - // reset GL state - glEnable(GL_SCISSOR_TEST); - - onDraw(clip); -} - -void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red, - GLclampf green, GLclampf blue, - GLclampf alpha) const -{ - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const uint32_t fbHeight = hw.getHeight(); - glColor4f(red,green,blue,alpha); - - TextureManager::deactivateTextures(); - - glDisable(GL_BLEND); - glDisable(GL_DITHER); - - Region::const_iterator it = clip.begin(); - Region::const_iterator const end = clip.end(); - glEnable(GL_SCISSOR_TEST); - glVertexPointer(2, GL_FLOAT, 0, mVertices); - while (it != end) { - const Rect& r = *it++; - const GLint sy = fbHeight - (r.top + r.height()); - glScissor(r.left, sy, r.width(), r.height()); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - } -} - -void LayerBase::clearWithOpenGL(const Region& clip) const -{ - clearWithOpenGL(clip,0,0,0,0); -} - -void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const -{ - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const uint32_t fbHeight = hw.getHeight(); - const State& s(drawingState()); - - // bind our texture - TextureManager::activateTexture(texture, needsFiltering()); - uint32_t width = texture.width; - uint32_t height = texture.height; - - GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA; - if (UNLIKELY(s.alpha < 0xFF)) { - const GLfloat alpha = s.alpha * (1.0f/255.0f); - if (mPremultipliedAlpha) { - glColor4f(alpha, alpha, alpha, alpha); - } else { - glColor4f(1, 1, 1, alpha); - } - glEnable(GL_BLEND); - glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA); - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - } else { - glColor4f(1, 1, 1, 1); - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - if (needsBlending()) { - glEnable(GL_BLEND); - glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA); - } else { - glDisable(GL_BLEND); - } - } - - Region::const_iterator it = clip.begin(); - Region::const_iterator const end = clip.end(); - const GLfloat texCoords[4][2] = { - { 0, 0 }, - { 0, 1 }, - { 1, 1 }, - { 1, 0 } - }; - - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - - // the texture's source is rotated - switch (texture.transform) { - case HAL_TRANSFORM_ROT_90: - glTranslatef(0, 1, 0); - glRotatef(-90, 0, 0, 1); - break; - case HAL_TRANSFORM_ROT_180: - glTranslatef(1, 1, 0); - glRotatef(-180, 0, 0, 1); - break; - case HAL_TRANSFORM_ROT_270: - glTranslatef(1, 0, 0); - glRotatef(-270, 0, 0, 1); - break; - } - - if (texture.NPOTAdjust) { - glScalef(texture.wScale, texture.hScale, 1.0f); - } - - if (needsDithering()) { - glEnable(GL_DITHER); - } else { - glDisable(GL_DITHER); - } - - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, mVertices); - glTexCoordPointer(2, GL_FLOAT, 0, texCoords); - - while (it != end) { - const Rect& r = *it++; - const GLint sy = fbHeight - (r.top + r.height()); - glScissor(r.left, sy, r.width(), r.height()); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - } - glDisableClientState(GL_TEXTURE_COORD_ARRAY); -} - -void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const -{ - const Layer::State& s(drawingState()); - snprintf(buffer, SIZE, - "+ %s %p\n" - " " - "z=%9d, pos=(%4d,%4d), size=(%4d,%4d), " - "needsBlending=%1d, needsDithering=%1d, invalidate=%1d, " - "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n", - getTypeId(), this, s.z, tx(), ty(), s.w, s.h, - needsBlending(), needsDithering(), contentDirty, - s.alpha, s.flags, - s.transform[0][0], s.transform[0][1], - s.transform[1][0], s.transform[1][1]); - result.append(buffer); -} - -// --------------------------------------------------------------------------- - -int32_t LayerBaseClient::sIdentity = 1; - -LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display, - const sp<Client>& client) - : LayerBase(flinger, display), mClientRef(client), - mIdentity(uint32_t(android_atomic_inc(&sIdentity))) -{ -} - -LayerBaseClient::~LayerBaseClient() -{ - sp<Client> c(mClientRef.promote()); - if (c != 0) { - c->detachLayer(this); - } -} - -sp<LayerBaseClient::Surface> LayerBaseClient::getSurface() -{ - sp<Surface> s; - Mutex::Autolock _l(mLock); - s = mClientSurface.promote(); - if (s == 0) { - s = createSurface(); - mClientSurface = s; - } - return s; -} - -sp<LayerBaseClient::Surface> LayerBaseClient::createSurface() const -{ - return new Surface(mFlinger, mIdentity, - const_cast<LayerBaseClient *>(this)); -} - -void LayerBaseClient::dump(String8& result, char* buffer, size_t SIZE) const -{ - LayerBase::dump(result, buffer, SIZE); - - sp<Client> client(mClientRef.promote()); - snprintf(buffer, SIZE, - " name=%s\n" - " client=%p, identity=%u\n", - getName().string(), - client.get(), getIdentity()); - - result.append(buffer); -} - -// --------------------------------------------------------------------------- - -LayerBaseClient::Surface::Surface( - const sp<SurfaceFlinger>& flinger, - int identity, - const sp<LayerBaseClient>& owner) - : mFlinger(flinger), mIdentity(identity), mOwner(owner) -{ -} - -LayerBaseClient::Surface::~Surface() -{ - /* - * This is a good place to clean-up all client resources - */ - - // destroy client resources - sp<LayerBaseClient> layer = getOwner(); - if (layer != 0) { - mFlinger->destroySurface(layer); - } -} - -sp<LayerBaseClient> LayerBaseClient::Surface::getOwner() const { - sp<LayerBaseClient> owner(mOwner.promote()); - return owner; -} - -status_t LayerBaseClient::Surface::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - switch (code) { - case REGISTER_BUFFERS: - case UNREGISTER_BUFFERS: - case CREATE_OVERLAY: - { - if (!mFlinger->mAccessSurfaceFlinger.checkCalling()) { - IPCThreadState* ipc = IPCThreadState::self(); - const int pid = ipc->getCallingPid(); - const int uid = ipc->getCallingUid(); - LOGE("Permission Denial: " - "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); - return PERMISSION_DENIED; - } - } - } - return BnSurface::onTransact(code, data, reply, flags); -} - -sp<GraphicBuffer> LayerBaseClient::Surface::requestBuffer(int bufferIdx, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage) -{ - return NULL; -} - -status_t LayerBaseClient::Surface::setBufferCount(int bufferCount) -{ - return INVALID_OPERATION; -} - -status_t LayerBaseClient::Surface::registerBuffers( - const ISurface::BufferHeap& buffers) -{ - return INVALID_OPERATION; -} - -void LayerBaseClient::Surface::postBuffer(ssize_t offset) -{ -} - -void LayerBaseClient::Surface::unregisterBuffers() -{ -} - -sp<OverlayRef> LayerBaseClient::Surface::createOverlay( - uint32_t w, uint32_t h, int32_t format, int32_t orientation) -{ - return NULL; -}; - -// --------------------------------------------------------------------------- - -}; // namespace android diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h deleted file mode 100644 index 4288cf7..0000000 --- a/libs/surfaceflinger/LayerBase.h +++ /dev/null @@ -1,333 +0,0 @@ -/* - * 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. - */ - -#ifndef ANDROID_LAYER_BASE_H -#define ANDROID_LAYER_BASE_H - -#include <stdint.h> -#include <sys/types.h> - -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <GLES/gl.h> - -#include <utils/RefBase.h> - -#include <ui/Region.h> -#include <ui/Overlay.h> - -#include <surfaceflinger/ISurfaceComposerClient.h> -#include <private/surfaceflinger/SharedBufferStack.h> -#include <private/surfaceflinger/LayerState.h> - -#include <pixelflinger/pixelflinger.h> - -#include "Transform.h" - -namespace android { - -// --------------------------------------------------------------------------- - -class DisplayHardware; -class Client; -class GraphicBuffer; -class GraphicPlane; -class LayerBaseClient; -class SurfaceFlinger; -class Texture; - -// --------------------------------------------------------------------------- - -class LayerBase : public RefBase -{ -public: - LayerBase(SurfaceFlinger* flinger, DisplayID display); - - DisplayID dpy; - mutable bool contentDirty; - Region visibleRegionScreen; - Region transparentRegionScreen; - Region coveredRegionScreen; - - struct State { - uint32_t w; - uint32_t h; - uint32_t requested_w; - uint32_t requested_h; - uint32_t z; - uint8_t alpha; - uint8_t flags; - uint8_t reserved[2]; - int32_t sequence; // changes when visible regions can change - uint32_t tint; - Transform transform; - Region transparentRegion; - }; - - void setName(const String8& name); - String8 getName() const; - - // modify current state - bool setPosition(int32_t x, int32_t y); - bool setLayer(uint32_t z); - bool setSize(uint32_t w, uint32_t h); - bool setAlpha(uint8_t alpha); - bool setMatrix(const layer_state_t::matrix22_t& matrix); - bool setTransparentRegionHint(const Region& opaque); - bool setFlags(uint8_t flags, uint8_t mask); - - void commitTransaction(); - bool requestTransaction(); - void forceVisibilityTransaction(); - - uint32_t getTransactionFlags(uint32_t flags); - uint32_t setTransactionFlags(uint32_t flags); - - Rect visibleBounds() const; - void drawRegion(const Region& reg) const; - - void invalidate(); - - virtual sp<LayerBaseClient> getLayerBaseClient() const { return 0; } - - virtual const char* getTypeId() const { return "LayerBase"; } - - /** - * draw - performs some global clipping optimizations - * and calls onDraw(). - * Typically this method is not overridden, instead implement onDraw() - * to perform the actual drawing. - */ - virtual void draw(const Region& clip) const; - - /** - * onDraw - draws the surface. - */ - virtual void onDraw(const Region& clip) const = 0; - - /** - * initStates - called just after construction - */ - virtual void initStates(uint32_t w, uint32_t h, uint32_t flags); - - /** - * doTransaction - process the transaction. This is a good place to figure - * out which attributes of the surface have changed. - */ - virtual uint32_t doTransaction(uint32_t transactionFlags); - - /** - * setVisibleRegion - called to set the new visible region. This gives - * a chance to update the new visible region or record the fact it changed. - */ - virtual void setVisibleRegion(const Region& visibleRegion); - - /** - * setCoveredRegion - called when the covered region changes. The covered - * region corresponds to any area of the surface that is covered - * (transparently or not) by another surface. - */ - virtual void setCoveredRegion(const Region& coveredRegion); - - /** - * validateVisibility - cache a bunch of things - */ - virtual void validateVisibility(const Transform& globalTransform); - - /** - * lockPageFlip - called each time the screen is redrawn and returns whether - * the visible regions need to be recomputed (this is a fairly heavy - * operation, so this should be set only if needed). Typically this is used - * to figure out if the content or size of a surface has changed. - */ - virtual void lockPageFlip(bool& recomputeVisibleRegions); - - /** - * unlockPageFlip - called each time the screen is redrawn. updates the - * final dirty region wrt the planeTransform. - * At this point, all visible regions, surface position and size, etc... are - * correct. - */ - virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion); - - /** - * finishPageFlip - called after all surfaces have drawn. - */ - virtual void finishPageFlip(); - - /** - * needsBlending - true if this surface needs blending - */ - virtual bool needsBlending() const { return false; } - - /** - * needsDithering - true if this surface needs dithering - */ - virtual bool needsDithering() const { return false; } - - /** - * needsLinearFiltering - true if this surface needs filtering - */ - virtual bool needsFiltering() const { return mNeedsFiltering; } - - /** - * isSecure - true if this surface is secure, that is if it prevents - * screenshots or VNC servers. - */ - virtual bool isSecure() const { return false; } - - /** Called from the main thread, when the surface is removed from the - * draw list */ - virtual status_t ditch() { return NO_ERROR; } - - /** called with the state lock when the surface is removed from the - * current list */ - virtual void onRemoved() { }; - - /** always call base class first */ - virtual void dump(String8& result, char* scratch, size_t size) const; - - - enum { // flags for doTransaction() - eVisibleRegion = 0x00000002, - }; - - - inline const State& drawingState() const { return mDrawingState; } - inline const State& currentState() const { return mCurrentState; } - inline State& currentState() { return mCurrentState; } - - static int compareCurrentStateZ( - sp<LayerBase> const * layerA, - sp<LayerBase> const * layerB) { - return layerA[0]->currentState().z - layerB[0]->currentState().z; - } - - int32_t getOrientation() const { return mOrientation; } - int tx() const { return mLeft; } - int ty() const { return mTop; } - -protected: - const GraphicPlane& graphicPlane(int dpy) const; - GraphicPlane& graphicPlane(int dpy); - - void clearWithOpenGL(const Region& clip, GLclampf r, GLclampf g, - GLclampf b, GLclampf alpha) const; - void clearWithOpenGL(const Region& clip) const; - void drawWithOpenGL(const Region& clip, const Texture& texture) const; - - sp<SurfaceFlinger> mFlinger; - uint32_t mFlags; - - // cached during validateVisibility() - bool mNeedsFiltering; - int32_t mOrientation; - GLfloat mVertices[4][2]; - Rect mTransformedBounds; - int mLeft; - int mTop; - - // these are protected by an external lock - State mCurrentState; - State mDrawingState; - volatile int32_t mTransactionFlags; - - // don't change, don't need a lock - bool mPremultipliedAlpha; - String8 mName; - mutable bool mDebug; - - - // atomic - volatile int32_t mInvalidate; - - -protected: - virtual ~LayerBase(); - -private: - LayerBase(const LayerBase& rhs); -}; - - -// --------------------------------------------------------------------------- - -class LayerBaseClient : public LayerBase -{ -public: - class Surface; - - LayerBaseClient(SurfaceFlinger* flinger, DisplayID display, - const sp<Client>& client); - virtual ~LayerBaseClient(); - - sp<Surface> getSurface(); - virtual sp<Surface> createSurface() const; - virtual sp<LayerBaseClient> getLayerBaseClient() const { - return const_cast<LayerBaseClient*>(this); } - virtual const char* getTypeId() const { return "LayerBaseClient"; } - - uint32_t getIdentity() const { return mIdentity; } - - class Surface : public BnSurface { - public: - int32_t getIdentity() const { return mIdentity; } - - protected: - Surface(const sp<SurfaceFlinger>& flinger, int identity, - const sp<LayerBaseClient>& owner); - virtual ~Surface(); - virtual status_t onTransact(uint32_t code, const Parcel& data, - Parcel* reply, uint32_t flags); - sp<LayerBaseClient> getOwner() const; - - private: - virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage); - virtual status_t setBufferCount(int bufferCount); - - virtual status_t registerBuffers(const ISurface::BufferHeap& buffers); - virtual void postBuffer(ssize_t offset); - virtual void unregisterBuffers(); - virtual sp<OverlayRef> createOverlay(uint32_t w, uint32_t h, - int32_t format, int32_t orientation); - - protected: - friend class LayerBaseClient; - sp<SurfaceFlinger> mFlinger; - int32_t mIdentity; - wp<LayerBaseClient> mOwner; - }; - - friend class Surface; - -protected: - virtual void dump(String8& result, char* scratch, size_t size) const; - -private: - mutable Mutex mLock; - mutable wp<Surface> mClientSurface; - const wp<Client> mClientRef; - // only read - const uint32_t mIdentity; - static int32_t sIdentity; -}; - -// --------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_LAYER_BASE_H diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp deleted file mode 100644 index 64a43c7..0000000 --- a/libs/surfaceflinger/LayerBlur.cpp +++ /dev/null @@ -1,249 +0,0 @@ -/* - * 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 <stdlib.h> -#include <stdint.h> -#include <sys/types.h> - -#include <utils/Errors.h> -#include <utils/Log.h> - -#include <GLES/gl.h> -#include <GLES/glext.h> - -#include "clz.h" -#include "BlurFilter.h" -#include "LayerBlur.h" -#include "SurfaceFlinger.h" -#include "DisplayHardware/DisplayHardware.h" - -namespace android { -// --------------------------------------------------------------------------- - -LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display, - const sp<Client>& client) - : LayerBaseClient(flinger, display, client), mCacheDirty(true), - mRefreshCache(true), mCacheAge(0), mTextureName(-1U), - mWidthScale(1.0f), mHeightScale(1.0f), - mBlurFormat(GGL_PIXEL_FORMAT_RGB_565) -{ -} - -LayerBlur::~LayerBlur() -{ - if (mTextureName != -1U) { - glDeleteTextures(1, &mTextureName); - } -} - -void LayerBlur::setVisibleRegion(const Region& visibleRegion) -{ - LayerBaseClient::setVisibleRegion(visibleRegion); - if (visibleRegionScreen.isEmpty()) { - if (mTextureName != -1U) { - // We're not visible, free the texture up. - glBindTexture(GL_TEXTURE_2D, 0); - glDeleteTextures(1, &mTextureName); - mTextureName = -1U; - } - } -} - -uint32_t LayerBlur::doTransaction(uint32_t flags) -{ - // we're doing a transaction, refresh the cache! - if (!mFlinger->isFrozen()) { - mRefreshCache = true; - mCacheDirty = true; - flags |= eVisibleRegion; - this->contentDirty = true; - } - return LayerBase::doTransaction(flags); -} - -void LayerBlur::unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion) -{ - // this code-path must be as tight as possible, it's called each time - // the screen is composited. - if (UNLIKELY(!visibleRegionScreen.isEmpty())) { - // if anything visible below us is invalidated, the cache becomes dirty - if (!mCacheDirty && - !visibleRegionScreen.intersect(outDirtyRegion).isEmpty()) { - mCacheDirty = true; - } - if (mCacheDirty) { - if (!mFlinger->isFrozen()) { - // update everything below us that is visible - outDirtyRegion.orSelf(visibleRegionScreen); - nsecs_t now = systemTime(); - if ((now - mCacheAge) >= ms2ns(500)) { - mCacheAge = now; - mRefreshCache = true; - mCacheDirty = false; - } else { - if (!mAutoRefreshPending) { - mFlinger->postMessageAsync( - new MessageBase(MessageQueue::INVALIDATE), - ms2ns(500)); - mAutoRefreshPending = true; - } - } - } - } - } - LayerBase::unlockPageFlip(planeTransform, outDirtyRegion); -} - -void LayerBlur::onDraw(const Region& clip) const -{ - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const uint32_t fbHeight = hw.getHeight(); - int x = mTransformedBounds.left; - int y = mTransformedBounds.top; - int w = mTransformedBounds.width(); - int h = mTransformedBounds.height(); - GLint X = x; - GLint Y = fbHeight - (y + h); - if (X < 0) { - w += X; - X = 0; - } - if (Y < 0) { - h += Y; - Y = 0; - } - if (w<0 || h<0) { - // we're outside of the framebuffer - return; - } - - if (mTextureName == -1U) { - // create the texture name the first time - // can't do that in the ctor, because it runs in another thread. - glGenTextures(1, &mTextureName); - glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, &mReadFormat); - glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, &mReadType); - if (mReadFormat != GL_RGB || mReadType != GL_UNSIGNED_SHORT_5_6_5) { - mReadFormat = GL_RGBA; - mReadType = GL_UNSIGNED_BYTE; - mBlurFormat = GGL_PIXEL_FORMAT_RGBX_8888; - } - } - - Region::const_iterator it = clip.begin(); - Region::const_iterator const end = clip.end(); - if (it != end) { -#if defined(GL_OES_texture_external) - if (GLExtensions::getInstance().haveTextureExternal()) { - glDisable(GL_TEXTURE_EXTERNAL_OES); - } -#endif - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, mTextureName); - - if (mRefreshCache) { - mRefreshCache = false; - mAutoRefreshPending = false; - - int32_t pixelSize = 4; - int32_t s = w; - if (mReadType == GL_UNSIGNED_SHORT_5_6_5) { - // allocate enough memory for 4-bytes (2 pixels) aligned data - s = (w + 1) & ~1; - pixelSize = 2; - } - - uint16_t* const pixels = (uint16_t*)malloc(s*h*pixelSize); - - // This reads the frame-buffer, so a h/w GL would have to - // finish() its rendering first. we don't want to do that - // too often. Read data is 4-bytes aligned. - glReadPixels(X, Y, w, h, mReadFormat, mReadType, pixels); - - // blur that texture. - GGLSurface bl; - bl.version = sizeof(GGLSurface); - bl.width = w; - bl.height = h; - bl.stride = s; - bl.format = mBlurFormat; - bl.data = (GGLubyte*)pixels; - blurFilter(&bl, 8, 2); - - if (GLExtensions::getInstance().haveNpot()) { - glTexImage2D(GL_TEXTURE_2D, 0, mReadFormat, w, h, 0, - mReadFormat, mReadType, pixels); - mWidthScale = 1.0f / w; - mHeightScale =-1.0f / h; - mYOffset = 0; - } else { - GLuint tw = 1 << (31 - clz(w)); - GLuint th = 1 << (31 - clz(h)); - if (tw < GLuint(w)) tw <<= 1; - if (th < GLuint(h)) th <<= 1; - glTexImage2D(GL_TEXTURE_2D, 0, mReadFormat, tw, th, 0, - mReadFormat, mReadType, NULL); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, - mReadFormat, mReadType, pixels); - mWidthScale = 1.0f / tw; - mHeightScale =-1.0f / th; - mYOffset = th-h; - } - - free((void*)pixels); - } - - const State& s = drawingState(); - if (UNLIKELY(s.alpha < 0xFF)) { - const GLfloat alpha = s.alpha * (1.0f/255.0f); - glColor4f(0, 0, 0, alpha); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - } else { - glDisable(GL_BLEND); - } - - if (mFlags & DisplayHardware::SLOW_CONFIG) { - glDisable(GL_DITHER); - } else { - glEnable(GL_DITHER); - } - - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glScalef(mWidthScale, mHeightScale, 1); - glTranslatef(-x, mYOffset - y, 0); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, mVertices); - glTexCoordPointer(2, GL_FLOAT, 0, mVertices); - while (it != end) { - const Rect& r = *it++; - const GLint sy = fbHeight - (r.top + r.height()); - glScissor(r.left, sy, r.width(), r.height()); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - } - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - } -} - -// --------------------------------------------------------------------------- - -}; // namespace android diff --git a/libs/surfaceflinger/LayerBlur.h b/libs/surfaceflinger/LayerBlur.h deleted file mode 100644 index 4c9ec64..0000000 --- a/libs/surfaceflinger/LayerBlur.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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. - */ - -#ifndef ANDROID_LAYER_BLUR_H -#define ANDROID_LAYER_BLUR_H - -#include <stdint.h> -#include <sys/types.h> - -#include <ui/Region.h> - -#include "LayerBase.h" - -namespace android { - -// --------------------------------------------------------------------------- - -class LayerBlur : public LayerBaseClient -{ -public: - LayerBlur(SurfaceFlinger* flinger, DisplayID display, - const sp<Client>& client); - virtual ~LayerBlur(); - - virtual void onDraw(const Region& clip) const; - virtual bool needsBlending() const { return true; } - virtual bool isSecure() const { return false; } - virtual const char* getTypeId() const { return "LayerBlur"; } - - virtual uint32_t doTransaction(uint32_t flags); - virtual void setVisibleRegion(const Region& visibleRegion); - virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion); - -private: - bool mCacheDirty; - mutable bool mRefreshCache; - mutable bool mAutoRefreshPending; - nsecs_t mCacheAge; - mutable GLuint mTextureName; - mutable GLfloat mWidthScale; - mutable GLfloat mHeightScale; - mutable GLfloat mYOffset; - mutable GLint mReadFormat; - mutable GLint mReadType; - mutable uint32_t mBlurFormat; -}; - -// --------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_LAYER_BLUR_H diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp deleted file mode 100644 index 5f83636..0000000 --- a/libs/surfaceflinger/LayerBuffer.cpp +++ /dev/null @@ -1,682 +0,0 @@ -/* - * 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 <stdlib.h> -#include <stdint.h> -#include <math.h> -#include <sys/types.h> - -#include <utils/Errors.h> -#include <utils/Log.h> -#include <utils/StopWatch.h> - -#include <ui/GraphicBuffer.h> -#include <ui/PixelFormat.h> -#include <ui/FramebufferNativeWindow.h> -#include <ui/Rect.h> -#include <ui/Region.h> - -#include <hardware/copybit.h> - -#include "LayerBuffer.h" -#include "SurfaceFlinger.h" -#include "DisplayHardware/DisplayHardware.h" - -namespace android { - -// --------------------------------------------------------------------------- - -gralloc_module_t const* LayerBuffer::sGrallocModule = 0; - -// --------------------------------------------------------------------------- - -LayerBuffer::LayerBuffer(SurfaceFlinger* flinger, DisplayID display, - const sp<Client>& client) - : LayerBaseClient(flinger, display, client), - mNeedsBlending(false), mBlitEngine(0) -{ -} - -LayerBuffer::~LayerBuffer() -{ - if (mBlitEngine) { - copybit_close(mBlitEngine); - } -} - -void LayerBuffer::onFirstRef() -{ - LayerBaseClient::onFirstRef(); - mSurface = new SurfaceLayerBuffer(mFlinger, this); - - hw_module_t const* module = (hw_module_t const*)sGrallocModule; - if (!module) { - // NOTE: technically there is a race here, but it shouldn't - // cause any problem since hw_get_module() always returns - // the same value. - if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) { - sGrallocModule = (gralloc_module_t const *)module; - } - } - - if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) { - copybit_open(module, &mBlitEngine); - } -} - -sp<LayerBaseClient::Surface> LayerBuffer::createSurface() const -{ - return mSurface; -} - -status_t LayerBuffer::ditch() -{ - mSurface.clear(); - return NO_ERROR; -} - -bool LayerBuffer::needsBlending() const { - return mNeedsBlending; -} - -void LayerBuffer::setNeedsBlending(bool blending) { - mNeedsBlending = blending; -} - -void LayerBuffer::postBuffer(ssize_t offset) -{ - sp<Source> source(getSource()); - if (source != 0) - source->postBuffer(offset); -} - -void LayerBuffer::unregisterBuffers() -{ - sp<Source> source(clearSource()); - if (source != 0) - source->unregisterBuffers(); -} - -uint32_t LayerBuffer::doTransaction(uint32_t flags) -{ - sp<Source> source(getSource()); - if (source != 0) - source->onTransaction(flags); - uint32_t res = LayerBase::doTransaction(flags); - // we always want filtering for these surfaces - mNeedsFiltering = !(mFlags & DisplayHardware::SLOW_CONFIG); - return res; -} - -void LayerBuffer::unlockPageFlip(const Transform& planeTransform, - Region& outDirtyRegion) -{ - // this code-path must be as tight as possible, it's called each time - // the screen is composited. - sp<Source> source(getSource()); - if (source != 0) - source->onVisibilityResolved(planeTransform); - LayerBase::unlockPageFlip(planeTransform, outDirtyRegion); -} - -void LayerBuffer::onDraw(const Region& clip) const -{ - sp<Source> source(getSource()); - if (LIKELY(source != 0)) { - source->onDraw(clip); - } else { - clearWithOpenGL(clip); - } -} - -void LayerBuffer::serverDestroy() -{ - sp<Source> source(clearSource()); - if (source != 0) { - source->destroy(); - } -} - -/** - * This creates a "buffer" source for this surface - */ -status_t LayerBuffer::registerBuffers(const ISurface::BufferHeap& buffers) -{ - Mutex::Autolock _l(mLock); - if (mSource != 0) - return INVALID_OPERATION; - - sp<BufferSource> source = new BufferSource(*this, buffers); - - status_t result = source->getStatus(); - if (result == NO_ERROR) { - mSource = source; - } - return result; -} - -/** - * This creates an "overlay" source for this surface - */ -sp<OverlayRef> LayerBuffer::createOverlay(uint32_t w, uint32_t h, int32_t f, - int32_t orientation) -{ - sp<OverlayRef> result; - Mutex::Autolock _l(mLock); - if (mSource != 0) - return result; - - sp<OverlaySource> source = new OverlaySource(*this, &result, w, h, f, orientation); - if (result != 0) { - mSource = source; - } - return result; -} - -sp<LayerBuffer::Source> LayerBuffer::getSource() const { - Mutex::Autolock _l(mLock); - return mSource; -} - -sp<LayerBuffer::Source> LayerBuffer::clearSource() { - sp<Source> source; - Mutex::Autolock _l(mLock); - source = mSource; - mSource.clear(); - return source; -} - -// ============================================================================ -// LayerBuffer::SurfaceLayerBuffer -// ============================================================================ - -LayerBuffer::SurfaceLayerBuffer::SurfaceLayerBuffer( - const sp<SurfaceFlinger>& flinger, const sp<LayerBuffer>& owner) - : LayerBaseClient::Surface(flinger, owner->getIdentity(), owner) -{ -} - -LayerBuffer::SurfaceLayerBuffer::~SurfaceLayerBuffer() -{ - unregisterBuffers(); -} - -status_t LayerBuffer::SurfaceLayerBuffer::registerBuffers( - const ISurface::BufferHeap& buffers) -{ - sp<LayerBuffer> owner(getOwner()); - if (owner != 0) - return owner->registerBuffers(buffers); - return NO_INIT; -} - -void LayerBuffer::SurfaceLayerBuffer::postBuffer(ssize_t offset) -{ - sp<LayerBuffer> owner(getOwner()); - if (owner != 0) - owner->postBuffer(offset); -} - -void LayerBuffer::SurfaceLayerBuffer::unregisterBuffers() -{ - sp<LayerBuffer> owner(getOwner()); - if (owner != 0) - owner->unregisterBuffers(); -} - -sp<OverlayRef> LayerBuffer::SurfaceLayerBuffer::createOverlay( - uint32_t w, uint32_t h, int32_t format, int32_t orientation) { - sp<OverlayRef> result; - sp<LayerBuffer> owner(getOwner()); - if (owner != 0) - result = owner->createOverlay(w, h, format, orientation); - return result; -} - -// ============================================================================ -// LayerBuffer::Buffer -// ============================================================================ - -LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers, - ssize_t offset, size_t bufferSize) - : mBufferHeap(buffers), mSupportsCopybit(false) -{ - NativeBuffer& src(mNativeBuffer); - src.crop.l = 0; - src.crop.t = 0; - src.crop.r = buffers.w; - src.crop.b = buffers.h; - - src.img.w = buffers.hor_stride ?: buffers.w; - src.img.h = buffers.ver_stride ?: buffers.h; - src.img.format = buffers.format; - src.img.base = (void*)(intptr_t(buffers.heap->base()) + offset); - src.img.handle = 0; - - gralloc_module_t const * module = LayerBuffer::getGrallocModule(); - if (module && module->perform) { - int err = module->perform(module, - GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER, - buffers.heap->heapID(), bufferSize, - offset, buffers.heap->base(), - &src.img.handle); - - // we can fail here is the passed buffer is purely software - mSupportsCopybit = (err == NO_ERROR); - } - } - -LayerBuffer::Buffer::~Buffer() -{ - NativeBuffer& src(mNativeBuffer); - if (src.img.handle) { - native_handle_delete(src.img.handle); - } -} - -// ============================================================================ -// LayerBuffer::Source -// LayerBuffer::BufferSource -// LayerBuffer::OverlaySource -// ============================================================================ - -LayerBuffer::Source::Source(LayerBuffer& layer) - : mLayer(layer) -{ -} -LayerBuffer::Source::~Source() { -} -void LayerBuffer::Source::onDraw(const Region& clip) const { -} -void LayerBuffer::Source::onTransaction(uint32_t flags) { -} -void LayerBuffer::Source::onVisibilityResolved( - const Transform& planeTransform) { -} -void LayerBuffer::Source::postBuffer(ssize_t offset) { -} -void LayerBuffer::Source::unregisterBuffers() { -} - -// --------------------------------------------------------------------------- - -LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer, - const ISurface::BufferHeap& buffers) - : Source(layer), mStatus(NO_ERROR), mBufferSize(0) -{ - if (buffers.heap == NULL) { - // this is allowed, but in this case, it is illegal to receive - // postBuffer(). The surface just erases the framebuffer with - // fully transparent pixels. - mBufferHeap = buffers; - mLayer.setNeedsBlending(false); - return; - } - - status_t err = (buffers.heap->heapID() >= 0) ? NO_ERROR : NO_INIT; - if (err != NO_ERROR) { - LOGE("LayerBuffer::BufferSource: invalid heap (%s)", strerror(err)); - mStatus = err; - return; - } - - PixelFormatInfo info; - err = getPixelFormatInfo(buffers.format, &info); - if (err != NO_ERROR) { - LOGE("LayerBuffer::BufferSource: invalid format %d (%s)", - buffers.format, strerror(err)); - mStatus = err; - return; - } - - if (buffers.hor_stride<0 || buffers.ver_stride<0) { - LOGE("LayerBuffer::BufferSource: invalid parameters " - "(w=%d, h=%d, xs=%d, ys=%d)", - buffers.w, buffers.h, buffers.hor_stride, buffers.ver_stride); - mStatus = BAD_VALUE; - return; - } - - mBufferHeap = buffers; - mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0); - mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride; - mLayer.forceVisibilityTransaction(); -} - -LayerBuffer::BufferSource::~BufferSource() -{ - class MessageDestroyTexture : public MessageBase { - SurfaceFlinger* flinger; - GLuint name; - public: - MessageDestroyTexture( - SurfaceFlinger* flinger, GLuint name) - : flinger(flinger), name(name) { } - virtual bool handler() { - glDeleteTextures(1, &name); - return true; - } - }; - - if (mTexture.name != -1U) { - // GL textures can only be destroyed from the GL thread - getFlinger()->mEventQueue.postMessage( - new MessageDestroyTexture(getFlinger(), mTexture.name) ); - } - if (mTexture.image != EGL_NO_IMAGE_KHR) { - EGLDisplay dpy(getFlinger()->graphicPlane(0).getEGLDisplay()); - eglDestroyImageKHR(dpy, mTexture.image); - } -} - -void LayerBuffer::BufferSource::postBuffer(ssize_t offset) -{ - ISurface::BufferHeap buffers; - { // scope for the lock - Mutex::Autolock _l(mBufferSourceLock); - buffers = mBufferHeap; - if (buffers.heap != 0) { - const size_t memorySize = buffers.heap->getSize(); - if ((size_t(offset) + mBufferSize) > memorySize) { - LOGE("LayerBuffer::BufferSource::postBuffer() " - "invalid buffer (offset=%d, size=%d, heap-size=%d", - int(offset), int(mBufferSize), int(memorySize)); - return; - } - } - } - - sp<Buffer> buffer; - if (buffers.heap != 0) { - buffer = new LayerBuffer::Buffer(buffers, offset, mBufferSize); - if (buffer->getStatus() != NO_ERROR) - buffer.clear(); - setBuffer(buffer); - mLayer.invalidate(); - } -} - -void LayerBuffer::BufferSource::unregisterBuffers() -{ - Mutex::Autolock _l(mBufferSourceLock); - mBufferHeap.heap.clear(); - mBuffer.clear(); - mLayer.invalidate(); -} - -sp<LayerBuffer::Buffer> LayerBuffer::BufferSource::getBuffer() const -{ - Mutex::Autolock _l(mBufferSourceLock); - return mBuffer; -} - -void LayerBuffer::BufferSource::setBuffer(const sp<LayerBuffer::Buffer>& buffer) -{ - Mutex::Autolock _l(mBufferSourceLock); - mBuffer = buffer; -} - -void LayerBuffer::BufferSource::onDraw(const Region& clip) const -{ - sp<Buffer> ourBuffer(getBuffer()); - if (UNLIKELY(ourBuffer == 0)) { - // nothing to do, we don't have a buffer - mLayer.clearWithOpenGL(clip); - return; - } - - status_t err = NO_ERROR; - NativeBuffer src(ourBuffer->getBuffer()); - const Rect transformedBounds(mLayer.getTransformedBounds()); - -#if defined(EGL_ANDROID_image_native_buffer) - if (GLExtensions::getInstance().haveDirectTexture()) { - err = INVALID_OPERATION; - if (ourBuffer->supportsCopybit()) { - copybit_device_t* copybit = mLayer.mBlitEngine; - if (copybit && err != NO_ERROR) { - // create our EGLImageKHR the first time - err = initTempBuffer(); - if (err == NO_ERROR) { - // NOTE: Assume the buffer is allocated with the proper USAGE flags - const NativeBuffer& dst(mTempBuffer); - region_iterator clip(Region(Rect(dst.crop.r, dst.crop.b))); - copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0); - copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF); - copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE); - err = copybit->stretch(copybit, &dst.img, &src.img, - &dst.crop, &src.crop, &clip); - if (err != NO_ERROR) { - clearTempBufferImage(); - } - } - } - } - } -#endif - else { - err = INVALID_OPERATION; - } - - if (err != NO_ERROR) { - // slower fallback - GGLSurface t; - t.version = sizeof(GGLSurface); - t.width = src.crop.r; - t.height = src.crop.b; - t.stride = src.img.w; - t.vstride= src.img.h; - t.format = src.img.format; - t.data = (GGLubyte*)src.img.base; - const Region dirty(Rect(t.width, t.height)); - mTextureManager.loadTexture(&mTexture, dirty, t); - } - - mTexture.transform = mBufferHeap.transform; - mLayer.drawWithOpenGL(clip, mTexture); -} - -status_t LayerBuffer::BufferSource::initTempBuffer() const -{ - // figure out the size we need now - const ISurface::BufferHeap& buffers(mBufferHeap); - uint32_t w = mLayer.mTransformedBounds.width(); - uint32_t h = mLayer.mTransformedBounds.height(); - if (buffers.w * h != buffers.h * w) { - int t = w; w = h; h = t; - } - - // we're in the copybit case, so make sure we can handle this blit - // we don't have to keep the aspect ratio here - copybit_device_t* copybit = mLayer.mBlitEngine; - const int down = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT); - const int up = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT); - if (buffers.w > w*down) w = buffers.w / down; - else if (w > buffers.w*up) w = buffers.w*up; - if (buffers.h > h*down) h = buffers.h / down; - else if (h > buffers.h*up) h = buffers.h*up; - - if (mTexture.image != EGL_NO_IMAGE_KHR) { - // we have an EGLImage, make sure the needed size didn't change - if (w!=mTexture.width || h!= mTexture.height) { - // delete the EGLImage and texture - clearTempBufferImage(); - } else { - // we're good, we have an EGLImageKHR and it's (still) the - // right size - return NO_ERROR; - } - } - - // figure out if we need linear filtering - if (buffers.w * h == buffers.h * w) { - // same pixel area, don't use filtering - mLayer.mNeedsFiltering = false; - } - - // Allocate a temporary buffer and create the corresponding EGLImageKHR - // once the EGLImage has been created we don't need the - // graphic buffer reference anymore. - sp<GraphicBuffer> buffer = new GraphicBuffer( - w, h, HAL_PIXEL_FORMAT_RGB_565, - GraphicBuffer::USAGE_HW_TEXTURE | - GraphicBuffer::USAGE_HW_2D); - - status_t err = buffer->initCheck(); - if (err == NO_ERROR) { - NativeBuffer& dst(mTempBuffer); - dst.img.w = buffer->getStride(); - dst.img.h = h; - dst.img.format = buffer->getPixelFormat(); - dst.img.handle = (native_handle_t *)buffer->handle; - dst.img.base = 0; - dst.crop.l = 0; - dst.crop.t = 0; - dst.crop.r = w; - dst.crop.b = h; - - EGLDisplay dpy(getFlinger()->graphicPlane(0).getEGLDisplay()); - err = mTextureManager.initEglImage(&mTexture, dpy, buffer); - } - - return err; -} - -void LayerBuffer::BufferSource::clearTempBufferImage() const -{ - // delete the image - EGLDisplay dpy(getFlinger()->graphicPlane(0).getEGLDisplay()); - eglDestroyImageKHR(dpy, mTexture.image); - - // and the associated texture (recreate a name) - glDeleteTextures(1, &mTexture.name); - Texture defaultTexture; - mTexture = defaultTexture; -} - -// --------------------------------------------------------------------------- - -LayerBuffer::OverlaySource::OverlaySource(LayerBuffer& layer, - sp<OverlayRef>* overlayRef, - uint32_t w, uint32_t h, int32_t format, int32_t orientation) - : Source(layer), mVisibilityChanged(false), - mOverlay(0), mOverlayHandle(0), mOverlayDevice(0), mOrientation(orientation) -{ - overlay_control_device_t* overlay_dev = getFlinger()->getOverlayEngine(); - if (overlay_dev == NULL) { - // overlays not supported - return; - } - - mOverlayDevice = overlay_dev; - overlay_t* overlay = overlay_dev->createOverlay(overlay_dev, w, h, format); - if (overlay == NULL) { - // couldn't create the overlay (no memory? no more overlays?) - return; - } - - // enable dithering... - overlay_dev->setParameter(overlay_dev, overlay, - OVERLAY_DITHER, OVERLAY_ENABLE); - - mOverlay = overlay; - mWidth = overlay->w; - mHeight = overlay->h; - mFormat = overlay->format; - mWidthStride = overlay->w_stride; - mHeightStride = overlay->h_stride; - mInitialized = false; - - mOverlayHandle = overlay->getHandleRef(overlay); - - sp<OverlayChannel> channel = new OverlayChannel( &layer ); - - *overlayRef = new OverlayRef(mOverlayHandle, channel, - mWidth, mHeight, mFormat, mWidthStride, mHeightStride); - getFlinger()->signalEvent(); -} - -LayerBuffer::OverlaySource::~OverlaySource() -{ - if (mOverlay && mOverlayDevice) { - overlay_control_device_t* overlay_dev = mOverlayDevice; - overlay_dev->destroyOverlay(overlay_dev, mOverlay); - } -} - -void LayerBuffer::OverlaySource::onDraw(const Region& clip) const -{ - // this would be where the color-key would be set, should we need it. - GLclampf red = 0; - GLclampf green = 0; - GLclampf blue = 0; - mLayer.clearWithOpenGL(clip, red, green, blue, 0); -} - -void LayerBuffer::OverlaySource::onTransaction(uint32_t flags) -{ - const Layer::State& front(mLayer.drawingState()); - const Layer::State& temp(mLayer.currentState()); - if (temp.sequence != front.sequence) { - mVisibilityChanged = true; - } -} - -void LayerBuffer::OverlaySource::onVisibilityResolved( - const Transform& planeTransform) -{ - // this code-path must be as tight as possible, it's called each time - // the screen is composited. - if (UNLIKELY(mOverlay != 0)) { - if (mVisibilityChanged || !mInitialized) { - mVisibilityChanged = false; - mInitialized = true; - const Rect bounds(mLayer.getTransformedBounds()); - int x = bounds.left; - int y = bounds.top; - int w = bounds.width(); - int h = bounds.height(); - - // we need a lock here to protect "destroy" - Mutex::Autolock _l(mOverlaySourceLock); - if (mOverlay) { - overlay_control_device_t* overlay_dev = mOverlayDevice; - overlay_dev->setPosition(overlay_dev, mOverlay, x,y,w,h); - // we need to combine the layer orientation and the - // user-requested orientation. - Transform finalTransform = Transform(mOrientation) * - Transform(mLayer.getOrientation()); - overlay_dev->setParameter(overlay_dev, mOverlay, - OVERLAY_TRANSFORM, finalTransform.getOrientation()); - overlay_dev->commit(overlay_dev, mOverlay); - } - } - } -} - -void LayerBuffer::OverlaySource::destroy() -{ - // we need a lock here to protect "onVisibilityResolved" - Mutex::Autolock _l(mOverlaySourceLock); - if (mOverlay && mOverlayDevice) { - overlay_control_device_t* overlay_dev = mOverlayDevice; - overlay_dev->destroyOverlay(overlay_dev, mOverlay); - mOverlay = 0; - } -} - -// --------------------------------------------------------------------------- -}; // namespace android diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h deleted file mode 100644 index 1c0bf83..0000000 --- a/libs/surfaceflinger/LayerBuffer.h +++ /dev/null @@ -1,220 +0,0 @@ -/* - * 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. - */ - -#ifndef ANDROID_LAYER_BUFFER_H -#define ANDROID_LAYER_BUFFER_H - -#include <stdint.h> -#include <sys/types.h> - -#include "LayerBase.h" -#include "TextureManager.h" - -struct copybit_device_t; - -namespace android { - -// --------------------------------------------------------------------------- - -class Buffer; -class Region; -class OverlayRef; - -// --------------------------------------------------------------------------- - -class LayerBuffer : public LayerBaseClient -{ - class Source : public LightRefBase<Source> { - public: - Source(LayerBuffer& layer); - virtual ~Source(); - virtual void onDraw(const Region& clip) const; - virtual void onTransaction(uint32_t flags); - virtual void onVisibilityResolved(const Transform& planeTransform); - virtual void postBuffer(ssize_t offset); - virtual void unregisterBuffers(); - virtual void destroy() { } - SurfaceFlinger* getFlinger() const { return mLayer.mFlinger.get(); } - protected: - LayerBuffer& mLayer; - }; - -public: - LayerBuffer(SurfaceFlinger* flinger, DisplayID display, - const sp<Client>& client); - virtual ~LayerBuffer(); - - virtual void onFirstRef(); - virtual bool needsBlending() const; - virtual const char* getTypeId() const { return "LayerBuffer"; } - - virtual sp<LayerBaseClient::Surface> createSurface() const; - virtual status_t ditch(); - virtual void onDraw(const Region& clip) const; - virtual uint32_t doTransaction(uint32_t flags); - virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion); - - status_t registerBuffers(const ISurface::BufferHeap& buffers); - void postBuffer(ssize_t offset); - void unregisterBuffers(); - sp<OverlayRef> createOverlay(uint32_t w, uint32_t h, int32_t format, - int32_t orientation); - - sp<Source> getSource() const; - sp<Source> clearSource(); - void setNeedsBlending(bool blending); - Rect getTransformedBounds() const { - return mTransformedBounds; - } - - void serverDestroy(); - -private: - struct NativeBuffer { - copybit_image_t img; - copybit_rect_t crop; - }; - - static gralloc_module_t const* sGrallocModule; - static gralloc_module_t const* getGrallocModule() { - return sGrallocModule; - } - - class Buffer : public LightRefBase<Buffer> { - public: - Buffer(const ISurface::BufferHeap& buffers, - ssize_t offset, size_t bufferSize); - inline bool supportsCopybit() const { - return mSupportsCopybit; - } - inline status_t getStatus() const { - return mBufferHeap.heap!=0 ? NO_ERROR : NO_INIT; - } - inline const NativeBuffer& getBuffer() const { - return mNativeBuffer; - } - protected: - friend class LightRefBase<Buffer>; - Buffer& operator = (const Buffer& rhs); - Buffer(const Buffer& rhs); - ~Buffer(); - private: - ISurface::BufferHeap mBufferHeap; - NativeBuffer mNativeBuffer; - bool mSupportsCopybit; - }; - - class BufferSource : public Source { - public: - BufferSource(LayerBuffer& layer, const ISurface::BufferHeap& buffers); - virtual ~BufferSource(); - - status_t getStatus() const { return mStatus; } - sp<Buffer> getBuffer() const; - void setBuffer(const sp<Buffer>& buffer); - - virtual void onDraw(const Region& clip) const; - virtual void postBuffer(ssize_t offset); - virtual void unregisterBuffers(); - virtual void destroy() { } - private: - status_t initTempBuffer() const; - void clearTempBufferImage() const; - mutable Mutex mBufferSourceLock; - sp<Buffer> mBuffer; - status_t mStatus; - ISurface::BufferHeap mBufferHeap; - size_t mBufferSize; - mutable Texture mTexture; - mutable NativeBuffer mTempBuffer; - mutable TextureManager mTextureManager; - }; - - class OverlaySource : public Source { - public: - OverlaySource(LayerBuffer& layer, - sp<OverlayRef>* overlayRef, - uint32_t w, uint32_t h, int32_t format, int32_t orientation); - virtual ~OverlaySource(); - virtual void onDraw(const Region& clip) const; - virtual void onTransaction(uint32_t flags); - virtual void onVisibilityResolved(const Transform& planeTransform); - virtual void destroy(); - private: - - class OverlayChannel : public BnOverlay { - wp<LayerBuffer> mLayer; - virtual void destroy() { - sp<LayerBuffer> layer(mLayer.promote()); - if (layer != 0) { - layer->serverDestroy(); - } - } - public: - OverlayChannel(const sp<LayerBuffer>& layer) - : mLayer(layer) { - } - }; - - friend class OverlayChannel; - bool mVisibilityChanged; - - overlay_t* mOverlay; - overlay_handle_t mOverlayHandle; - overlay_control_device_t* mOverlayDevice; - uint32_t mWidth; - uint32_t mHeight; - int32_t mFormat; - int32_t mWidthStride; - int32_t mHeightStride; - int32_t mOrientation; - mutable Mutex mOverlaySourceLock; - bool mInitialized; - }; - - - class SurfaceLayerBuffer : public LayerBaseClient::Surface - { - public: - SurfaceLayerBuffer(const sp<SurfaceFlinger>& flinger, - const sp<LayerBuffer>& owner); - virtual ~SurfaceLayerBuffer(); - - virtual status_t registerBuffers(const ISurface::BufferHeap& buffers); - virtual void postBuffer(ssize_t offset); - virtual void unregisterBuffers(); - - virtual sp<OverlayRef> createOverlay( - uint32_t w, uint32_t h, int32_t format, int32_t orientation); - private: - sp<LayerBuffer> getOwner() const { - return static_cast<LayerBuffer*>(Surface::getOwner().get()); - } - }; - - mutable Mutex mLock; - sp<Source> mSource; - sp<Surface> mSurface; - bool mInvalidate; - bool mNeedsBlending; - copybit_device_t* mBlitEngine; -}; - -// --------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_LAYER_BUFFER_H diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp deleted file mode 100644 index a1f339e..0000000 --- a/libs/surfaceflinger/LayerDim.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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 <stdlib.h> -#include <stdint.h> -#include <sys/types.h> - -#include <utils/Errors.h> -#include <utils/Log.h> - -#include <ui/GraphicBuffer.h> - -#include "LayerDim.h" -#include "SurfaceFlinger.h" -#include "DisplayHardware/DisplayHardware.h" - -namespace android { -// --------------------------------------------------------------------------- - -bool LayerDim::sUseTexture; -GLuint LayerDim::sTexId; -EGLImageKHR LayerDim::sImage; -int32_t LayerDim::sWidth; -int32_t LayerDim::sHeight; - -// --------------------------------------------------------------------------- - -LayerDim::LayerDim(SurfaceFlinger* flinger, DisplayID display, - const sp<Client>& client) - : LayerBaseClient(flinger, display, client) -{ -} - -void LayerDim::initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h) -{ - sTexId = -1; - sImage = EGL_NO_IMAGE_KHR; - sWidth = w; - sHeight = h; - sUseTexture = false; -} - -LayerDim::~LayerDim() -{ -} - -void LayerDim::onDraw(const Region& clip) const -{ - const State& s(drawingState()); - Region::const_iterator it = clip.begin(); - Region::const_iterator const end = clip.end(); - if (s.alpha>0 && (it != end)) { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const GLfloat alpha = s.alpha/255.0f; - const uint32_t fbHeight = hw.getHeight(); - glDisable(GL_DITHER); - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glColor4f(0, 0, 0, alpha); - -#if defined(GL_OES_texture_external) - if (GLExtensions::getInstance().haveTextureExternal()) { - glDisable(GL_TEXTURE_EXTERNAL_OES); - } -#endif - glDisable(GL_TEXTURE_2D); - - GLshort w = sWidth; - GLshort h = sHeight; - const GLshort vertices[4][2] = { - { 0, 0 }, - { 0, h }, - { w, h }, - { w, 0 } - }; - glVertexPointer(2, GL_SHORT, 0, vertices); - - while (it != end) { - const Rect& r = *it++; - const GLint sy = fbHeight - (r.top + r.height()); - glScissor(r.left, sy, r.width(), r.height()); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - } - } - glDisableClientState(GL_TEXTURE_COORD_ARRAY); -} - -// --------------------------------------------------------------------------- - -}; // namespace android diff --git a/libs/surfaceflinger/LayerDim.h b/libs/surfaceflinger/LayerDim.h deleted file mode 100644 index f032314..0000000 --- a/libs/surfaceflinger/LayerDim.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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. - */ - -#ifndef ANDROID_LAYER_DIM_H -#define ANDROID_LAYER_DIM_H - -#include <stdint.h> -#include <sys/types.h> - -#include <EGL/egl.h> -#include <EGL/eglext.h> - -#include "LayerBase.h" - -// --------------------------------------------------------------------------- - -namespace android { - -class LayerDim : public LayerBaseClient -{ - static bool sUseTexture; - static GLuint sTexId; - static EGLImageKHR sImage; - static int32_t sWidth; - static int32_t sHeight; -public: - LayerDim(SurfaceFlinger* flinger, DisplayID display, - const sp<Client>& client); - virtual ~LayerDim(); - - virtual void onDraw(const Region& clip) const; - virtual bool needsBlending() const { return true; } - virtual bool isSecure() const { return false; } - virtual const char* getTypeId() const { return "LayerDim"; } - - static void initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h); -}; - -// --------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_LAYER_DIM_H diff --git a/libs/surfaceflinger/MODULE_LICENSE_APACHE2 b/libs/surfaceflinger/MODULE_LICENSE_APACHE2 deleted file mode 100644 index e69de29..0000000 --- a/libs/surfaceflinger/MODULE_LICENSE_APACHE2 +++ /dev/null diff --git a/libs/surfaceflinger/MessageQueue.cpp b/libs/surfaceflinger/MessageQueue.cpp deleted file mode 100644 index d668e88..0000000 --- a/libs/surfaceflinger/MessageQueue.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (C) 2009 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 <errno.h> -#include <sys/types.h> - -#include <utils/threads.h> -#include <utils/Timers.h> -#include <utils/Log.h> -#include <binder/IPCThreadState.h> - -#include "MessageQueue.h" - -namespace android { - -// --------------------------------------------------------------------------- - -void MessageList::insert(const sp<MessageBase>& node) -{ - LIST::iterator cur(mList.begin()); - LIST::iterator end(mList.end()); - while (cur != end) { - if (*node < **cur) { - mList.insert(cur, node); - return; - } - ++cur; - } - mList.insert(++end, node); -} - -void MessageList::remove(MessageList::LIST::iterator pos) -{ - mList.erase(pos); -} - -// --------------------------------------------------------------------------- - -MessageQueue::MessageQueue() - : mInvalidate(false) -{ - mInvalidateMessage = new MessageBase(INVALIDATE); -} - -MessageQueue::~MessageQueue() -{ -} - -sp<MessageBase> MessageQueue::waitMessage(nsecs_t timeout) -{ - sp<MessageBase> result; - - bool again; - do { - const nsecs_t timeoutTime = systemTime() + timeout; - while (true) { - Mutex::Autolock _l(mLock); - nsecs_t now = systemTime(); - nsecs_t nextEventTime = -1; - - // invalidate messages are always handled first - if (mInvalidate) { - mInvalidate = false; - mInvalidateMessage->when = now; - result = mInvalidateMessage; - break; - } - - LIST::iterator cur(mMessages.begin()); - if (cur != mMessages.end()) { - result = *cur; - } - - if (result != 0) { - if (result->when <= now) { - // there is a message to deliver - mMessages.remove(cur); - break; - } - if (timeout>=0 && timeoutTime < now) { - // we timed-out, return a NULL message - result = 0; - break; - } - nextEventTime = result->when; - result = 0; - } - - if (timeout >= 0 && nextEventTime > 0) { - if (nextEventTime > timeoutTime) { - nextEventTime = timeoutTime; - } - } - - if (nextEventTime >= 0) { - //LOGD("nextEventTime = %lld ms", nextEventTime); - if (nextEventTime > 0) { - // we're about to wait, flush the binder command buffer - IPCThreadState::self()->flushCommands(); - const nsecs_t reltime = nextEventTime - systemTime(); - if (reltime > 0) { - mCondition.waitRelative(mLock, reltime); - } - } - } else { - //LOGD("going to wait"); - // we're about to wait, flush the binder command buffer - IPCThreadState::self()->flushCommands(); - mCondition.wait(mLock); - } - } - // here we're not holding the lock anymore - - if (result == 0) - break; - - again = result->handler(); - if (again) { - // the message has been processed. release our reference to it - // without holding the lock. - result->notify(); - result = 0; - } - - } while (again); - - return result; -} - -status_t MessageQueue::postMessage( - const sp<MessageBase>& message, nsecs_t relTime, uint32_t flags) -{ - return queueMessage(message, relTime, flags); -} - -status_t MessageQueue::invalidate() { - Mutex::Autolock _l(mLock); - mInvalidate = true; - mCondition.signal(); - return NO_ERROR; -} - -status_t MessageQueue::queueMessage( - const sp<MessageBase>& message, nsecs_t relTime, uint32_t flags) -{ - Mutex::Autolock _l(mLock); - message->when = systemTime() + relTime; - mMessages.insert(message); - - //LOGD("MessageQueue::queueMessage time = %lld ms", message->when); - //dumpLocked(message); - - mCondition.signal(); - return NO_ERROR; -} - -void MessageQueue::dump(const sp<MessageBase>& message) -{ - Mutex::Autolock _l(mLock); - dumpLocked(message); -} - -void MessageQueue::dumpLocked(const sp<MessageBase>& message) -{ - LIST::const_iterator cur(mMessages.begin()); - LIST::const_iterator end(mMessages.end()); - int c = 0; - while (cur != end) { - const char tick = (*cur == message) ? '>' : ' '; - LOGD("%c %d: msg{.what=%08x, when=%lld}", - tick, c, (*cur)->what, (*cur)->when); - ++cur; - c++; - } -} - -// --------------------------------------------------------------------------- - -}; // namespace android diff --git a/libs/surfaceflinger/MessageQueue.h b/libs/surfaceflinger/MessageQueue.h deleted file mode 100644 index 890f809..0000000 --- a/libs/surfaceflinger/MessageQueue.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2009 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. - */ - -#ifndef ANDROID_MESSAGE_QUEUE_H -#define ANDROID_MESSAGE_QUEUE_H - -#include <stdint.h> -#include <errno.h> -#include <sys/types.h> - -#include <utils/threads.h> -#include <utils/Timers.h> -#include <utils/List.h> - -#include "Barrier.h" - -namespace android { - -// --------------------------------------------------------------------------- - -class MessageBase; - -class MessageList -{ - List< sp<MessageBase> > mList; - typedef List< sp<MessageBase> > LIST; -public: - inline LIST::iterator begin() { return mList.begin(); } - inline LIST::const_iterator begin() const { return mList.begin(); } - inline LIST::iterator end() { return mList.end(); } - inline LIST::const_iterator end() const { return mList.end(); } - inline bool isEmpty() const { return mList.empty(); } - void insert(const sp<MessageBase>& node); - void remove(LIST::iterator pos); -}; - -// ============================================================================ - -class MessageBase : - public LightRefBase<MessageBase> -{ -public: - nsecs_t when; - uint32_t what; - int32_t arg0; - - MessageBase() : when(0), what(0), arg0(0) { } - MessageBase(uint32_t what, int32_t arg0=0) - : when(0), what(what), arg0(arg0) { } - - // return true if message has a handler - virtual bool handler() { return false; } - - // waits for the handler to be processed - void wait() const { barrier.wait(); } - - // releases all waiters. this is done automatically if - // handler returns true - void notify() const { barrier.open(); } - -protected: - virtual ~MessageBase() { } - -private: - mutable Barrier barrier; - friend class LightRefBase<MessageBase>; -}; - -inline bool operator < (const MessageBase& lhs, const MessageBase& rhs) { - return lhs.when < rhs.when; -} - -// --------------------------------------------------------------------------- - -class MessageQueue -{ - typedef List< sp<MessageBase> > LIST; -public: - - MessageQueue(); - ~MessageQueue(); - - // pre-defined messages - enum { - INVALIDATE = '_upd' - }; - - sp<MessageBase> waitMessage(nsecs_t timeout = -1); - - status_t postMessage(const sp<MessageBase>& message, - nsecs_t reltime=0, uint32_t flags = 0); - - status_t invalidate(); - - void dump(const sp<MessageBase>& message); - -private: - status_t queueMessage(const sp<MessageBase>& message, - nsecs_t reltime, uint32_t flags); - void dumpLocked(const sp<MessageBase>& message); - - Mutex mLock; - Condition mCondition; - MessageList mMessages; - bool mInvalidate; - sp<MessageBase> mInvalidateMessage; -}; - -// --------------------------------------------------------------------------- - -}; // namespace android - -#endif /* ANDROID_MESSAGE_QUEUE_H */ diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp deleted file mode 100644 index 68e8f19..0000000 --- a/libs/surfaceflinger/SurfaceFlinger.cpp +++ /dev/null @@ -1,1909 +0,0 @@ -/* - * 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 <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <math.h> -#include <limits.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/ioctl.h> - -#include <cutils/log.h> -#include <cutils/properties.h> - -#include <binder/IPCThreadState.h> -#include <binder/IServiceManager.h> -#include <binder/MemoryHeapBase.h> - -#include <utils/String8.h> -#include <utils/String16.h> -#include <utils/StopWatch.h> - -#include <ui/GraphicBufferAllocator.h> -#include <ui/PixelFormat.h> - -#include <pixelflinger/pixelflinger.h> -#include <GLES/gl.h> - -#include "clz.h" -#include "GLExtensions.h" -#include "Layer.h" -#include "LayerBlur.h" -#include "LayerBuffer.h" -#include "LayerDim.h" -#include "SurfaceFlinger.h" - -#include "DisplayHardware/DisplayHardware.h" - -/* ideally AID_GRAPHICS would be in a semi-public header - * or there would be a way to map a user/group name to its id - */ -#ifndef AID_GRAPHICS -#define AID_GRAPHICS 1003 -#endif - -#define DISPLAY_COUNT 1 - -namespace android { - -// --------------------------------------------------------------------------- - -void SurfaceFlinger::instantiate() { - defaultServiceManager()->addService( - String16("SurfaceFlinger"), new SurfaceFlinger()); -} - -void SurfaceFlinger::shutdown() { - // we should unregister here, but not really because - // when (if) the service manager goes away, all the services - // it has a reference to will leave too. -} - -// --------------------------------------------------------------------------- - -SurfaceFlinger::LayerVector::LayerVector(const SurfaceFlinger::LayerVector& rhs) - : lookup(rhs.lookup), layers(rhs.layers) -{ -} - -ssize_t SurfaceFlinger::LayerVector::indexOf( - const sp<LayerBase>& key, size_t guess) const -{ - if (guess<size() && lookup.keyAt(guess) == key) - return guess; - const ssize_t i = lookup.indexOfKey(key); - if (i>=0) { - const size_t idx = lookup.valueAt(i); - LOGE_IF(layers[idx]!=key, - "LayerVector[%p]: layers[%d]=%p, key=%p", - this, int(idx), layers[idx].get(), key.get()); - return idx; - } - return i; -} - -ssize_t SurfaceFlinger::LayerVector::add( - const sp<LayerBase>& layer, - Vector< sp<LayerBase> >::compar_t cmp) -{ - size_t count = layers.size(); - ssize_t l = 0; - ssize_t h = count-1; - ssize_t mid; - sp<LayerBase> const* a = layers.array(); - while (l <= h) { - mid = l + (h - l)/2; - const int c = cmp(a+mid, &layer); - if (c == 0) { l = mid; break; } - else if (c<0) { l = mid+1; } - else { h = mid-1; } - } - size_t order = l; - while (order<count && !cmp(&layer, a+order)) { - order++; - } - count = lookup.size(); - for (size_t i=0 ; i<count ; i++) { - if (lookup.valueAt(i) >= order) { - lookup.editValueAt(i)++; - } - } - layers.insertAt(layer, order); - lookup.add(layer, order); - return order; -} - -ssize_t SurfaceFlinger::LayerVector::remove(const sp<LayerBase>& layer) -{ - const ssize_t keyIndex = lookup.indexOfKey(layer); - if (keyIndex >= 0) { - const size_t index = lookup.valueAt(keyIndex); - LOGE_IF(layers[index]!=layer, - "LayerVector[%p]: layers[%u]=%p, layer=%p", - this, int(index), layers[index].get(), layer.get()); - layers.removeItemsAt(index); - lookup.removeItemsAt(keyIndex); - const size_t count = lookup.size(); - for (size_t i=0 ; i<count ; i++) { - if (lookup.valueAt(i) >= size_t(index)) { - lookup.editValueAt(i)--; - } - } - return index; - } - return NAME_NOT_FOUND; -} - -ssize_t SurfaceFlinger::LayerVector::reorder( - const sp<LayerBase>& layer, - Vector< sp<LayerBase> >::compar_t cmp) -{ - // XXX: it's a little lame. but oh well... - ssize_t err = remove(layer); - if (err >=0) - err = add(layer, cmp); - return err; -} - -// --------------------------------------------------------------------------- -#if 0 -#pragma mark - -#endif - -SurfaceFlinger::SurfaceFlinger() - : BnSurfaceComposer(), Thread(false), - mTransactionFlags(0), - mTransactionCount(0), - mResizeTransationPending(false), - mLayersRemoved(false), - mBootTime(systemTime()), - mHardwareTest("android.permission.HARDWARE_TEST"), - mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"), - mDump("android.permission.DUMP"), - mVisibleRegionsDirty(false), - mDeferReleaseConsole(false), - mFreezeDisplay(false), - mFreezeCount(0), - mFreezeDisplayTime(0), - mDebugRegion(0), - mDebugBackground(0), - mDebugInSwapBuffers(0), - mLastSwapBufferTime(0), - mDebugInTransaction(0), - mLastTransactionTime(0), - mBootFinished(false), - mConsoleSignals(0), - mSecureFrameBuffer(0) -{ - init(); -} - -void SurfaceFlinger::init() -{ - LOGI("SurfaceFlinger is starting"); - - // debugging stuff... - char value[PROPERTY_VALUE_MAX]; - property_get("debug.sf.showupdates", value, "0"); - mDebugRegion = atoi(value); - property_get("debug.sf.showbackground", value, "0"); - mDebugBackground = atoi(value); - - LOGI_IF(mDebugRegion, "showupdates enabled"); - LOGI_IF(mDebugBackground, "showbackground enabled"); -} - -SurfaceFlinger::~SurfaceFlinger() -{ - glDeleteTextures(1, &mWormholeTexName); -} - -overlay_control_device_t* SurfaceFlinger::getOverlayEngine() const -{ - return graphicPlane(0).displayHardware().getOverlayEngine(); -} - -sp<IMemoryHeap> SurfaceFlinger::getCblk() const -{ - return mServerHeap; -} - -sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() -{ - sp<ISurfaceComposerClient> bclient; - sp<Client> client(new Client(this)); - status_t err = client->initCheck(); - if (err == NO_ERROR) { - bclient = client; - } - return bclient; -} - -sp<ISurfaceComposerClient> SurfaceFlinger::createClientConnection() -{ - sp<ISurfaceComposerClient> bclient; - sp<UserClient> client(new UserClient(this)); - status_t err = client->initCheck(); - if (err == NO_ERROR) { - bclient = client; - } - return bclient; -} - - -const GraphicPlane& SurfaceFlinger::graphicPlane(int dpy) const -{ - LOGE_IF(uint32_t(dpy) >= DISPLAY_COUNT, "Invalid DisplayID %d", dpy); - const GraphicPlane& plane(mGraphicPlanes[dpy]); - return plane; -} - -GraphicPlane& SurfaceFlinger::graphicPlane(int dpy) -{ - return const_cast<GraphicPlane&>( - const_cast<SurfaceFlinger const *>(this)->graphicPlane(dpy)); -} - -void SurfaceFlinger::bootFinished() -{ - const nsecs_t now = systemTime(); - const nsecs_t duration = now - mBootTime; - LOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) ); - mBootFinished = true; - property_set("ctl.stop", "bootanim"); -} - -void SurfaceFlinger::onFirstRef() -{ - run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY); - - // Wait for the main thread to be done with its initialization - mReadyToRunBarrier.wait(); -} - -static inline uint16_t pack565(int r, int g, int b) { - return (r<<11)|(g<<5)|b; -} - -status_t SurfaceFlinger::readyToRun() -{ - LOGI( "SurfaceFlinger's main thread ready to run. " - "Initializing graphics H/W..."); - - // we only support one display currently - int dpy = 0; - - { - // initialize the main display - GraphicPlane& plane(graphicPlane(dpy)); - DisplayHardware* const hw = new DisplayHardware(this, dpy); - plane.setDisplayHardware(hw); - } - - // create the shared control-block - mServerHeap = new MemoryHeapBase(4096, - MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap"); - LOGE_IF(mServerHeap==0, "can't create shared memory dealer"); - - mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase()); - LOGE_IF(mServerCblk==0, "can't get to shared control block's address"); - - new(mServerCblk) surface_flinger_cblk_t; - - // initialize primary screen - // (other display should be initialized in the same manner, but - // asynchronously, as they could come and go. None of this is supported - // yet). - const GraphicPlane& plane(graphicPlane(dpy)); - const DisplayHardware& hw = plane.displayHardware(); - const uint32_t w = hw.getWidth(); - const uint32_t h = hw.getHeight(); - const uint32_t f = hw.getFormat(); - hw.makeCurrent(); - - // initialize the shared control block - mServerCblk->connected |= 1<<dpy; - display_cblk_t* dcblk = mServerCblk->displays + dpy; - memset(dcblk, 0, sizeof(display_cblk_t)); - dcblk->w = plane.getWidth(); - dcblk->h = plane.getHeight(); - dcblk->format = f; - dcblk->orientation = ISurfaceComposer::eOrientationDefault; - dcblk->xdpi = hw.getDpiX(); - dcblk->ydpi = hw.getDpiY(); - dcblk->fps = hw.getRefreshRate(); - dcblk->density = hw.getDensity(); - - // Initialize OpenGL|ES - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - glPixelStorei(GL_PACK_ALIGNMENT, 4); - glEnableClientState(GL_VERTEX_ARRAY); - glEnable(GL_SCISSOR_TEST); - glShadeModel(GL_FLAT); - glDisable(GL_DITHER); - glDisable(GL_CULL_FACE); - - const uint16_t g0 = pack565(0x0F,0x1F,0x0F); - const uint16_t g1 = pack565(0x17,0x2f,0x17); - const uint16_t textureData[4] = { g0, g1, g1, g0 }; - glGenTextures(1, &mWormholeTexName); - glBindTexture(GL_TEXTURE_2D, mWormholeTexName); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, - GL_RGB, GL_UNSIGNED_SHORT_5_6_5, textureData); - - glViewport(0, 0, w, h); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrthof(0, w, h, 0, 0, 1); - - LayerDim::initDimmer(this, w, h); - - mReadyToRunBarrier.open(); - - /* - * We're now ready to accept clients... - */ - - // start boot animation - property_set("ctl.start", "bootanim"); - - return NO_ERROR; -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark Events Handler -#endif - -void SurfaceFlinger::waitForEvent() -{ - while (true) { - nsecs_t timeout = -1; - const nsecs_t freezeDisplayTimeout = ms2ns(5000); - if (UNLIKELY(isFrozen())) { - // wait 5 seconds - const nsecs_t now = systemTime(); - if (mFreezeDisplayTime == 0) { - mFreezeDisplayTime = now; - } - nsecs_t waitTime = freezeDisplayTimeout - (now - mFreezeDisplayTime); - timeout = waitTime>0 ? waitTime : 0; - } - - sp<MessageBase> msg = mEventQueue.waitMessage(timeout); - - // see if we timed out - if (isFrozen()) { - const nsecs_t now = systemTime(); - nsecs_t frozenTime = (now - mFreezeDisplayTime); - if (frozenTime >= freezeDisplayTimeout) { - // we timed out and are still frozen - LOGW("timeout expired mFreezeDisplay=%d, mFreezeCount=%d", - mFreezeDisplay, mFreezeCount); - mFreezeDisplayTime = 0; - mFreezeCount = 0; - mFreezeDisplay = false; - } - } - - if (msg != 0) { - switch (msg->what) { - case MessageQueue::INVALIDATE: - // invalidate message, just return to the main loop - return; - } - } - } -} - -void SurfaceFlinger::signalEvent() { - mEventQueue.invalidate(); -} - -void SurfaceFlinger::signal() const { - // this is the IPC call - const_cast<SurfaceFlinger*>(this)->signalEvent(); -} - -status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg, - nsecs_t reltime, uint32_t flags) -{ - return mEventQueue.postMessage(msg, reltime, flags); -} - -status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg, - nsecs_t reltime, uint32_t flags) -{ - status_t res = mEventQueue.postMessage(msg, reltime, flags); - if (res == NO_ERROR) { - msg->wait(); - } - return res; -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark Main loop -#endif - -bool SurfaceFlinger::threadLoop() -{ - waitForEvent(); - - // check for transactions - if (UNLIKELY(mConsoleSignals)) { - handleConsoleEvents(); - } - - if (LIKELY(mTransactionCount == 0)) { - // if we're in a global transaction, don't do anything. - const uint32_t mask = eTransactionNeeded | eTraversalNeeded; - uint32_t transactionFlags = getTransactionFlags(mask); - if (LIKELY(transactionFlags)) { - handleTransaction(transactionFlags); - } - } - - // post surfaces (if needed) - handlePageFlip(); - - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - if (LIKELY(hw.canDraw() && !isFrozen())) { - // repaint the framebuffer (if needed) - handleRepaint(); - - // inform the h/w that we're done compositing - hw.compositionComplete(); - - // release the clients before we flip ('cause flip might block) - unlockClients(); - - postFramebuffer(); - } else { - // pretend we did the post - unlockClients(); - usleep(16667); // 60 fps period - } - return true; -} - -void SurfaceFlinger::postFramebuffer() -{ - if (!mInvalidRegion.isEmpty()) { - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const nsecs_t now = systemTime(); - mDebugInSwapBuffers = now; - hw.flip(mInvalidRegion); - mLastSwapBufferTime = systemTime() - now; - mDebugInSwapBuffers = 0; - mInvalidRegion.clear(); - } -} - -void SurfaceFlinger::handleConsoleEvents() -{ - // something to do with the console - const DisplayHardware& hw = graphicPlane(0).displayHardware(); - - int what = android_atomic_and(0, &mConsoleSignals); - if (what & eConsoleAcquired) { - hw.acquireScreen(); - } - - if (mDeferReleaseConsole && hw.canDraw()) { - // We got the release signal before the acquire signal - mDeferReleaseConsole = false; - hw.releaseScreen(); - } - - if (what & eConsoleReleased) { - if (hw.canDraw()) { - hw.releaseScreen(); - } else { - mDeferReleaseConsole = true; - } - } - - mDirtyRegion.set(hw.bounds()); -} - -void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) -{ - Vector< sp<LayerBase> > ditchedLayers; - - { // scope for the lock - Mutex::Autolock _l(mStateLock); - const nsecs_t now = systemTime(); - mDebugInTransaction = now; - handleTransactionLocked(transactionFlags, ditchedLayers); - mLastTransactionTime = systemTime() - now; - mDebugInTransaction = 0; - } - - // do this without lock held - const size_t count = ditchedLayers.size(); - for (size_t i=0 ; i<count ; i++) { - if (ditchedLayers[i] != 0) { - //LOGD("ditching layer %p", ditchedLayers[i].get()); - ditchedLayers[i]->ditch(); - } - } -} - -void SurfaceFlinger::handleTransactionLocked( - uint32_t transactionFlags, Vector< sp<LayerBase> >& ditchedLayers) -{ - const LayerVector& currentLayers(mCurrentState.layersSortedByZ); - const size_t count = currentLayers.size(); - - /* - * Traversal of the children - * (perform the transaction for each of them if needed) - */ - - const bool layersNeedTransaction = transactionFlags & eTraversalNeeded; - if (layersNeedTransaction) { - for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer = currentLayers[i]; - uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); - if (!trFlags) continue; - - const uint32_t flags = layer->doTransaction(0); - if (flags & Layer::eVisibleRegion) - mVisibleRegionsDirty = true; - } - } - - /* - * Perform our own transaction if needed - */ - - if (transactionFlags & eTransactionNeeded) { - if (mCurrentState.orientation != mDrawingState.orientation) { - // the orientation has changed, recompute all visible regions - // and invalidate everything. - - const int dpy = 0; - const int orientation = mCurrentState.orientation; - const uint32_t type = mCurrentState.orientationType; - GraphicPlane& plane(graphicPlane(dpy)); - plane.setOrientation(orientation); - - // update the shared control block - const DisplayHardware& hw(plane.displayHardware()); - volatile display_cblk_t* dcblk = mServerCblk->displays + dpy; - dcblk->orientation = orientation; - dcblk->w = plane.getWidth(); - dcblk->h = plane.getHeight(); - - mVisibleRegionsDirty = true; - mDirtyRegion.set(hw.bounds()); - } - - if (mCurrentState.freezeDisplay != mDrawingState.freezeDisplay) { - // freezing or unfreezing the display -> trigger animation if needed - mFreezeDisplay = mCurrentState.freezeDisplay; - if (mFreezeDisplay) - mFreezeDisplayTime = 0; - } - - if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) { - // layers have been added - mVisibleRegionsDirty = true; - } - - // some layers might have been removed, so - // we need to update the regions they're exposing. - if (mLayersRemoved) { - mLayersRemoved = false; - mVisibleRegionsDirty = true; - const LayerVector& previousLayers(mDrawingState.layersSortedByZ); - const size_t count = previousLayers.size(); - for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer(previousLayers[i]); - if (currentLayers.indexOf( layer ) < 0) { - // this layer is not visible anymore - ditchedLayers.add(layer); - mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen); - } - } - } - } - - commitTransaction(); -} - -sp<FreezeLock> SurfaceFlinger::getFreezeLock() const -{ - return new FreezeLock(const_cast<SurfaceFlinger *>(this)); -} - -void SurfaceFlinger::computeVisibleRegions( - LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion) -{ - const GraphicPlane& plane(graphicPlane(0)); - const Transform& planeTransform(plane.transform()); - const DisplayHardware& hw(plane.displayHardware()); - const Region screenRegion(hw.bounds()); - - Region aboveOpaqueLayers; - Region aboveCoveredLayers; - Region dirty; - - bool secureFrameBuffer = false; - - size_t i = currentLayers.size(); - while (i--) { - const sp<LayerBase>& layer = currentLayers[i]; - layer->validateVisibility(planeTransform); - - // start with the whole surface at its current location - const Layer::State& s(layer->drawingState()); - - /* - * opaqueRegion: area of a surface that is fully opaque. - */ - Region opaqueRegion; - - /* - * visibleRegion: area of a surface that is visible on screen - * and not fully transparent. This is essentially the layer's - * footprint minus the opaque regions above it. - * Areas covered by a translucent surface are considered visible. - */ - Region visibleRegion; - - /* - * coveredRegion: area of a surface that is covered by all - * visible regions above it (which includes the translucent areas). - */ - Region coveredRegion; - - - // handle hidden surfaces by setting the visible region to empty - if (LIKELY(!(s.flags & ISurfaceComposer::eLayerHidden) && s.alpha)) { - const bool translucent = layer->needsBlending(); - const Rect bounds(layer->visibleBounds()); - visibleRegion.set(bounds); - visibleRegion.andSelf(screenRegion); - if (!visibleRegion.isEmpty()) { - // Remove the transparent area from the visible region - if (translucent) { - visibleRegion.subtractSelf(layer->transparentRegionScreen); - } - - // compute the opaque region - const int32_t layerOrientation = layer->getOrientation(); - if (s.alpha==255 && !translucent && - ((layerOrientation & Transform::ROT_INVALID) == false)) { - // the opaque region is the layer's footprint - opaqueRegion = visibleRegion; - } - } - } - - // Clip the covered region to the visible region - coveredRegion = aboveCoveredLayers.intersect(visibleRegion); - - // Update aboveCoveredLayers for next (lower) layer - aboveCoveredLayers.orSelf(visibleRegion); - - // subtract the opaque region covered by the layers above us - visibleRegion.subtractSelf(aboveOpaqueLayers); - - // compute this layer's dirty region - if (layer->contentDirty) { - // we need to invalidate the whole region - dirty = visibleRegion; - // as well, as the old visible region - dirty.orSelf(layer->visibleRegionScreen); - layer->contentDirty = false; - } else { - /* compute the exposed region: - * the exposed region consists of two components: - * 1) what's VISIBLE now and was COVERED before - * 2) what's EXPOSED now less what was EXPOSED before - * - * note that (1) is conservative, we start with the whole - * visible region but only keep what used to be covered by - * something -- which mean it may have been exposed. - * - * (2) handles areas that were not covered by anything but got - * exposed because of a resize. - */ - const Region newExposed = visibleRegion - coveredRegion; - const Region oldVisibleRegion = layer->visibleRegionScreen; - const Region oldCoveredRegion = layer->coveredRegionScreen; - const Region oldExposed = oldVisibleRegion - oldCoveredRegion; - dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed); - } - dirty.subtractSelf(aboveOpaqueLayers); - - // accumulate to the screen dirty region - dirtyRegion.orSelf(dirty); - - // Update aboveOpaqueLayers for next (lower) layer - aboveOpaqueLayers.orSelf(opaqueRegion); - - // Store the visible region is screen space - layer->setVisibleRegion(visibleRegion); - layer->setCoveredRegion(coveredRegion); - - // If a secure layer is partially visible, lock-down the screen! - if (layer->isSecure() && !visibleRegion.isEmpty()) { - secureFrameBuffer = true; - } - } - - // invalidate the areas where a layer was removed - dirtyRegion.orSelf(mDirtyRegionRemovedLayer); - mDirtyRegionRemovedLayer.clear(); - - mSecureFrameBuffer = secureFrameBuffer; - opaqueRegion = aboveOpaqueLayers; -} - - -void SurfaceFlinger::commitTransaction() -{ - mDrawingState = mCurrentState; - mResizeTransationPending = false; - mTransactionCV.broadcast(); -} - -void SurfaceFlinger::handlePageFlip() -{ - bool visibleRegions = mVisibleRegionsDirty; - LayerVector& currentLayers = const_cast<LayerVector&>( - mDrawingState.layersSortedByZ); - visibleRegions |= lockPageFlip(currentLayers); - - const DisplayHardware& hw = graphicPlane(0).displayHardware(); - const Region screenRegion(hw.bounds()); - if (visibleRegions) { - Region opaqueRegion; - computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion); - mWormholeRegion = screenRegion.subtract(opaqueRegion); - mVisibleRegionsDirty = false; - } - - unlockPageFlip(currentLayers); - mDirtyRegion.andSelf(screenRegion); -} - -bool SurfaceFlinger::lockPageFlip(const LayerVector& currentLayers) -{ - bool recomputeVisibleRegions = false; - size_t count = currentLayers.size(); - sp<LayerBase> const* layers = currentLayers.array(); - for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer(layers[i]); - layer->lockPageFlip(recomputeVisibleRegions); - } - return recomputeVisibleRegions; -} - -void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers) -{ - const GraphicPlane& plane(graphicPlane(0)); - const Transform& planeTransform(plane.transform()); - size_t count = currentLayers.size(); - sp<LayerBase> const* layers = currentLayers.array(); - for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer(layers[i]); - layer->unlockPageFlip(planeTransform, mDirtyRegion); - } -} - - -void SurfaceFlinger::handleRepaint() -{ - // compute the invalid region - mInvalidRegion.orSelf(mDirtyRegion); - if (mInvalidRegion.isEmpty()) { - // nothing to do - return; - } - - if (UNLIKELY(mDebugRegion)) { - debugFlashRegions(); - } - - // set the frame buffer - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - uint32_t flags = hw.getFlags(); - if ((flags & DisplayHardware::SWAP_RECTANGLE) || - (flags & DisplayHardware::BUFFER_PRESERVED)) - { - // we can redraw only what's dirty, but since SWAP_RECTANGLE only - // takes a rectangle, we must make sure to update that whole - // rectangle in that case - if (flags & DisplayHardware::SWAP_RECTANGLE) { - // TODO: we really should be able to pass a region to - // SWAP_RECTANGLE so that we don't have to redraw all this. - mDirtyRegion.set(mInvalidRegion.bounds()); - } else { - // in the BUFFER_PRESERVED case, obviously, we can update only - // what's needed and nothing more. - // NOTE: this is NOT a common case, as preserving the backbuffer - // is costly and usually involves copying the whole update back. - } - } else { - if (flags & DisplayHardware::PARTIAL_UPDATES) { - // We need to redraw the rectangle that will be updated - // (pushed to the framebuffer). - // This is needed because PARTIAL_UPDATES only takes one - // rectangle instead of a region (see DisplayHardware::flip()) - mDirtyRegion.set(mInvalidRegion.bounds()); - } else { - // we need to redraw everything (the whole screen) - mDirtyRegion.set(hw.bounds()); - mInvalidRegion = mDirtyRegion; - } - } - - // compose all surfaces - composeSurfaces(mDirtyRegion); - - // clear the dirty regions - mDirtyRegion.clear(); -} - -void SurfaceFlinger::composeSurfaces(const Region& dirty) -{ - if (UNLIKELY(!mWormholeRegion.isEmpty())) { - // should never happen unless the window manager has a bug - // draw something... - drawWormhole(); - } - const SurfaceFlinger& flinger(*this); - const LayerVector& drawingLayers(mDrawingState.layersSortedByZ); - const size_t count = drawingLayers.size(); - sp<LayerBase> const* const layers = drawingLayers.array(); - for (size_t i=0 ; i<count ; ++i) { - const sp<LayerBase>& layer = layers[i]; - const Region& visibleRegion(layer->visibleRegionScreen); - if (!visibleRegion.isEmpty()) { - const Region clip(dirty.intersect(visibleRegion)); - if (!clip.isEmpty()) { - layer->draw(clip); - } - } - } -} - -void SurfaceFlinger::unlockClients() -{ - const LayerVector& drawingLayers(mDrawingState.layersSortedByZ); - const size_t count = drawingLayers.size(); - sp<LayerBase> const* const layers = drawingLayers.array(); - for (size_t i=0 ; i<count ; ++i) { - const sp<LayerBase>& layer = layers[i]; - layer->finishPageFlip(); - } -} - -void SurfaceFlinger::debugFlashRegions() -{ - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const uint32_t flags = hw.getFlags(); - - if (!((flags & DisplayHardware::SWAP_RECTANGLE) || - (flags & DisplayHardware::BUFFER_PRESERVED))) { - const Region repaint((flags & DisplayHardware::PARTIAL_UPDATES) ? - mDirtyRegion.bounds() : hw.bounds()); - composeSurfaces(repaint); - } - - TextureManager::deactivateTextures(); - - glDisable(GL_BLEND); - glDisable(GL_DITHER); - glDisable(GL_SCISSOR_TEST); - - static int toggle = 0; - toggle = 1 - toggle; - if (toggle) { - glColor4f(1, 0, 1, 1); - } else { - glColor4f(1, 1, 0, 1); - } - - Region::const_iterator it = mDirtyRegion.begin(); - Region::const_iterator const end = mDirtyRegion.end(); - while (it != end) { - const Rect& r = *it++; - GLfloat vertices[][2] = { - { r.left, r.top }, - { r.left, r.bottom }, - { r.right, r.bottom }, - { r.right, r.top } - }; - glVertexPointer(2, GL_FLOAT, 0, vertices); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - } - - if (mInvalidRegion.isEmpty()) { - mDirtyRegion.dump("mDirtyRegion"); - mInvalidRegion.dump("mInvalidRegion"); - } - hw.flip(mInvalidRegion); - - if (mDebugRegion > 1) - usleep(mDebugRegion * 1000); - - glEnable(GL_SCISSOR_TEST); - //mDirtyRegion.dump("mDirtyRegion"); -} - -void SurfaceFlinger::drawWormhole() const -{ - const Region region(mWormholeRegion.intersect(mDirtyRegion)); - if (region.isEmpty()) - return; - - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - const int32_t width = hw.getWidth(); - const int32_t height = hw.getHeight(); - - glDisable(GL_BLEND); - glDisable(GL_DITHER); - - if (LIKELY(!mDebugBackground)) { - glClearColor(0,0,0,0); - Region::const_iterator it = region.begin(); - Region::const_iterator const end = region.end(); - while (it != end) { - const Rect& r = *it++; - const GLint sy = height - (r.top + r.height()); - glScissor(r.left, sy, r.width(), r.height()); - glClear(GL_COLOR_BUFFER_BIT); - } - } else { - const GLshort vertices[][2] = { { 0, 0 }, { width, 0 }, - { width, height }, { 0, height } }; - const GLshort tcoords[][2] = { { 0, 0 }, { 1, 0 }, { 1, 1 }, { 0, 1 } }; - glVertexPointer(2, GL_SHORT, 0, vertices); - glTexCoordPointer(2, GL_SHORT, 0, tcoords); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); -#if defined(GL_OES_texture_external) - if (GLExtensions::getInstance().haveTextureExternal()) { - glDisable(GL_TEXTURE_EXTERNAL_OES); - } -#endif - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, mWormholeTexName); - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glScalef(width*(1.0f/32.0f), height*(1.0f/32.0f), 1); - Region::const_iterator it = region.begin(); - Region::const_iterator const end = region.end(); - while (it != end) { - const Rect& r = *it++; - const GLint sy = height - (r.top + r.height()); - glScissor(r.left, sy, r.width(), r.height()); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - } - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - } -} - -void SurfaceFlinger::debugShowFPS() const -{ - static int mFrameCount; - static int mLastFrameCount = 0; - static nsecs_t mLastFpsTime = 0; - static float mFps = 0; - mFrameCount++; - nsecs_t now = systemTime(); - nsecs_t diff = now - mLastFpsTime; - if (diff > ms2ns(250)) { - mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; - mLastFpsTime = now; - mLastFrameCount = mFrameCount; - } - // XXX: mFPS has the value we want - } - -status_t SurfaceFlinger::addLayer(const sp<LayerBase>& layer) -{ - Mutex::Autolock _l(mStateLock); - addLayer_l(layer); - setTransactionFlags(eTransactionNeeded|eTraversalNeeded); - return NO_ERROR; -} - -status_t SurfaceFlinger::addLayer_l(const sp<LayerBase>& layer) -{ - ssize_t i = mCurrentState.layersSortedByZ.add( - layer, &LayerBase::compareCurrentStateZ); - return (i < 0) ? status_t(i) : status_t(NO_ERROR); -} - -ssize_t SurfaceFlinger::addClientLayer(const sp<Client>& client, - const sp<LayerBaseClient>& lbc) -{ - Mutex::Autolock _l(mStateLock); - - // attach this layer to the client - ssize_t name = client->attachLayer(lbc); - - // add this layer to the current state list - addLayer_l(lbc); - - return name; -} - -status_t SurfaceFlinger::removeLayer(const sp<LayerBase>& layer) -{ - Mutex::Autolock _l(mStateLock); - status_t err = purgatorizeLayer_l(layer); - if (err == NO_ERROR) - setTransactionFlags(eTransactionNeeded); - return err; -} - -status_t SurfaceFlinger::removeLayer_l(const sp<LayerBase>& layerBase) -{ - sp<LayerBaseClient> lbc(layerBase->getLayerBaseClient()); - if (lbc != 0) { - mLayerMap.removeItem( lbc->getSurface()->asBinder() ); - } - ssize_t index = mCurrentState.layersSortedByZ.remove(layerBase); - if (index >= 0) { - mLayersRemoved = true; - return NO_ERROR; - } - return status_t(index); -} - -status_t SurfaceFlinger::purgatorizeLayer_l(const sp<LayerBase>& layerBase) -{ - // remove the layer from the main list (through a transaction). - ssize_t err = removeLayer_l(layerBase); - - layerBase->onRemoved(); - - // it's possible that we don't find a layer, because it might - // have been destroyed already -- this is not technically an error - // from the user because there is a race between Client::destroySurface(), - // ~Client() and ~ISurface(). - return (err == NAME_NOT_FOUND) ? status_t(NO_ERROR) : err; -} - -status_t SurfaceFlinger::invalidateLayerVisibility(const sp<LayerBase>& layer) -{ - layer->forceVisibilityTransaction(); - setTransactionFlags(eTraversalNeeded); - return NO_ERROR; -} - -uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) -{ - return android_atomic_and(~flags, &mTransactionFlags) & flags; -} - -uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) -{ - uint32_t old = android_atomic_or(flags, &mTransactionFlags); - if ((old & flags)==0) { // wake the server up - signalEvent(); - } - return old; -} - -void SurfaceFlinger::openGlobalTransaction() -{ - android_atomic_inc(&mTransactionCount); -} - -void SurfaceFlinger::closeGlobalTransaction() -{ - if (android_atomic_dec(&mTransactionCount) == 1) { - signalEvent(); - - // if there is a transaction with a resize, wait for it to - // take effect before returning. - Mutex::Autolock _l(mStateLock); - while (mResizeTransationPending) { - status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); - if (CC_UNLIKELY(err != NO_ERROR)) { - // just in case something goes wrong in SF, return to the - // called after a few seconds. - LOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!"); - mResizeTransationPending = false; - break; - } - } - } -} - -status_t SurfaceFlinger::freezeDisplay(DisplayID dpy, uint32_t flags) -{ - if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT)) - return BAD_VALUE; - - Mutex::Autolock _l(mStateLock); - mCurrentState.freezeDisplay = 1; - setTransactionFlags(eTransactionNeeded); - - // flags is intended to communicate some sort of animation behavior - // (for instance fading) - return NO_ERROR; -} - -status_t SurfaceFlinger::unfreezeDisplay(DisplayID dpy, uint32_t flags) -{ - if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT)) - return BAD_VALUE; - - Mutex::Autolock _l(mStateLock); - mCurrentState.freezeDisplay = 0; - setTransactionFlags(eTransactionNeeded); - - // flags is intended to communicate some sort of animation behavior - // (for instance fading) - return NO_ERROR; -} - -int SurfaceFlinger::setOrientation(DisplayID dpy, - int orientation, uint32_t flags) -{ - if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT)) - return BAD_VALUE; - - Mutex::Autolock _l(mStateLock); - if (mCurrentState.orientation != orientation) { - if (uint32_t(orientation)<=eOrientation270 || orientation==42) { - mCurrentState.orientationType = flags; - mCurrentState.orientation = orientation; - setTransactionFlags(eTransactionNeeded); - mTransactionCV.wait(mStateLock); - } else { - orientation = BAD_VALUE; - } - } - return orientation; -} - -sp<ISurface> SurfaceFlinger::createSurface(const sp<Client>& client, int pid, - const String8& name, ISurfaceComposerClient::surface_data_t* params, - DisplayID d, uint32_t w, uint32_t h, PixelFormat format, - uint32_t flags) -{ - sp<LayerBaseClient> layer; - sp<LayerBaseClient::Surface> surfaceHandle; - - if (int32_t(w|h) < 0) { - LOGE("createSurface() failed, w or h is negative (w=%d, h=%d)", - int(w), int(h)); - return surfaceHandle; - } - - //LOGD("createSurface for pid %d (%d x %d)", pid, w, h); - sp<Layer> normalLayer; - switch (flags & eFXSurfaceMask) { - case eFXSurfaceNormal: - if (UNLIKELY(flags & ePushBuffers)) { - layer = createPushBuffersSurface(client, d, w, h, flags); - } else { - normalLayer = createNormalSurface(client, d, w, h, flags, format); - layer = normalLayer; - } - break; - case eFXSurfaceBlur: - layer = createBlurSurface(client, d, w, h, flags); - break; - case eFXSurfaceDim: - layer = createDimSurface(client, d, w, h, flags); - break; - } - - if (layer != 0) { - layer->initStates(w, h, flags); - layer->setName(name); - ssize_t token = addClientLayer(client, layer); - - surfaceHandle = layer->getSurface(); - if (surfaceHandle != 0) { - params->token = token; - params->identity = surfaceHandle->getIdentity(); - params->width = w; - params->height = h; - params->format = format; - if (normalLayer != 0) { - Mutex::Autolock _l(mStateLock); - mLayerMap.add(surfaceHandle->asBinder(), normalLayer); - } - } - - setTransactionFlags(eTransactionNeeded); - } - - return surfaceHandle; -} - -sp<Layer> SurfaceFlinger::createNormalSurface( - const sp<Client>& client, DisplayID display, - uint32_t w, uint32_t h, uint32_t flags, - PixelFormat& format) -{ - // initialize the surfaces - switch (format) { // TODO: take h/w into account - case PIXEL_FORMAT_TRANSPARENT: - case PIXEL_FORMAT_TRANSLUCENT: - format = PIXEL_FORMAT_RGBA_8888; - break; - case PIXEL_FORMAT_OPAQUE: -#ifdef NO_RGBX_8888 - format = PIXEL_FORMAT_RGB_565; -#else - format = PIXEL_FORMAT_RGBX_8888; -#endif - break; - } - -#ifdef NO_RGBX_8888 - if (format == PIXEL_FORMAT_RGBX_8888) - format = PIXEL_FORMAT_RGBA_8888; -#endif - - sp<Layer> layer = new Layer(this, display, client); - status_t err = layer->setBuffers(w, h, format, flags); - if (LIKELY(err != NO_ERROR)) { - LOGE("createNormalSurfaceLocked() failed (%s)", strerror(-err)); - layer.clear(); - } - return layer; -} - -sp<LayerBlur> SurfaceFlinger::createBlurSurface( - const sp<Client>& client, DisplayID display, - uint32_t w, uint32_t h, uint32_t flags) -{ - sp<LayerBlur> layer = new LayerBlur(this, display, client); - layer->initStates(w, h, flags); - return layer; -} - -sp<LayerDim> SurfaceFlinger::createDimSurface( - const sp<Client>& client, DisplayID display, - uint32_t w, uint32_t h, uint32_t flags) -{ - sp<LayerDim> layer = new LayerDim(this, display, client); - layer->initStates(w, h, flags); - return layer; -} - -sp<LayerBuffer> SurfaceFlinger::createPushBuffersSurface( - const sp<Client>& client, DisplayID display, - uint32_t w, uint32_t h, uint32_t flags) -{ - sp<LayerBuffer> layer = new LayerBuffer(this, display, client); - layer->initStates(w, h, flags); - return layer; -} - -status_t SurfaceFlinger::removeSurface(const sp<Client>& client, SurfaceID sid) -{ - /* - * called by the window manager, when a surface should be marked for - * destruction. - * - * The surface is removed from the current and drawing lists, but placed - * in the purgatory queue, so it's not destroyed right-away (we need - * to wait for all client's references to go away first). - */ - - status_t err = NAME_NOT_FOUND; - Mutex::Autolock _l(mStateLock); - sp<LayerBaseClient> layer = client->getLayerUser(sid); - if (layer != 0) { - err = purgatorizeLayer_l(layer); - if (err == NO_ERROR) { - setTransactionFlags(eTransactionNeeded); - } - } - return err; -} - -status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer) -{ - // called by ~ISurface() when all references are gone - - class MessageDestroySurface : public MessageBase { - SurfaceFlinger* flinger; - sp<LayerBaseClient> layer; - public: - MessageDestroySurface( - SurfaceFlinger* flinger, const sp<LayerBaseClient>& layer) - : flinger(flinger), layer(layer) { } - virtual bool handler() { - sp<LayerBaseClient> l(layer); - layer.clear(); // clear it outside of the lock; - Mutex::Autolock _l(flinger->mStateLock); - /* - * remove the layer from the current list -- chances are that it's - * not in the list anyway, because it should have been removed - * already upon request of the client (eg: window manager). - * However, a buggy client could have not done that. - * Since we know we don't have any more clients, we don't need - * to use the purgatory. - */ - status_t err = flinger->removeLayer_l(l); - LOGE_IF(err<0 && err != NAME_NOT_FOUND, - "error removing layer=%p (%s)", l.get(), strerror(-err)); - return true; - } - }; - - postMessageAsync( new MessageDestroySurface(this, layer) ); - return NO_ERROR; -} - -status_t SurfaceFlinger::setClientState( - const sp<Client>& client, - int32_t count, - const layer_state_t* states) -{ - Mutex::Autolock _l(mStateLock); - uint32_t flags = 0; - for (int i=0 ; i<count ; i++) { - const layer_state_t& s(states[i]); - sp<LayerBaseClient> layer(client->getLayerUser(s.surface)); - if (layer != 0) { - const uint32_t what = s.what; - if (what & ePositionChanged) { - if (layer->setPosition(s.x, s.y)) - flags |= eTraversalNeeded; - } - if (what & eLayerChanged) { - if (layer->setLayer(s.z)) { - mCurrentState.layersSortedByZ.reorder( - layer, &Layer::compareCurrentStateZ); - // we need traversal (state changed) - // AND transaction (list changed) - flags |= eTransactionNeeded|eTraversalNeeded; - } - } - if (what & eSizeChanged) { - if (layer->setSize(s.w, s.h)) { - flags |= eTraversalNeeded; - mResizeTransationPending = true; - } - } - if (what & eAlphaChanged) { - if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f))) - flags |= eTraversalNeeded; - } - if (what & eMatrixChanged) { - if (layer->setMatrix(s.matrix)) - flags |= eTraversalNeeded; - } - if (what & eTransparentRegionChanged) { - if (layer->setTransparentRegionHint(s.transparentRegion)) - flags |= eTraversalNeeded; - } - if (what & eVisibilityChanged) { - if (layer->setFlags(s.flags, s.mask)) - flags |= eTraversalNeeded; - } - } - } - if (flags) { - setTransactionFlags(flags); - } - return NO_ERROR; -} - -void SurfaceFlinger::screenReleased(int dpy) -{ - // this may be called by a signal handler, we can't do too much in here - android_atomic_or(eConsoleReleased, &mConsoleSignals); - signalEvent(); -} - -void SurfaceFlinger::screenAcquired(int dpy) -{ - // this may be called by a signal handler, we can't do too much in here - android_atomic_or(eConsoleAcquired, &mConsoleSignals); - signalEvent(); -} - -status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 1024; - char buffer[SIZE]; - String8 result; - if (!mDump.checkCalling()) { - snprintf(buffer, SIZE, "Permission Denial: " - "can't dump SurfaceFlinger from pid=%d, uid=%d\n", - IPCThreadState::self()->getCallingPid(), - IPCThreadState::self()->getCallingUid()); - result.append(buffer); - } else { - - // figure out if we're stuck somewhere - const nsecs_t now = systemTime(); - const nsecs_t inSwapBuffers(mDebugInSwapBuffers); - const nsecs_t inTransaction(mDebugInTransaction); - nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0; - nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0; - - // Try to get the main lock, but don't insist if we can't - // (this would indicate SF is stuck, but we want to be able to - // print something in dumpsys). - int retry = 3; - while (mStateLock.tryLock()<0 && --retry>=0) { - usleep(1000000); - } - const bool locked(retry >= 0); - if (!locked) { - snprintf(buffer, SIZE, - "SurfaceFlinger appears to be unresponsive, " - "dumping anyways (no locks held)\n"); - result.append(buffer); - } - - const LayerVector& currentLayers = mCurrentState.layersSortedByZ; - const size_t count = currentLayers.size(); - for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer(currentLayers[i]); - layer->dump(result, buffer, SIZE); - const Layer::State& s(layer->drawingState()); - s.transparentRegion.dump(result, "transparentRegion"); - layer->transparentRegionScreen.dump(result, "transparentRegionScreen"); - layer->visibleRegionScreen.dump(result, "visibleRegionScreen"); - } - - mWormholeRegion.dump(result, "WormholeRegion"); - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - snprintf(buffer, SIZE, - " display frozen: %s, freezeCount=%d, orientation=%d, canDraw=%d\n", - mFreezeDisplay?"yes":"no", mFreezeCount, - mCurrentState.orientation, hw.canDraw()); - result.append(buffer); - snprintf(buffer, SIZE, - " last eglSwapBuffers() time: %f us\n" - " last transaction time : %f us\n", - mLastSwapBufferTime/1000.0, mLastTransactionTime/1000.0); - result.append(buffer); - - if (inSwapBuffersDuration || !locked) { - snprintf(buffer, SIZE, " eglSwapBuffers time: %f us\n", - inSwapBuffersDuration/1000.0); - result.append(buffer); - } - - if (inTransactionDuration || !locked) { - snprintf(buffer, SIZE, " transaction time: %f us\n", - inTransactionDuration/1000.0); - result.append(buffer); - } - - const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); - alloc.dump(result); - - if (locked) { - mStateLock.unlock(); - } - } - write(fd, result.string(), result.size()); - return NO_ERROR; -} - -status_t SurfaceFlinger::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - switch (code) { - case CREATE_CONNECTION: - case OPEN_GLOBAL_TRANSACTION: - case CLOSE_GLOBAL_TRANSACTION: - case SET_ORIENTATION: - case FREEZE_DISPLAY: - case UNFREEZE_DISPLAY: - case BOOT_FINISHED: - { - // codes that require permission check - IPCThreadState* ipc = IPCThreadState::self(); - const int pid = ipc->getCallingPid(); - const int uid = ipc->getCallingUid(); - if ((uid != AID_GRAPHICS) && !mAccessSurfaceFlinger.check(pid, uid)) { - LOGE("Permission Denial: " - "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); - return PERMISSION_DENIED; - } - } - } - status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags); - if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - if (UNLIKELY(!mHardwareTest.checkCalling())) { - IPCThreadState* ipc = IPCThreadState::self(); - const int pid = ipc->getCallingPid(); - const int uid = ipc->getCallingUid(); - LOGE("Permission Denial: " - "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); - return PERMISSION_DENIED; - } - int n; - switch (code) { - case 1000: // SHOW_CPU, NOT SUPPORTED ANYMORE - return NO_ERROR; - case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE - return NO_ERROR; - case 1002: // SHOW_UPDATES - n = data.readInt32(); - mDebugRegion = n ? n : (mDebugRegion ? 0 : 1); - return NO_ERROR; - case 1003: // SHOW_BACKGROUND - n = data.readInt32(); - mDebugBackground = n ? 1 : 0; - return NO_ERROR; - case 1004:{ // repaint everything - Mutex::Autolock _l(mStateLock); - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - mDirtyRegion.set(hw.bounds()); // careful that's not thread-safe - signalEvent(); - return NO_ERROR; - } - case 1005:{ // force transaction - setTransactionFlags(eTransactionNeeded|eTraversalNeeded); - return NO_ERROR; - } - case 1007: // set mFreezeCount - mFreezeCount = data.readInt32(); - mFreezeDisplayTime = 0; - return NO_ERROR; - case 1010: // interrogate. - reply->writeInt32(0); - reply->writeInt32(0); - reply->writeInt32(mDebugRegion); - reply->writeInt32(mDebugBackground); - return NO_ERROR; - case 1013: { - Mutex::Autolock _l(mStateLock); - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - reply->writeInt32(hw.getPageFlipCount()); - } - return NO_ERROR; - } - } - return err; -} - -// --------------------------------------------------------------------------- - -sp<Layer> SurfaceFlinger::getLayer(const sp<ISurface>& sur) const -{ - sp<Layer> result; - Mutex::Autolock _l(mStateLock); - result = mLayerMap.valueFor( sur->asBinder() ).promote(); - return result; -} - -// --------------------------------------------------------------------------- - -Client::Client(const sp<SurfaceFlinger>& flinger) - : mFlinger(flinger), mNameGenerator(1) -{ -} - -Client::~Client() -{ - const size_t count = mLayers.size(); - for (size_t i=0 ; i<count ; i++) { - sp<LayerBaseClient> layer(mLayers.valueAt(i).promote()); - if (layer != 0) { - mFlinger->removeLayer(layer); - } - } -} - -status_t Client::initCheck() const { - return NO_ERROR; -} - -ssize_t Client::attachLayer(const sp<LayerBaseClient>& layer) -{ - int32_t name = android_atomic_inc(&mNameGenerator); - mLayers.add(name, layer); - return name; -} - -void Client::detachLayer(const LayerBaseClient* layer) -{ - // we do a linear search here, because this doesn't happen often - const size_t count = mLayers.size(); - for (size_t i=0 ; i<count ; i++) { - if (mLayers.valueAt(i) == layer) { - mLayers.removeItemsAt(i, 1); - break; - } - } -} -sp<LayerBaseClient> Client::getLayerUser(int32_t i) const { - sp<LayerBaseClient> lbc; - const wp<LayerBaseClient>& layer(mLayers.valueFor(i)); - if (layer != 0) { - lbc = layer.promote(); - LOGE_IF(lbc==0, "getLayerUser(name=%d) is dead", int(i)); - } - return lbc; -} - -sp<IMemoryHeap> Client::getControlBlock() const { - return 0; -} -ssize_t Client::getTokenForSurface(const sp<ISurface>& sur) const { - return -1; -} -sp<ISurface> Client::createSurface( - ISurfaceComposerClient::surface_data_t* params, int pid, - const String8& name, - DisplayID display, uint32_t w, uint32_t h, PixelFormat format, - uint32_t flags) -{ - return mFlinger->createSurface(this, pid, name, params, - display, w, h, format, flags); -} -status_t Client::destroySurface(SurfaceID sid) { - return mFlinger->removeSurface(this, sid); -} -status_t Client::setState(int32_t count, const layer_state_t* states) { - return mFlinger->setClientState(this, count, states); -} - -// --------------------------------------------------------------------------- - -UserClient::UserClient(const sp<SurfaceFlinger>& flinger) - : ctrlblk(0), mBitmap(0), mFlinger(flinger) -{ - const int pgsize = getpagesize(); - const int cblksize = ((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1)); - - mCblkHeap = new MemoryHeapBase(cblksize, 0, - "SurfaceFlinger Client control-block"); - - ctrlblk = static_cast<SharedClient *>(mCblkHeap->getBase()); - if (ctrlblk) { // construct the shared structure in-place. - new(ctrlblk) SharedClient; - } -} - -UserClient::~UserClient() -{ - if (ctrlblk) { - ctrlblk->~SharedClient(); // destroy our shared-structure. - } - - /* - * When a UserClient dies, it's unclear what to do exactly. - * We could go ahead and destroy all surfaces linked to that client - * however, it wouldn't be fair to the main Client - * (usually the the window-manager), which might want to re-target - * the layer to another UserClient. - * I think the best is to do nothing, or not much; in most cases the - * WM itself will go ahead and clean things up when it detects a client of - * his has died. - * The remaining question is what to display? currently we keep - * just keep the current buffer. - */ -} - -status_t UserClient::initCheck() const { - return ctrlblk == 0 ? NO_INIT : NO_ERROR; -} - -void UserClient::detachLayer(const Layer* layer) -{ - int32_t name = layer->getToken(); - if (name >= 0) { - int32_t mask = 1LU<<name; - if ((android_atomic_and(~mask, &mBitmap) & mask) == 0) { - LOGW("token %d wasn't marked as used %08x", name, int(mBitmap)); - } - } -} - -sp<IMemoryHeap> UserClient::getControlBlock() const { - return mCblkHeap; -} - -ssize_t UserClient::getTokenForSurface(const sp<ISurface>& sur) const -{ - int32_t name = NAME_NOT_FOUND; - sp<Layer> layer(mFlinger->getLayer(sur)); - if (layer == 0) return name; - - // if this layer already has a token, just return it - name = layer->getToken(); - if ((name >= 0) && (layer->getClient() == this)) - return name; - - name = 0; - do { - int32_t mask = 1LU<<name; - if ((android_atomic_or(mask, &mBitmap) & mask) == 0) { - // we found and locked that name - status_t err = layer->setToken( - const_cast<UserClient*>(this), ctrlblk, name); - if (err != NO_ERROR) { - // free the name - android_atomic_and(~mask, &mBitmap); - name = err; - } - break; - } - if (++name > 31) - name = NO_MEMORY; - } while(name >= 0); - - //LOGD("getTokenForSurface(%p) => %d (client=%p, bitmap=%08lx)", - // sur->asBinder().get(), name, this, mBitmap); - return name; -} - -sp<ISurface> UserClient::createSurface( - ISurfaceComposerClient::surface_data_t* params, int pid, - const String8& name, - DisplayID display, uint32_t w, uint32_t h, PixelFormat format, - uint32_t flags) { - return 0; -} -status_t UserClient::destroySurface(SurfaceID sid) { - return INVALID_OPERATION; -} -status_t UserClient::setState(int32_t count, const layer_state_t* states) { - return INVALID_OPERATION; -} - -// --------------------------------------------------------------------------- - -GraphicPlane::GraphicPlane() - : mHw(0) -{ -} - -GraphicPlane::~GraphicPlane() { - delete mHw; -} - -bool GraphicPlane::initialized() const { - return mHw ? true : false; -} - -int GraphicPlane::getWidth() const { - return mWidth; -} - -int GraphicPlane::getHeight() const { - return mHeight; -} - -void GraphicPlane::setDisplayHardware(DisplayHardware *hw) -{ - mHw = hw; - - // initialize the display orientation transform. - // it's a constant that should come from the display driver. - int displayOrientation = ISurfaceComposer::eOrientationDefault; - char property[PROPERTY_VALUE_MAX]; - if (property_get("ro.sf.hwrotation", property, NULL) > 0) { - //displayOrientation - switch (atoi(property)) { - case 90: - displayOrientation = ISurfaceComposer::eOrientation90; - break; - case 270: - displayOrientation = ISurfaceComposer::eOrientation270; - break; - } - } - - const float w = hw->getWidth(); - const float h = hw->getHeight(); - GraphicPlane::orientationToTransfrom(displayOrientation, w, h, - &mDisplayTransform); - if (displayOrientation & ISurfaceComposer::eOrientationSwapMask) { - mDisplayWidth = h; - mDisplayHeight = w; - } else { - mDisplayWidth = w; - mDisplayHeight = h; - } - - setOrientation(ISurfaceComposer::eOrientationDefault); -} - -status_t GraphicPlane::orientationToTransfrom( - int orientation, int w, int h, Transform* tr) -{ - uint32_t flags = 0; - switch (orientation) { - case ISurfaceComposer::eOrientationDefault: - flags = Transform::ROT_0; - break; - case ISurfaceComposer::eOrientation90: - flags = Transform::ROT_90; - break; - case ISurfaceComposer::eOrientation180: - flags = Transform::ROT_180; - break; - case ISurfaceComposer::eOrientation270: - flags = Transform::ROT_270; - break; - default: - return BAD_VALUE; - } - tr->set(flags, w, h); - return NO_ERROR; -} - -status_t GraphicPlane::setOrientation(int orientation) -{ - // If the rotation can be handled in hardware, this is where - // the magic should happen. - - const DisplayHardware& hw(displayHardware()); - const float w = mDisplayWidth; - const float h = mDisplayHeight; - mWidth = int(w); - mHeight = int(h); - - Transform orientationTransform; - GraphicPlane::orientationToTransfrom(orientation, w, h, - &orientationTransform); - if (orientation & ISurfaceComposer::eOrientationSwapMask) { - mWidth = int(h); - mHeight = int(w); - } - - mOrientation = orientation; - mGlobalTransform = mDisplayTransform * orientationTransform; - return NO_ERROR; -} - -const DisplayHardware& GraphicPlane::displayHardware() const { - return *mHw; -} - -const Transform& GraphicPlane::transform() const { - return mGlobalTransform; -} - -EGLDisplay GraphicPlane::getEGLDisplay() const { - return mHw->getEGLDisplay(); -} - -// --------------------------------------------------------------------------- - -}; // namespace android diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h deleted file mode 100644 index 0bfc170..0000000 --- a/libs/surfaceflinger/SurfaceFlinger.h +++ /dev/null @@ -1,420 +0,0 @@ -/* - * 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. - */ - -#ifndef ANDROID_SURFACE_FLINGER_H -#define ANDROID_SURFACE_FLINGER_H - -#include <stdint.h> -#include <sys/types.h> - -#include <utils/SortedVector.h> -#include <utils/KeyedVector.h> -#include <utils/threads.h> -#include <utils/Atomic.h> -#include <utils/Errors.h> -#include <utils/RefBase.h> - -#include <binder/IMemory.h> -#include <binder/Permission.h> - -#include <ui/PixelFormat.h> -#include <surfaceflinger/ISurfaceComposer.h> -#include <surfaceflinger/ISurfaceComposerClient.h> - -#include "Barrier.h" -#include "Layer.h" - -#include "MessageQueue.h" - -struct copybit_device_t; -struct overlay_device_t; - -namespace android { - -// --------------------------------------------------------------------------- - -class Client; -class DisplayHardware; -class FreezeLock; -class Layer; -class LayerBlur; -class LayerDim; -class LayerBuffer; - -#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) -#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) - -// --------------------------------------------------------------------------- - -class Client : public BnSurfaceComposerClient -{ -public: - Client(const sp<SurfaceFlinger>& flinger); - ~Client(); - - status_t initCheck() const; - - // protected by SurfaceFlinger::mStateLock - ssize_t attachLayer(const sp<LayerBaseClient>& layer); - void detachLayer(const LayerBaseClient* layer); - sp<LayerBaseClient> getLayerUser(int32_t i) const; - -private: - - // ISurfaceComposerClient interface - virtual sp<IMemoryHeap> getControlBlock() const; - virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const; - virtual sp<ISurface> createSurface( - surface_data_t* params, int pid, const String8& name, - DisplayID display, uint32_t w, uint32_t h,PixelFormat format, - uint32_t flags); - virtual status_t destroySurface(SurfaceID surfaceId); - virtual status_t setState(int32_t count, const layer_state_t* states); - - DefaultKeyedVector< size_t, wp<LayerBaseClient> > mLayers; - sp<SurfaceFlinger> mFlinger; - int32_t mNameGenerator; -}; - -class UserClient : public BnSurfaceComposerClient -{ -public: - // pointer to this client's control block - SharedClient* ctrlblk; - -public: - UserClient(const sp<SurfaceFlinger>& flinger); - ~UserClient(); - - status_t initCheck() const; - - // protected by SurfaceFlinger::mStateLock - void detachLayer(const Layer* layer); - -private: - - // ISurfaceComposerClient interface - virtual sp<IMemoryHeap> getControlBlock() const; - virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const; - virtual sp<ISurface> createSurface( - surface_data_t* params, int pid, const String8& name, - DisplayID display, uint32_t w, uint32_t h,PixelFormat format, - uint32_t flags); - virtual status_t destroySurface(SurfaceID surfaceId); - virtual status_t setState(int32_t count, const layer_state_t* states); - - // atomic-ops - mutable volatile int32_t mBitmap; - - sp<IMemoryHeap> mCblkHeap; - sp<SurfaceFlinger> mFlinger; -}; - -// --------------------------------------------------------------------------- - -class GraphicPlane -{ -public: - static status_t orientationToTransfrom(int orientation, int w, int h, - Transform* tr); - - GraphicPlane(); - ~GraphicPlane(); - - bool initialized() const; - - void setDisplayHardware(DisplayHardware *); - status_t setOrientation(int orientation); - int getOrientation() const { return mOrientation; } - int getWidth() const; - int getHeight() const; - - const DisplayHardware& displayHardware() const; - const Transform& transform() const; - EGLDisplay getEGLDisplay() const; - -private: - GraphicPlane(const GraphicPlane&); - GraphicPlane operator = (const GraphicPlane&); - - DisplayHardware* mHw; - Transform mGlobalTransform; - Transform mDisplayTransform; - int mOrientation; - float mDisplayWidth; - float mDisplayHeight; - int mWidth; - int mHeight; -}; - -// --------------------------------------------------------------------------- - -enum { - eTransactionNeeded = 0x01, - eTraversalNeeded = 0x02 -}; - -class SurfaceFlinger : public BnSurfaceComposer, protected Thread -{ -public: - static void instantiate(); - static void shutdown(); - - SurfaceFlinger(); - virtual ~SurfaceFlinger(); - void init(); - - virtual status_t onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); - - virtual status_t dump(int fd, const Vector<String16>& args); - - // ISurfaceComposer interface - virtual sp<ISurfaceComposerClient> createConnection(); - virtual sp<ISurfaceComposerClient> createClientConnection(); - virtual sp<IMemoryHeap> getCblk() const; - virtual void bootFinished(); - virtual void openGlobalTransaction(); - virtual void closeGlobalTransaction(); - virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags); - virtual status_t unfreezeDisplay(DisplayID dpy, uint32_t flags); - virtual int setOrientation(DisplayID dpy, int orientation, uint32_t flags); - virtual void signal() const; - - void screenReleased(DisplayID dpy); - void screenAcquired(DisplayID dpy); - - overlay_control_device_t* getOverlayEngine() const; - - status_t removeLayer(const sp<LayerBase>& layer); - status_t addLayer(const sp<LayerBase>& layer); - status_t invalidateLayerVisibility(const sp<LayerBase>& layer); - - sp<Layer> getLayer(const sp<ISurface>& sur) const; - -private: - friend class Client; - friend class LayerBase; - friend class LayerBuffer; - friend class LayerBaseClient; - friend class LayerBaseClient::Surface; - friend class Layer; - friend class LayerBlur; - friend class LayerDim; - - sp<ISurface> createSurface(const sp<Client>& client, - int pid, const String8& name, - ISurfaceComposerClient::surface_data_t* params, - DisplayID display, uint32_t w, uint32_t h, PixelFormat format, - uint32_t flags); - - sp<Layer> createNormalSurface( - const sp<Client>& client, DisplayID display, - uint32_t w, uint32_t h, uint32_t flags, - PixelFormat& format); - - sp<LayerBlur> createBlurSurface( - const sp<Client>& client, DisplayID display, - uint32_t w, uint32_t h, uint32_t flags); - - sp<LayerDim> createDimSurface( - const sp<Client>& client, DisplayID display, - uint32_t w, uint32_t h, uint32_t flags); - - sp<LayerBuffer> createPushBuffersSurface( - const sp<Client>& client, DisplayID display, - uint32_t w, uint32_t h, uint32_t flags); - - status_t removeSurface(const sp<Client>& client, SurfaceID sid); - status_t destroySurface(const sp<LayerBaseClient>& layer); - status_t setClientState(const sp<Client>& client, - int32_t count, const layer_state_t* states); - - - class LayerVector { - public: - inline LayerVector() { } - LayerVector(const LayerVector&); - inline size_t size() const { return layers.size(); } - inline sp<LayerBase> const* array() const { return layers.array(); } - ssize_t add(const sp<LayerBase>&, Vector< sp<LayerBase> >::compar_t); - ssize_t remove(const sp<LayerBase>&); - ssize_t reorder(const sp<LayerBase>&, Vector< sp<LayerBase> >::compar_t); - ssize_t indexOf(const sp<LayerBase>& key, size_t guess=0) const; - inline sp<LayerBase> operator [] (size_t i) const { return layers[i]; } - private: - KeyedVector< sp<LayerBase> , size_t> lookup; - Vector< sp<LayerBase> > layers; - }; - - struct State { - State() { - orientation = ISurfaceComposer::eOrientationDefault; - freezeDisplay = 0; - } - LayerVector layersSortedByZ; - uint8_t orientation; - uint8_t orientationType; - uint8_t freezeDisplay; - }; - - virtual bool threadLoop(); - virtual status_t readyToRun(); - virtual void onFirstRef(); - -public: // hack to work around gcc 4.0.3 bug - const GraphicPlane& graphicPlane(int dpy) const; - GraphicPlane& graphicPlane(int dpy); -private: - - void waitForEvent(); -public: // hack to work around gcc 4.0.3 bug - void signalEvent(); -private: - void handleConsoleEvents(); - void handleTransaction(uint32_t transactionFlags); - void handleTransactionLocked( - uint32_t transactionFlags, - Vector< sp<LayerBase> >& ditchedLayers); - - void computeVisibleRegions( - LayerVector& currentLayers, - Region& dirtyRegion, - Region& wormholeRegion); - - void handlePageFlip(); - bool lockPageFlip(const LayerVector& currentLayers); - void unlockPageFlip(const LayerVector& currentLayers); - void handleRepaint(); - void postFramebuffer(); - void composeSurfaces(const Region& dirty); - void unlockClients(); - - - ssize_t addClientLayer(const sp<Client>& client, - const sp<LayerBaseClient>& lbc); - status_t addLayer_l(const sp<LayerBase>& layer); - status_t removeLayer_l(const sp<LayerBase>& layer); - status_t purgatorizeLayer_l(const sp<LayerBase>& layer); - - uint32_t getTransactionFlags(uint32_t flags); - uint32_t setTransactionFlags(uint32_t flags); - void commitTransaction(); - - - friend class FreezeLock; - sp<FreezeLock> getFreezeLock() const; - inline void incFreezeCount() { - if (mFreezeCount == 0) - mFreezeDisplayTime = 0; - mFreezeCount++; - } - inline void decFreezeCount() { if (mFreezeCount > 0) mFreezeCount--; } - inline bool hasFreezeRequest() const { return mFreezeDisplay; } - inline bool isFrozen() const { - return (mFreezeDisplay || mFreezeCount>0) && mBootFinished; - } - - - void debugFlashRegions(); - void debugShowFPS() const; - void drawWormhole() const; - - - mutable MessageQueue mEventQueue; - - status_t postMessageAsync(const sp<MessageBase>& msg, - nsecs_t reltime=0, uint32_t flags = 0); - - status_t postMessageSync(const sp<MessageBase>& msg, - nsecs_t reltime=0, uint32_t flags = 0); - - // access must be protected by mStateLock - mutable Mutex mStateLock; - State mCurrentState; - State mDrawingState; - volatile int32_t mTransactionFlags; - volatile int32_t mTransactionCount; - Condition mTransactionCV; - bool mResizeTransationPending; - - // protected by mStateLock (but we could use another lock) - GraphicPlane mGraphicPlanes[1]; - bool mLayersRemoved; - DefaultKeyedVector< wp<IBinder>, wp<Layer> > mLayerMap; - - // constant members (no synchronization needed for access) - sp<IMemoryHeap> mServerHeap; - surface_flinger_cblk_t* mServerCblk; - GLuint mWormholeTexName; - nsecs_t mBootTime; - Permission mHardwareTest; - Permission mAccessSurfaceFlinger; - Permission mDump; - - // Can only accessed from the main thread, these members - // don't need synchronization - Region mDirtyRegion; - Region mDirtyRegionRemovedLayer; - Region mInvalidRegion; - Region mWormholeRegion; - bool mVisibleRegionsDirty; - bool mDeferReleaseConsole; - bool mFreezeDisplay; - int32_t mFreezeCount; - nsecs_t mFreezeDisplayTime; - - // don't use a lock for these, we don't care - int mDebugRegion; - int mDebugBackground; - volatile nsecs_t mDebugInSwapBuffers; - nsecs_t mLastSwapBufferTime; - volatile nsecs_t mDebugInTransaction; - nsecs_t mLastTransactionTime; - bool mBootFinished; - - // these are thread safe - mutable Barrier mReadyToRunBarrier; - - // atomic variables - enum { - eConsoleReleased = 1, - eConsoleAcquired = 2 - }; - volatile int32_t mConsoleSignals; - - // only written in the main thread, only read in other threads - volatile int32_t mSecureFrameBuffer; -}; - -// --------------------------------------------------------------------------- - -class FreezeLock : public LightRefBase<FreezeLock> { - SurfaceFlinger* mFlinger; -public: - FreezeLock(SurfaceFlinger* flinger) - : mFlinger(flinger) { - mFlinger->incFreezeCount(); - } - ~FreezeLock() { - mFlinger->decFreezeCount(); - } -}; - -// --------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_SURFACE_FLINGER_H diff --git a/libs/surfaceflinger/TextureManager.cpp b/libs/surfaceflinger/TextureManager.cpp deleted file mode 100644 index 3b326df..0000000 --- a/libs/surfaceflinger/TextureManager.cpp +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright (C) 2010 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 <stdlib.h> -#include <stdint.h> -#include <sys/types.h> - -#include <utils/Errors.h> -#include <utils/Log.h> - -#include <ui/GraphicBuffer.h> - -#include <GLES/gl.h> -#include <GLES/glext.h> - -#include <hardware/hardware.h> - -#include "clz.h" -#include "DisplayHardware/DisplayHardware.h" -#include "GLExtensions.h" -#include "TextureManager.h" - -namespace android { - -// --------------------------------------------------------------------------- - -TextureManager::TextureManager() - : mGLExtensions(GLExtensions::getInstance()) -{ -} - -GLenum TextureManager::getTextureTarget(const Image* image) { -#if defined(GL_OES_texture_external) - switch (image->target) { - case Texture::TEXTURE_EXTERNAL: - return GL_TEXTURE_EXTERNAL_OES; - } -#endif - return GL_TEXTURE_2D; -} - -status_t TextureManager::initTexture(Texture* texture) -{ - if (texture->name != -1UL) - return INVALID_OPERATION; - - GLuint textureName = -1; - glGenTextures(1, &textureName); - texture->name = textureName; - texture->width = 0; - texture->height = 0; - - const GLenum target = GL_TEXTURE_2D; - glBindTexture(target, textureName); - glTexParameterx(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterx(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - return NO_ERROR; -} - -status_t TextureManager::initTexture(Image* pImage, int32_t format) -{ - if (pImage->name != -1UL) - return INVALID_OPERATION; - - GLuint textureName = -1; - glGenTextures(1, &textureName); - pImage->name = textureName; - pImage->width = 0; - pImage->height = 0; - - GLenum target = GL_TEXTURE_2D; -#if defined(GL_OES_texture_external) - if (GLExtensions::getInstance().haveTextureExternal()) { - if (format && isYuvFormat(format)) { - target = GL_TEXTURE_EXTERNAL_OES; - pImage->target = Texture::TEXTURE_EXTERNAL; - } - } -#endif - - glBindTexture(target, textureName); - glTexParameterx(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterx(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - return NO_ERROR; -} - -bool TextureManager::isSupportedYuvFormat(int format) -{ - switch (format) { - case HAL_PIXEL_FORMAT_YV12: - return true; - } - return false; -} - -bool TextureManager::isYuvFormat(int format) -{ - switch (format) { - // supported YUV formats - case HAL_PIXEL_FORMAT_YV12: - // Legacy/deprecated YUV formats - case HAL_PIXEL_FORMAT_YCbCr_422_SP: - case HAL_PIXEL_FORMAT_YCrCb_420_SP: - case HAL_PIXEL_FORMAT_YCbCr_422_I: - case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: - return true; - } - - // Any OEM format needs to be considered - if (format>=0x100 && format<=0x1FF) - return true; - - return false; -} - -status_t TextureManager::initEglImage(Image* pImage, - EGLDisplay dpy, const sp<GraphicBuffer>& buffer) -{ - status_t err = NO_ERROR; - if (!pImage->dirty) return err; - - // free the previous image - if (pImage->image != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(dpy, pImage->image); - pImage->image = EGL_NO_IMAGE_KHR; - } - - // construct an EGL_NATIVE_BUFFER_ANDROID - android_native_buffer_t* clientBuf = buffer->getNativeBuffer(); - - // create the new EGLImageKHR - const EGLint attrs[] = { - EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, - EGL_NONE, EGL_NONE - }; - pImage->image = eglCreateImageKHR( - dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, - (EGLClientBuffer)clientBuf, attrs); - - if (pImage->image != EGL_NO_IMAGE_KHR) { - if (pImage->name == -1UL) { - initTexture(pImage, buffer->format); - } - const GLenum target = getTextureTarget(pImage); - glBindTexture(target, pImage->name); - glEGLImageTargetTexture2DOES(target, (GLeglImageOES)pImage->image); - GLint error = glGetError(); - if (error != GL_NO_ERROR) { - LOGE("glEGLImageTargetTexture2DOES(%p) failed err=0x%04x", - pImage->image, error); - err = INVALID_OPERATION; - } else { - // Everything went okay! - pImage->dirty = false; - pImage->width = clientBuf->width; - pImage->height = clientBuf->height; - } - } else { - LOGE("eglCreateImageKHR() failed. err=0x%4x", eglGetError()); - err = INVALID_OPERATION; - } - return err; -} - -status_t TextureManager::loadTexture(Texture* texture, - const Region& dirty, const GGLSurface& t) -{ - if (texture->name == -1UL) { - status_t err = initTexture(texture); - LOGE_IF(err, "loadTexture failed in initTexture (%s)", strerror(err)); - return err; - } - - if (texture->target != GL_TEXTURE_2D) - return INVALID_OPERATION; - - glBindTexture(GL_TEXTURE_2D, texture->name); - - /* - * In OpenGL ES we can't specify a stride with glTexImage2D (however, - * GL_UNPACK_ALIGNMENT is a limited form of stride). - * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we - * need to do something reasonable (here creating a bigger texture). - * - * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT); - * - * This situation doesn't happen often, but some h/w have a limitation - * for their framebuffer (eg: must be multiple of 8 pixels), and - * we need to take that into account when using these buffers as - * textures. - * - * This should never be a problem with POT textures - */ - - int unpack = __builtin_ctz(t.stride * bytesPerPixel(t.format)); - unpack = 1 << ((unpack > 3) ? 3 : unpack); - glPixelStorei(GL_UNPACK_ALIGNMENT, unpack); - - /* - * round to POT if needed - */ - if (!mGLExtensions.haveNpot()) { - texture->NPOTAdjust = true; - } - - if (texture->NPOTAdjust) { - // find the smallest power-of-two that will accommodate our surface - texture->potWidth = 1 << (31 - clz(t.width)); - texture->potHeight = 1 << (31 - clz(t.height)); - if (texture->potWidth < t.width) texture->potWidth <<= 1; - if (texture->potHeight < t.height) texture->potHeight <<= 1; - texture->wScale = float(t.width) / texture->potWidth; - texture->hScale = float(t.height) / texture->potHeight; - } else { - texture->potWidth = t.width; - texture->potHeight = t.height; - } - - Rect bounds(dirty.bounds()); - GLvoid* data = 0; - if (texture->width != t.width || texture->height != t.height) { - texture->width = t.width; - texture->height = t.height; - - // texture size changed, we need to create a new one - bounds.set(Rect(t.width, t.height)); - if (t.width == texture->potWidth && - t.height == texture->potHeight) { - // we can do it one pass - data = t.data; - } - - if (t.format == HAL_PIXEL_FORMAT_RGB_565) { - glTexImage2D(GL_TEXTURE_2D, 0, - GL_RGB, texture->potWidth, texture->potHeight, 0, - GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data); - } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) { - glTexImage2D(GL_TEXTURE_2D, 0, - GL_RGBA, texture->potWidth, texture->potHeight, 0, - GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data); - } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 || - t.format == HAL_PIXEL_FORMAT_RGBX_8888) { - glTexImage2D(GL_TEXTURE_2D, 0, - GL_RGBA, texture->potWidth, texture->potHeight, 0, - GL_RGBA, GL_UNSIGNED_BYTE, data); - } else if (isSupportedYuvFormat(t.format)) { - // just show the Y plane of YUV buffers - glTexImage2D(GL_TEXTURE_2D, 0, - GL_LUMINANCE, texture->potWidth, texture->potHeight, 0, - GL_LUMINANCE, GL_UNSIGNED_BYTE, data); - } else { - // oops, we don't handle this format! - LOGE("texture=%d, using format %d, which is not " - "supported by the GL", texture->name, t.format); - } - } - if (!data) { - if (t.format == HAL_PIXEL_FORMAT_RGB_565) { - glTexSubImage2D(GL_TEXTURE_2D, 0, - 0, bounds.top, t.width, bounds.height(), - GL_RGB, GL_UNSIGNED_SHORT_5_6_5, - t.data + bounds.top*t.stride*2); - } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) { - glTexSubImage2D(GL_TEXTURE_2D, 0, - 0, bounds.top, t.width, bounds.height(), - GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, - t.data + bounds.top*t.stride*2); - } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 || - t.format == HAL_PIXEL_FORMAT_RGBX_8888) { - glTexSubImage2D(GL_TEXTURE_2D, 0, - 0, bounds.top, t.width, bounds.height(), - GL_RGBA, GL_UNSIGNED_BYTE, - t.data + bounds.top*t.stride*4); - } else if (isSupportedYuvFormat(t.format)) { - // just show the Y plane of YUV buffers - glTexSubImage2D(GL_TEXTURE_2D, 0, - 0, bounds.top, t.width, bounds.height(), - GL_LUMINANCE, GL_UNSIGNED_BYTE, - t.data + bounds.top*t.stride); - } - } - return NO_ERROR; -} - -void TextureManager::activateTexture(const Texture& texture, bool filter) -{ - const GLenum target = getTextureTarget(&texture); - if (target == GL_TEXTURE_2D) { - glBindTexture(GL_TEXTURE_2D, texture.name); - glEnable(GL_TEXTURE_2D); -#if defined(GL_OES_texture_external) - if (GLExtensions::getInstance().haveTextureExternal()) { - glDisable(GL_TEXTURE_EXTERNAL_OES); - } - } else { - glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture.name); - glEnable(GL_TEXTURE_EXTERNAL_OES); - glDisable(GL_TEXTURE_2D); -#endif - } - - if (filter) { - glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } else { - glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } -} - -void TextureManager::deactivateTextures() -{ - glDisable(GL_TEXTURE_2D); -#if defined(GL_OES_texture_external) - if (GLExtensions::getInstance().haveTextureExternal()) { - glDisable(GL_TEXTURE_EXTERNAL_OES); - } -#endif -} - -// --------------------------------------------------------------------------- - -}; // namespace android diff --git a/libs/surfaceflinger/TextureManager.h b/libs/surfaceflinger/TextureManager.h deleted file mode 100644 index c7c14e7..0000000 --- a/libs/surfaceflinger/TextureManager.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#ifndef ANDROID_TEXTURE_MANAGER_H -#define ANDROID_TEXTURE_MANAGER_H - -#include <stdint.h> -#include <sys/types.h> - -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <GLES/gl.h> - -#include <ui/Region.h> - -#include <pixelflinger/pixelflinger.h> - -namespace android { - -// --------------------------------------------------------------------------- - -class GLExtensions; -class GraphicBuffer; - -// --------------------------------------------------------------------------- - -struct Image { - enum { TEXTURE_2D=0, TEXTURE_EXTERNAL=1 }; - Image() : name(-1U), image(EGL_NO_IMAGE_KHR), width(0), height(0), - transform(0), dirty(1), target(TEXTURE_2D) { } - GLuint name; - EGLImageKHR image; - GLuint width; - GLuint height; - uint32_t transform; - unsigned dirty : 1; - unsigned target : 1; -}; - -struct Texture : public Image { - Texture() : Image(), NPOTAdjust(0) { } - GLuint potWidth; - GLuint potHeight; - GLfloat wScale; - GLfloat hScale; - unsigned NPOTAdjust : 1; -}; - -// --------------------------------------------------------------------------- - -class TextureManager { - const GLExtensions& mGLExtensions; - static status_t initTexture(Image* texture, int32_t format); - static status_t initTexture(Texture* texture); - static bool isSupportedYuvFormat(int format); - static bool isYuvFormat(int format); - static GLenum getTextureTarget(const Image* pImage); -public: - - TextureManager(); - - // load bitmap data into the active buffer - status_t loadTexture(Texture* texture, - const Region& dirty, const GGLSurface& t); - - // make active buffer an EGLImage if needed - status_t initEglImage(Image* texture, - EGLDisplay dpy, const sp<GraphicBuffer>& buffer); - - // activate a texture - static void activateTexture(const Texture& texture, bool filter); - - // deactivate a texture - static void deactivateTextures(); -}; - -// --------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_TEXTURE_MANAGER_H diff --git a/libs/surfaceflinger/Transform.cpp b/libs/surfaceflinger/Transform.cpp deleted file mode 100644 index 5e27cc9..0000000 --- a/libs/surfaceflinger/Transform.cpp +++ /dev/null @@ -1,391 +0,0 @@ -/* - * 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 <math.h> - -#include <cutils/compiler.h> -#include <utils/String8.h> -#include <ui/Region.h> - -#include "Transform.h" - -// --------------------------------------------------------------------------- - -namespace android { - -// --------------------------------------------------------------------------- - -template <typename T> inline T min(T a, T b) { - return a<b ? a : b; -} -template <typename T> inline T min(T a, T b, T c) { - return min(a, min(b, c)); -} -template <typename T> inline T min(T a, T b, T c, T d) { - return min(a, b, min(c, d)); -} - -template <typename T> inline T max(T a, T b) { - return a>b ? a : b; -} -template <typename T> inline T max(T a, T b, T c) { - return max(a, max(b, c)); -} -template <typename T> inline T max(T a, T b, T c, T d) { - return max(a, b, max(c, d)); -} - -// --------------------------------------------------------------------------- - -Transform::Transform() { - reset(); -} - -Transform::Transform(const Transform& other) - : mMatrix(other.mMatrix), mType(other.mType) { -} - -Transform::Transform(uint32_t orientation) { - set(orientation, 0, 0); -} - -Transform::~Transform() { -} - -static const float EPSILON = 0.0f; - -bool Transform::isZero(float f) { - return fabs(f) <= EPSILON; -} - -bool Transform::absIsOne(float f) { - return isZero(fabs(f) - 1.0f); -} - -Transform Transform::operator * (const Transform& rhs) const -{ - if (CC_LIKELY(mType == IDENTITY)) - return rhs; - - Transform r(*this); - if (rhs.mType == IDENTITY) - return r; - - // TODO: we could use mType to optimize the matrix multiply - const mat33& A(mMatrix); - const mat33& B(rhs.mMatrix); - mat33& D(r.mMatrix); - for (int i=0 ; i<3 ; i++) { - const float v0 = A[0][i]; - const float v1 = A[1][i]; - const float v2 = A[2][i]; - D[0][i] = v0*B[0][0] + v1*B[0][1] + v2*B[0][2]; - D[1][i] = v0*B[1][0] + v1*B[1][1] + v2*B[1][2]; - D[2][i] = v0*B[2][0] + v1*B[2][1] + v2*B[2][2]; - } - r.mType |= rhs.mType; - - // TODO: we could recompute this value from r and rhs - r.mType &= 0xFF; - r.mType |= UNKNOWN_TYPE; - return r; -} - -float const* Transform::operator [] (int i) const { - return mMatrix[i].v; -} - -bool Transform::transformed() const { - return type() > TRANSLATE; -} - -int Transform::tx() const { - return floorf(mMatrix[2][0] + 0.5f); -} - -int Transform::ty() const { - return floorf(mMatrix[2][1] + 0.5f); -} - -void Transform::reset() { - mType = IDENTITY; - for(int i=0 ; i<3 ; i++) { - vec3& v(mMatrix[i]); - for (int j=0 ; j<3 ; j++) - v[j] = ((i==j) ? 1.0f : 0.0f); - } -} - -void Transform::set(float tx, float ty) -{ - mMatrix[2][0] = tx; - mMatrix[2][1] = ty; - mMatrix[2][2] = 1.0f; - - if (isZero(tx) && isZero(ty)) { - mType &= ~TRANSLATE; - } else { - mType |= TRANSLATE; - } -} - -void Transform::set(float a, float b, float c, float d) -{ - mat33& M(mMatrix); - M[0][0] = a; M[1][0] = b; - M[0][1] = c; M[1][1] = d; - M[0][2] = 0; M[1][2] = 0; - mType = UNKNOWN_TYPE; -} - -status_t Transform::set(uint32_t flags, float w, float h) -{ - if (flags & ROT_INVALID) { - // that's not allowed! - reset(); - return BAD_VALUE; - } - - mType = flags << 8; - float sx = (flags & FLIP_H) ? -1 : 1; - float sy = (flags & FLIP_V) ? -1 : 1; - float a=0, b=0, c=0, d=0, x=0, y=0; - int xmask = 0; - - // computation of x,y - // x y - // 0 0 0 - // w 0 ROT90 - // w h FLIPH|FLIPV - // 0 h FLIPH|FLIPV|ROT90 - - if (flags & ROT_90) { - mType |= ROTATE; - b = -sy; - c = sx; - xmask = 1; - } else { - a = sx; - d = sy; - } - - if (flags & FLIP_H) { - mType ^= SCALE; - xmask ^= 1; - } - - if (flags & FLIP_V) { - mType ^= SCALE; - y = h; - } - - if ((flags & ROT_180) == ROT_180) { - mType |= ROTATE; - } - - if (xmask) { - x = w; - } - - if (!isZero(x) || !isZero(y)) { - mType |= TRANSLATE; - } - - mat33& M(mMatrix); - M[0][0] = a; M[1][0] = b; M[2][0] = x; - M[0][1] = c; M[1][1] = d; M[2][1] = y; - M[0][2] = 0; M[1][2] = 0; M[2][2] = 1; - - return NO_ERROR; -} - -Transform::vec2 Transform::transform(const vec2& v) const { - vec2 r; - const mat33& M(mMatrix); - r[0] = M[0][0]*v[0] + M[1][0]*v[1] + M[2][0]; - r[1] = M[0][1]*v[0] + M[1][1]*v[1] + M[2][1]; - return r; -} - -Transform::vec3 Transform::transform(const vec3& v) const { - vec3 r; - const mat33& M(mMatrix); - r[0] = M[0][0]*v[0] + M[1][0]*v[1] + M[2][0]*v[2]; - r[1] = M[0][1]*v[0] + M[1][1]*v[1] + M[2][1]*v[2]; - r[2] = M[0][2]*v[0] + M[1][2]*v[1] + M[2][2]*v[2]; - return r; -} - -void Transform::transform(float* point, int x, int y) const -{ - const mat33& M(mMatrix); - vec2 v(x, y); - v = transform(v); - point[0] = v[0]; - point[1] = v[1]; -} - -Rect Transform::makeBounds(int w, int h) const -{ - return transform( Rect(w, h) ); -} - -Rect Transform::transform(const Rect& bounds) const -{ - Rect r; - vec2 lt( bounds.left, bounds.top ); - vec2 rt( bounds.right, bounds.top ); - vec2 lb( bounds.left, bounds.bottom ); - vec2 rb( bounds.right, bounds.bottom ); - - lt = transform(lt); - rt = transform(rt); - lb = transform(lb); - rb = transform(rb); - - r.left = floorf(min(lt[0], rt[0], lb[0], rb[0]) + 0.5f); - r.top = floorf(min(lt[1], rt[1], lb[1], rb[1]) + 0.5f); - r.right = floorf(max(lt[0], rt[0], lb[0], rb[0]) + 0.5f); - r.bottom = floorf(max(lt[1], rt[1], lb[1], rb[1]) + 0.5f); - - return r; -} - -Region Transform::transform(const Region& reg) const -{ - Region out; - if (CC_UNLIKELY(transformed())) { - if (CC_LIKELY(preserveRects())) { - Region::const_iterator it = reg.begin(); - Region::const_iterator const end = reg.end(); - while (it != end) { - out.orSelf(transform(*it++)); - } - } else { - out.set(transform(reg.bounds())); - } - } else { - out = reg.translate(tx(), ty()); - } - return out; -} - -uint32_t Transform::type() const -{ - if (mType & UNKNOWN_TYPE) { - // recompute what this transform is - - const mat33& M(mMatrix); - const float a = M[0][0]; - const float b = M[1][0]; - const float c = M[0][1]; - const float d = M[1][1]; - const float x = M[2][0]; - const float y = M[2][1]; - - bool scale = false; - uint32_t flags = ROT_0; - if (isZero(b) && isZero(c)) { - if (a<0) flags |= FLIP_H; - if (d<0) flags |= FLIP_V; - if (!absIsOne(a) || !absIsOne(d)) { - scale = true; - } - } else if (isZero(a) && isZero(d)) { - flags |= ROT_90; - if (b>0) flags |= FLIP_H; - if (c<0) flags |= FLIP_V; - if (!absIsOne(b) || !absIsOne(c)) { - scale = true; - } - } else { - flags = ROT_INVALID; - } - - mType = flags << 8; - if (flags & ROT_INVALID) { - mType |= UNKNOWN; - } else { - if ((flags & ROT_90) || ((flags & ROT_180) == ROT_180)) - mType |= ROTATE; - if (flags & FLIP_H) - mType ^= SCALE; - if (flags & FLIP_V) - mType ^= SCALE; - if (scale) - mType |= SCALE; - } - - if (!isZero(x) || !isZero(y)) - mType |= TRANSLATE; - } - return mType; -} - -uint32_t Transform::getType() const { - return type() & 0xFF; -} - -uint32_t Transform::getOrientation() const -{ - return (type() >> 8) & 0xFF; -} - -bool Transform::preserveRects() const -{ - return (type() & ROT_INVALID) ? false : true; -} - -void Transform::dump(const char* name) const -{ - type(); // updates the type - - String8 flags, type; - const mat33& m(mMatrix); - uint32_t orient = mType >> 8; - - if (orient&ROT_INVALID) { - flags.append("ROT_INVALID "); - } else { - if (orient&ROT_90) { - flags.append("ROT_90 "); - } else { - flags.append("ROT_0 "); - } - if (orient&FLIP_V) - flags.append("FLIP_V "); - if (orient&FLIP_H) - flags.append("FLIP_H "); - } - - if (!(mType&(SCALE|ROTATE|TRANSLATE))) - type.append("IDENTITY "); - if (mType&SCALE) - type.append("SCALE "); - if (mType&ROTATE) - type.append("ROTATE "); - if (mType&TRANSLATE) - type.append("TRANSLATE "); - - LOGD("%s 0x%08x (%s, %s)", name, mType, flags.string(), type.string()); - LOGD("%.4f %.4f %.4f", m[0][0], m[1][0], m[2][0]); - LOGD("%.4f %.4f %.4f", m[0][1], m[1][1], m[2][1]); - LOGD("%.4f %.4f %.4f", m[0][2], m[1][2], m[2][2]); -} - -// --------------------------------------------------------------------------- - -}; // namespace android diff --git a/libs/surfaceflinger/Transform.h b/libs/surfaceflinger/Transform.h deleted file mode 100644 index 20fa11a..0000000 --- a/libs/surfaceflinger/Transform.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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. - */ - -#ifndef ANDROID_TRANSFORM_H -#define ANDROID_TRANSFORM_H - -#include <stdint.h> -#include <sys/types.h> - -#include <ui/Point.h> -#include <ui/Rect.h> - -namespace android { - -class Region; - -// --------------------------------------------------------------------------- - -class Transform -{ -public: - Transform(); - Transform(const Transform& other); - explicit Transform(uint32_t orientation); - ~Transform(); - - // FIXME: must match OVERLAY_TRANSFORM_*, pull from hardware.h - enum orientation_flags { - ROT_0 = 0x00000000, - FLIP_H = 0x00000001, - FLIP_V = 0x00000002, - ROT_90 = 0x00000004, - ROT_180 = FLIP_H|FLIP_V, - ROT_270 = ROT_180|ROT_90, - ROT_INVALID = 0x80 - }; - - enum type_mask { - IDENTITY = 0, - TRANSLATE = 0x1, - ROTATE = 0x2, - SCALE = 0x4, - UNKNOWN = 0x8 - }; - - // query the transform - bool transformed() const; - bool preserveRects() const; - uint32_t getType() const; - uint32_t getOrientation() const; - - float const* operator [] (int i) const; // returns column i - int tx() const; - int ty() const; - - // modify the transform - void reset(); - void set(float tx, float ty); - void set(float a, float b, float c, float d); - status_t set(uint32_t flags, float w, float h); - - // transform data - Rect makeBounds(int w, int h) const; - void transform(float* point, int x, int y) const; - Region transform(const Region& reg) const; - Transform operator * (const Transform& rhs) const; - - // for debugging - void dump(const char* name) const; - -private: - struct vec3 { - float v[3]; - inline vec3() { } - inline vec3(float a, float b, float c) { - v[0] = a; v[1] = b; v[2] = c; - } - inline float operator [] (int i) const { return v[i]; } - inline float& operator [] (int i) { return v[i]; } - }; - struct vec2 { - float v[2]; - inline vec2() { } - inline vec2(float a, float b) { - v[0] = a; v[1] = b; - } - inline float operator [] (int i) const { return v[i]; } - inline float& operator [] (int i) { return v[i]; } - }; - struct mat33 { - vec3 v[3]; - inline const vec3& operator [] (int i) const { return v[i]; } - inline vec3& operator [] (int i) { return v[i]; } - }; - - enum { UNKNOWN_TYPE = 0x80000000 }; - - // assumes the last row is < 0 , 0 , 1 > - vec2 transform(const vec2& v) const; - vec3 transform(const vec3& v) const; - Rect transform(const Rect& bounds) const; - uint32_t type() const; - static bool absIsOne(float f); - static bool isZero(float f); - - mat33 mMatrix; - mutable uint32_t mType; -}; - -// --------------------------------------------------------------------------- -}; // namespace android - -#endif /* ANDROID_TRANSFORM_H */ diff --git a/libs/surfaceflinger/clz.cpp b/libs/surfaceflinger/clz.cpp deleted file mode 100644 index 2456b86..0000000 --- a/libs/surfaceflinger/clz.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 "clz.h" - -namespace android { - -int clz_impl(int32_t x) -{ -#if defined(__arm__) && !defined(__thumb__) - return __builtin_clz(x); -#else - if (!x) return 32; - int e = 31; - if (x&0xFFFF0000) { e -=16; x >>=16; } - if (x&0x0000FF00) { e -= 8; x >>= 8; } - if (x&0x000000F0) { e -= 4; x >>= 4; } - if (x&0x0000000C) { e -= 2; x >>= 2; } - if (x&0x00000002) { e -= 1; } - return e; -#endif -} - -}; // namespace android diff --git a/libs/surfaceflinger/clz.h b/libs/surfaceflinger/clz.h deleted file mode 100644 index 0ddf986..0000000 --- a/libs/surfaceflinger/clz.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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. - */ - -#ifndef ANDROID_SURFACE_FLINGER_CLZ_H - -#include <stdint.h> - -namespace android { - -int clz_impl(int32_t x); - -int inline clz(int32_t x) -{ -#if defined(__arm__) && !defined(__thumb__) - return __builtin_clz(x); -#else - return clz_impl(x); -#endif -} - - -}; // namespace android - -#endif /* ANDROID_SURFACE_FLINGER_CLZ_H */ diff --git a/libs/surfaceflinger/tests/Android.mk b/libs/surfaceflinger/tests/Android.mk deleted file mode 100644 index 5053e7d..0000000 --- a/libs/surfaceflinger/tests/Android.mk +++ /dev/null @@ -1 +0,0 @@ -include $(call all-subdir-makefiles) diff --git a/libs/surfaceflinger/tests/overlays/Android.mk b/libs/surfaceflinger/tests/overlays/Android.mk deleted file mode 100644 index 592b601..0000000 --- a/libs/surfaceflinger/tests/overlays/Android.mk +++ /dev/null @@ -1,17 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - overlays.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - libui \ - libsurfaceflinger_client - -LOCAL_MODULE:= test-overlays - -LOCAL_MODULE_TAGS := tests - -include $(BUILD_EXECUTABLE) diff --git a/libs/surfaceflinger/tests/overlays/overlays.cpp b/libs/surfaceflinger/tests/overlays/overlays.cpp deleted file mode 100644 index c248a615..0000000 --- a/libs/surfaceflinger/tests/overlays/overlays.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include <binder/IPCThreadState.h> -#include <binder/ProcessState.h> -#include <binder/IServiceManager.h> -#include <utils/Log.h> - -#include <ui/Overlay.h> - -#include <surfaceflinger/Surface.h> -#include <surfaceflinger/ISurface.h> -#include <surfaceflinger/SurfaceComposerClient.h> - -using namespace android; - -namespace android { -class Test { -public: - static const sp<ISurface>& getISurface(const sp<Surface>& s) { - return s->getISurface(); - } -}; -}; - -int main(int argc, char** argv) -{ - // set up the thread-pool - sp<ProcessState> proc(ProcessState::self()); - ProcessState::self()->startThreadPool(); - - // create a client to surfaceflinger - sp<SurfaceComposerClient> client = new SurfaceComposerClient(); - - // create pushbuffer surface - sp<Surface> surface = client->createSurface(getpid(), 0, 320, 240, - PIXEL_FORMAT_UNKNOWN, ISurfaceComposer::ePushBuffers); - - // get to the isurface - sp<ISurface> isurface = Test::getISurface(surface); - printf("isurface = %p\n", isurface.get()); - - // now request an overlay - sp<OverlayRef> ref = isurface->createOverlay(320, 240, PIXEL_FORMAT_RGB_565); - sp<Overlay> overlay = new Overlay(ref); - - - /* - * here we can use the overlay API - */ - - overlay_buffer_t buffer; - overlay->dequeueBuffer(&buffer); - printf("buffer = %p\n", buffer); - - void* address = overlay->getBufferAddress(buffer); - printf("address = %p\n", address); - - overlay->queueBuffer(buffer); - - return 0; -} diff --git a/libs/surfaceflinger/tests/resize/Android.mk b/libs/surfaceflinger/tests/resize/Android.mk deleted file mode 100644 index 24c2d01..0000000 --- a/libs/surfaceflinger/tests/resize/Android.mk +++ /dev/null @@ -1,17 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - resize.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - libui \ - libsurfaceflinger_client - -LOCAL_MODULE:= test-resize - -LOCAL_MODULE_TAGS := tests - -include $(BUILD_EXECUTABLE) diff --git a/libs/surfaceflinger/tests/resize/resize.cpp b/libs/surfaceflinger/tests/resize/resize.cpp deleted file mode 100644 index 127cca3..0000000 --- a/libs/surfaceflinger/tests/resize/resize.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include <cutils/memory.h> - -#include <utils/Log.h> - -#include <binder/IPCThreadState.h> -#include <binder/ProcessState.h> -#include <binder/IServiceManager.h> - -#include <surfaceflinger/Surface.h> -#include <surfaceflinger/ISurface.h> -#include <surfaceflinger/SurfaceComposerClient.h> - -#include <ui/Overlay.h> - -using namespace android; - -namespace android { -class Test { -public: - static const sp<ISurface>& getISurface(const sp<Surface>& s) { - return s->getISurface(); - } -}; -}; - -int main(int argc, char** argv) -{ - // set up the thread-pool - sp<ProcessState> proc(ProcessState::self()); - ProcessState::self()->startThreadPool(); - - // create a client to surfaceflinger - sp<SurfaceComposerClient> client = new SurfaceComposerClient(); - - // create pushbuffer surface - sp<Surface> surface = client->createSurface(getpid(), 0, 160, 240, - PIXEL_FORMAT_RGB_565); - - - client->openTransaction(); - surface->setLayer(100000); - client->closeTransaction(); - - Surface::SurfaceInfo info; - surface->lock(&info); - ssize_t bpr = info.s * bytesPerPixel(info.format); - android_memset16((uint16_t*)info.bits, 0xF800, bpr*info.h); - surface->unlockAndPost(); - - surface->lock(&info); - android_memset16((uint16_t*)info.bits, 0x07E0, bpr*info.h); - surface->unlockAndPost(); - - client->openTransaction(); - surface->setSize(320, 240); - client->closeTransaction(); - - - IPCThreadState::self()->joinThreadPool(); - - return 0; -} |