diff options
Diffstat (limited to 'libs/audioflinger')
24 files changed, 0 insertions, 13011 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 870c0b8..0000000 --- a/libs/audioflinger/Android.mk +++ /dev/null @@ -1,130 +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 - -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 a018b4c..0000000 --- a/libs/audioflinger/AudioDumpInterface.cpp +++ /dev/null @@ -1,531 +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) - : mFirstHwOutput(true), 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]); - } - 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; - - - if (AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices) || mFirstHwOutput) { - outFinal = mFinalInterface->openOutputStream(devices, format, channels, sampleRate, status); - if (outFinal != 0) { - lFormat = outFinal->format(); - lChannels = outFinal->channels(); - lRate = outFinal->sampleRate(); - if (!AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices)) { - mFirstHwOutput = false; - } - } - } else { - if (format != 0 && *format != 0) { - lFormat = *format; - } else { - lFormat = AudioSystem::PCM_16_BIT; - } - if (channels != 0 && *channels != 0) { - lChannels = *channels; - } else { - lChannels = AudioSystem::CHANNEL_OUT_STEREO; - } - if (sampleRate != 0 && *sampleRate != 0) { - lRate = *sampleRate; - } else { - lRate = 44100; - } - 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()); - mFirstHwOutput = true; - } - - 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; - - - if (mInputs.size() == 0) { - inFinal = mFinalInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics); - if (inFinal == 0) return 0; - - lFormat = inFinal->format(); - lChannels = inFinal->channels(); - lRate = inFinal->sampleRate(); - } else { - if (format != 0 && *format != 0) lFormat = *format; - if (channels != 0 && *channels != 0) lChannels = *channels; - if (sampleRate != 0 && *sampleRate != 0) lRate = *sampleRate; - 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; -} - - -// ---------------------------------------------------------------------------- - -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), mOutFile(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 * 1000000) / frameSize() / sampleRate()); - ret = bytes; - } - if(!mOutFile) { - if (mInterface->fileName() != "") { - char name[255]; - sprintf(name, "%s_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount); - mOutFile = fopen(name, "wb"); - LOGV("Opening dump file %s, fh %p", name, mOutFile); - } - } - if (mOutFile) { - fwrite(buffer, bytes, 1, mOutFile); - } - return ret; -} - -status_t AudioStreamOutDump::standby() -{ - LOGV("AudioStreamOutDump standby(), mOutFile %p, mFinalStream %p", mOutFile, 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 (mOutFile == 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 (mOutFile == 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(mOutFile) { - fclose(mOutFile); - mOutFile = 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), mInFile(0) -{ - LOGV("AudioStreamInDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream); -} - - -AudioStreamInDump::~AudioStreamInDump() -{ - Close(); -} - -ssize_t AudioStreamInDump::read(void* buffer, ssize_t bytes) -{ - if (mFinalStream) { - return mFinalStream->read(buffer, bytes); - } - - usleep((bytes * 1000000) / frameSize() / sampleRate()); - - if(!mInFile) { - 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"); - mInFile = fopen(name, "rb"); - LOGV("Opening dump file %s, fh %p", name, mInFile); - if (mInFile) { - fseek(mInFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET); - } - - } - if (mInFile) { - ssize_t bytesRead = fread(buffer, bytes, 1, mInFile); - if (bytesRead != bytes) { - fseek(mInFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET); - fread((uint8_t *)buffer+bytesRead, bytes-bytesRead, 1, mInFile); - } - } - return bytes; -} - -status_t AudioStreamInDump::standby() -{ - LOGV("AudioStreamInDump standby(), mInFile %p, mFinalStream %p", mInFile, 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(mInFile) { - fclose(mInFile); - mInFile = 0; - } -} -}; // namespace android diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h deleted file mode 100644 index 4c62b3e..0000000 --- a/libs/audioflinger/AudioDumpInterface.h +++ /dev/null @@ -1,166 +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 *mOutFile; // 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 *mInFile; // output file -}; - -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);} - - // 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 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; - bool mFirstHwOutput; - 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 2414e8d..0000000 --- a/libs/audioflinger/AudioFlinger.cpp +++ /dev/null @@ -1,4055 +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 <hardware_legacy/AudioHardwareInterface.h> - -#include "AudioMixer.h" -#include "AudioFlinger.h" - -#ifdef WITH_A2DP -#include "A2dpAudioInterface.h" -#endif - -#ifdef LVMX -#include "lifevibes.h" -#endif - -// ---------------------------------------------------------------------------- -// 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; - -// 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), mNextThreadId(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 - - setMode(AudioSystem::MODE_NORMAL); - - setMasterVolume(1.0f); - setMasterMute(false); - } else { - LOGE("Couldn't even initialize the stubbed audio hardware!"); - } -#ifdef LVMX - LifeVibes::init(); -#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, - status_t *status) -{ - sp<PlaybackThread::Track> track; - sp<TrackHandle> trackHandle; - sp<Client> client; - wp<Client> wclient; - status_t lStatus; - - 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); - } - track = thread->createTrack_l(client, streamType, sampleRate, format, - channelCount, frameCount, sharedBuffer, &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) -{ - // check calling permissions - if (!settingsAllowed()) { - return PERMISSION_DENIED; - } - if ((mode < 0) || (mode >= AudioSystem::NUM_MODES)) { - LOGW("Illegal value: setMode(%d)", mode); - return BAD_VALUE; - } - - AutoMutex lock(mHardwareLock); - mHardwareStatus = AUDIO_HW_SET_MODE; - status_t ret = mAudioHardware->setMode(mode); -#ifdef LVMX - if (NO_ERROR == ret) { - LifeVibes::setMode(mode); - } -#endif - mHardwareStatus = AUDIO_HW_IDLE; - 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) { - musicEnabled = 1; - } else if (value == LifevibesDisable) { - 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 ((NO_ERROR == result) && (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) -{ - - LOGV("registerClient() %p, tid %d, calling tid %d", client.get(), gettid(), IPCThreadState::self()->getCallingPid()); - Mutex::Autolock _l(mLock); - - sp<IBinder> binder = client->asBinder(); - if (mNotificationClients.indexOf(binder) < 0) { - LOGV("Adding notification client %p", binder.get()); - binder->linkToDeath(this); - mNotificationClients.add(binder); - } - - // 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::binderDied(const wp<IBinder>& who) { - - LOGV("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid()); - Mutex::Autolock _l(mLock); - - IBinder *binder = who.unsafe_get(); - - if (binder != NULL) { - int index = mNotificationClients.indexOf(binder); - if (index >= 0) { - LOGV("Removing notification client %p", binder); - mNotificationClients.removeAt(index); - } - } -} - -// 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++) { - sp<IBinder> binder = mNotificationClients.itemAt(i); - LOGV("audioConfigChanged_l() Notifying change to client %p", binder.get()); - sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder); - 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), - mFormat(0), mFrameSize(1), 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 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 because audioConfigChanged() will lock AudioFlinger mLock - // before calling Audioflinger::audioConfigChanged_l() thus creating - // potential cross deadlock between AudioFlinger::mLock and mLock - mLock.unlock(); - audioConfigChanged(configEvent->mEvent, configEvent->mParam); - 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) - : ThreadBase(audioFlinger, id), - mMixBuffer(0), mSuspended(0), mBytesWritten(0), mOutput(output), - mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false) -{ - 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); - } - // notify client processes that a new input has been opened - sendConfigEvent(AudioSystem::OUTPUT_OPENED); -} - -AudioFlinger::PlaybackThread::~PlaybackThread() -{ - delete [] mMixBuffer; -} - -status_t AudioFlinger::PlaybackThread::dump(int fd, const Vector<String16>& args) -{ - dumpInternals(fd, args); - dumpTracks(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 Buf S M F SRate LeftV RighV Serv User\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 Buf S M F SRate LeftV RighV Serv User\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::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); - 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, - status_t *status) -{ - sp<Track> track; - status_t lStatus; - - if (mType == DIRECT) { - if (sampleRate != mSampleRate || format != mFormat || channelCount != 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); - if (track->getCblk() == NULL || track->name() < 0) { - lStatus = NO_MEMORY; - goto Exit; - } - mTracks.add(track); - } - 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); - 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); -} - -void AudioFlinger::PlaybackThread::audioConfigChanged(int event, int param) { - AudioSystem::OutputDescriptor desc; - void *param2 = 0; - - LOGV("PlaybackThread::audioConfigChanged, thread %p, event %d, param %d", this, event, param); - - switch (event) { - case AudioSystem::OUTPUT_OPENED: - case AudioSystem::OUTPUT_CONFIG_CHANGED: - desc.channels = mChannelCount; - 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; - } - Mutex::Autolock _l(mAudioFlinger->mLock); - mAudioFlinger->audioConfigChanged_l(event, mId, param2); -} - -void AudioFlinger::PlaybackThread::readOutputParameters() -{ - mSampleRate = mOutput->sampleRate(); - mChannelCount = AudioSystem::popCount(mOutput->channels()); - - mFormat = mOutput->format(); - mFrameSize = 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)); -} - -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); -} - -// ---------------------------------------------------------------------------- - -AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id) - : PlaybackThread(audioFlinger, output, id), - 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() -{ - int16_t* curBuf = mMixBuffer; - 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; - - 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); - } - - if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) { - // mix buffers... - mAudioMixer->process(curBuf); - sleepTime = 0; - standbyTime = systemTime() + kStandbyTimeInNsecs; - } 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 (curBuf, 0, mixBufferSize); - sleepTime = 0; - LOGV_IF((mBytesWritten == 0 && (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)), "anticipated start"); - } - } - - if (mSuspended) { - sleepTime = idleSleepTime; - } - // sleepTime == 0 means we must write to audio hardware - if (sleepTime == 0) { - mLastWriteTime = systemTime(); - mInWrite = true; - mBytesWritten += mixBufferSize; -#ifdef LVMX - int audioOutputType = LifeVibes::getMixerType(mId, mType); - if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { - LifeVibes::process(audioOutputType, curBuf, mixBufferSize); - } -#endif - int bytesWritten = (int)mOutput->write(curBuf, 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 { - 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(); - } - - 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(); - - 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 - - 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); - - // compute volume for this track - int16_t left, right; - if (track->isMuted() || masterMute || track->isPausing() || - mStreamTypes[track->type()].mute) { - left = right = 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; - float v_clamped = v * cblk->volume[0]; - if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN; - left = int16_t(v_clamped); - v_clamped = v * cblk->volume[1]; - if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN; - right = int16_t(v_clamped); - } - - // XXX: these things DON'T need to be done each time - mAudioMixer->setBufferProvider(track); - mAudioMixer->enable(AudioMixer::MIXING); - - 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; - } -#ifdef LVMX - if ( tracksConnectedChanged || stateChanged ) - { - // only do the ramp when the volume is changed by the user / application - param = AudioMixer::VOLUME; - } -#endif - mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left); - mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right); - mAudioMixer->setParameter( - AudioMixer::TRACK, - AudioMixer::FORMAT, track->format()); - mAudioMixer->setParameter( - AudioMixer::TRACK, - AudioMixer::CHANNEL_COUNT, track->channelCount()); - mAudioMixer->setParameter( - AudioMixer::RESAMPLE, - AudioMixer::SAMPLE_RATE, - int(cblk->sampleRate)); - - // 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); - mAudioMixer->disable(AudioMixer::MIXING); - } 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->isTerminated()) { - mTracks.remove(track); - deleteTrackName_l(track->mName); - } - } - } - - return mixerStatus; -} - -void AudioFlinger::MixerThread::getTracks( - SortedVector < sp<Track> >& tracks, - SortedVector < wp<Track> >& activeTracks, - int streamType) -{ - LOGV ("MixerThread::getTracks() mixer %p, mTracks.size %d, mActiveTracks.size %d", this, mTracks.size(), mActiveTracks.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) { - tracks.add(t); - int j = mActiveTracks.indexOf(t); - if (j >= 0) { - t = mActiveTracks[j].promote(); - if (t != NULL) { - activeTracks.add(t); - } - } - } - } - - size = activeTracks.size(); - for (size_t i = 0; i < size; i++) { - mActiveTracks.remove(activeTracks[i]); - } - - size = tracks.size(); - for (size_t i = 0; i < size; i++) { - sp<Track> t = tracks[i]; - mTracks.remove(t); - deleteTrackName_l(t->name()); - } -} - -void AudioFlinger::MixerThread::putTracks( - SortedVector < sp<Track> >& tracks, - SortedVector < wp<Track> >& activeTracks) -{ - LOGV ("MixerThread::putTracks() mixer %p, tracks.size %d, activeTracks.size %d", this, tracks.size(), activeTracks.size()); - Mutex::Autolock _l(mLock); - size_t size = tracks.size(); - for (size_t i = 0; i < size ; i++) { - sp<Track> t = tracks[i]; - int name = getTrackName_l(); - - if (name < 0) return; - - t->mName = name; - t->mThread = this; - mTracks.add(t); - - int j = activeTracks.indexOf(t); - if (j >= 0) { - mActiveTracks.add(t); - // force buffer refilling and no ramp volume when the track is mixed for the first time - t->mFillingUpStatus = Track::FS_FILLING; - } - } -} - -// 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 (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) - : PlaybackThread(audioFlinger, output, id), - mLeftVolume (1.0), mRightVolume(1.0) -{ - mType = PlaybackThread::DIRECT; -} - -AudioFlinger::DirectOutputThread::~DirectOutputThread() -{ -} - - -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()) - { - 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; - } - } - - // 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); - - // 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 != mLeftVolume || right != mRightVolume) { - mOutput->setVolume(left, right); - left = mLeftVolume; - right = mRightVolume; - } - - if (track->mFillingUpStatus == Track::FS_FILLED) { - track->mFillingUpStatus = Track::FS_ACTIVE; - if (track->mState == TrackBase::RESUMING) { - track->mState = TrackBase::ACTIVE; - } - } - - // 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 (trackToRemove->isTerminated()) { - mTracks.remove(trackToRemove); - deleteTrackName_l(trackToRemove->mName); - } - } - } - - 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) { - mLastWriteTime = systemTime(); - mInWrite = true; - mBytesWritten += mixBufferSize; - int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize); - if (bytesWritten < 0) mBytesWritten -= mixBufferSize; - mNumWrites++; - mInWrite = false; - mStandby = false; - } else { - 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(); - } - - 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), 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() -{ - int16_t* curBuf = mMixBuffer; - 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; - - 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); - } - - if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) { - // mix buffers... - if (outputsReady(outputTracks)) { - mAudioMixer->process(curBuf); - } else { - memset(curBuf, 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; - break; - } - } - } - } - - if (mSuspended) { - sleepTime = idleSleepTime; - } - // sleepTime == 0 means we must write to audio hardware - if (sleepTime == 0) { - standbyTime = systemTime() + kStandbyTimeInNsecs; - for (size_t i = 0; i < outputTracks.size(); i++) { - outputTracks[i]->write(curBuf, writeFrames); - } - mStandby = false; - mBytesWritten += mixBufferSize; - } else { - 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(); - } - - 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) - : RefBase(), - mThread(thread), - mClient(client), - mCblk(0), - mFrameCount(0), - mState(IDLE), - mClientTid(-1), - mFormat(format), - mFlags(flags & ~SYSTEM_FLAGS_MASK) -{ - 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->channels = (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->flowControlFlag = 1; - } 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->channels = (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->flowControlFlag = 1; - 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->channels; -} - -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, channels %d", - bufferStart, bufferEnd, mBuffer, mBufferEnd, - cblk->server, cblk->serverBase, cblk->user, cblk->userBase, cblk->channels); - 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) - : TrackBase(thread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer), - mMute(false), mSharedBuffer(sharedBuffer), mName(-1) -{ - if (mCblk != NULL) { - sp<ThreadBase> baseThread = thread.promote(); - if (baseThread != 0) { - PlaybackThread *playbackThread = (PlaybackThread *)baseThread.get(); - mName = playbackThread->getTrackName_l(); - } - 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, " %5d %5d %3u %3u %3u %04u %1d %1d %1d %5u %5u %5u %08x %08x\n", - mName - AudioMixer::TRACK0, - (mClient == NULL) ? getpid() : mClient->pid(), - mStreamType, - mFormat, - mCblk->channels, - mFrameCount, - mState, - mMute, - mFillingUpStatus, - mCblk->sampleRate, - mCblk->volume[0], - mCblk->volume[1], - mCblk->server, - mCblk->user); -} - -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->forceReady) { - mFillingUpStatus = FS_FILLED; - mCblk->forceReady = 0; - 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->flowControlFlag = 1; - mCblk->forceReady = 0; - 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; -} - -// ---------------------------------------------------------------------------- - -// 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) - : TrackBase(thread, client, sampleRate, format, - channelCount, frameCount, flags, 0), - 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->flowControlFlag = 1; - } -} - -void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size) -{ - snprintf(buffer, size, " %05d %03u %03u %04u %01d %05u %08x %08x\n", - (mClient == NULL) ? getpid() : mClient->pid(), - mFormat, - mCblk->channels, - 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), - mActive(false), mSourceThread(sourceThread) -{ - - PlaybackThread *playbackThread = (PlaybackThread *)thread.unsafe_get(); - if (mCblk != NULL) { - mCblk->out = 1; - 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->channels %d mBufferEnd %p", - mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, 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 channels = mCblk->channels; - 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 * channels]; - pInBuffer->frameCount = startFrames; - pInBuffer->i16 = pInBuffer->mBuffer; - memset(pInBuffer->raw, 0, startFrames * channels * 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 * channels * sizeof(int16_t)); - mCblk->stepUser(outFrames); - pInBuffer->frameCount -= outFrames; - pInBuffer->i16 += outFrames * channels; - mOutBuffer.frameCount -= outFrames; - mOutBuffer.i16 += outFrames * channels; - - 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 * channels]; - pInBuffer->frameCount = inBuffer.frameCount; - pInBuffer->i16 = pInBuffer->mBuffer; - memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channels * 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 * channels]; - pInBuffer->frameCount = frames; - pInBuffer->i16 = pInBuffer->mBuffer; - memset(pInBuffer->raw, 0, frames * channels * 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::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::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, - status_t *status) -{ - sp<RecordThread::RecordTrack> recordTrack; - sp<RecordHandle> recordHandle; - sp<Client> client; - wp<Client> wclient; - status_t lStatus; - RecordThread *thread; - size_t inFrameCount; - - // 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); - } - - // 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); - } - 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(); - sendConfigEvent(AudioSystem::INPUT_OPENED); -} - - -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 (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 && - (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 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(int event, int param) { - AudioSystem::OutputDescriptor desc; - void *param2 = 0; - - switch (event) { - case AudioSystem::INPUT_OPENED: - case AudioSystem::INPUT_CONFIG_CHANGED: - desc.channels = mChannelCount; - desc.samplingRate = mSampleRate; - desc.format = mFormat; - desc.frameCount = mFrameCount; - desc.latency = 0; - param2 = &desc; - break; - - case AudioSystem::INPUT_CLOSED: - default: - break; - } - Mutex::Autolock _l(mAudioFlinger->mLock); - 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(); - mChannelCount = AudioSystem::popCount(mInput->channels()); - mFormat = mInput->format(); - mFrameSize = 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) { - if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) || - (format != AudioSystem::PCM_16_BIT) || - (channels != AudioSystem::CHANNEL_OUT_STEREO)) { - thread = new DirectOutputThread(this, output, ++mNextThreadId); - LOGV("openOutput() created direct output: ID %d thread %p", mNextThreadId, thread); - } else { - thread = new MixerThread(this, output, ++mNextThreadId); - LOGV("openOutput() created mixer output: ID %d thread %p", mNextThreadId, 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(mNextThreadId, thread); - - if (pSamplingRate) *pSamplingRate = samplingRate; - if (pFormat) *pFormat = format; - if (pChannels) *pChannels = channels; - if (pLatencyMs) *pLatencyMs = thread->latency(); - - return mNextThreadId; - } - - 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; - } - - - DuplicatingThread *thread = new DuplicatingThread(this, thread1, ++mNextThreadId); - thread->addOutputTrack(thread2); - mPlaybackThreads.add(mNextThreadId, thread); - return mNextThreadId; -} - -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) { - // Start record thread - thread = new RecordThread(this, input, reqSamplingRate, reqChannels, ++mNextThreadId); - mRecordThreads.add(mNextThreadId, thread); - LOGV("openInput() created record thread: ID %d thread %p", mNextThreadId, thread); - if (pSamplingRate) *pSamplingRate = reqSamplingRate; - if (pFormat) *pFormat = format; - if (pChannels) *pChannels = reqChannels; - - input->standby(); - - return mNextThreadId; - } - - 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); - - 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; - SortedVector < sp<MixerThread::Track> > tracks; - SortedVector < wp<MixerThread::Track> > activeTracks; - srcThread->getTracks(tracks, activeTracks, stream); - if (tracks.size()) { - dstThread->putTracks(tracks, activeTracks); - } - } - } - - dstThread->sendConfigEvent(AudioSystem::STREAM_CONFIG_CHANGED, stream); - - return NO_ERROR; -} - -// 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; -} - -// ---------------------------------------------------------------------------- - -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 739ec33..0000000 --- a/libs/audioflinger/AudioFlinger.h +++ /dev/null @@ -1,807 +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 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 IBinder::DeathRecipient -{ -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, - 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); - - // IBinder::DeathRecipient - virtual void binderDied(const wp<IBinder>& who); - - 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, - status_t *status); - - virtual status_t onTransact( - uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags); - -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; - }; - - - class TrackHandle; - class RecordHandle; - class RecordThread; - class PlaybackThread; - class MixerThread; - class DirectOutputThread; - class DuplicatingThread; - class Track; - class RecordTrack; - - 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); - ~TrackBase(); - - virtual status_t start() = 0; - virtual void stop() = 0; - sp<IMemory> getCblk() const; - audio_track_cblk_t* cblk() const { return mCblk; } - - 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; - }; - - 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(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; - int mChannelCount; - int mFormat; - uint32_t mFrameSize; - 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); - ~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; - } - - - 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; - }; // 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); - 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, - 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(int event, int param = 0); - virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames); - - 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(); - - virtual status_t dumpInternals(int fd, const Vector<String16>& args); - status_t dumpTracks(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; - }; - - class MixerThread : public PlaybackThread { - public: - MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id); - virtual ~MixerThread(); - - // Thread virtuals - virtual bool threadLoop(); - - void getTracks(SortedVector < sp<Track> >& tracks, - SortedVector < wp<Track> >& activeTracks, - int streamType); - void putTracks(SortedVector < sp<Track> >& tracks, - SortedVector < wp<Track> >& activeTracks); - 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); - ~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: - float mLeftVolume; - float mRightVolume; - }; - - 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); - - 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 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); - - - // 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); - ~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(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; - }; - - 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; - - SortedVector< sp<IBinder> > mNotificationClients; - int mNextThreadId; -}; - -// ---------------------------------------------------------------------------- - -}; // 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 19a442a..0000000 --- a/libs/audioflinger/AudioMixer.cpp +++ /dev/null @@ -1,915 +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->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++; - } -} - - 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, int value) -{ - switch (target) { - case TRACK: - if (name == CHANNEL_COUNT) { - if ((uint32_t(value) <= MAX_NUM_CHANNELS) && (value)) { - if (mState.tracks[ mActiveTrack ].channelCount != value) { - mState.tracks[ mActiveTrack ].channelCount = value; - LOGV("setParameter(TRACK, CHANNEL_COUNT, %d)", value); - invalidateState(1<<mActiveTrack); - } - return NO_ERROR; - } - } - break; - case RESAMPLE: - if (name == SAMPLE_RATE) { - if (value > 0) { - track_t& track = mState.tracks[ mActiveTrack ]; - if (track.setResampler(uint32_t(value), mSampleRate)) { - LOGV("setParameter(RESAMPLE, SAMPLE_RATE, %u)", - uint32_t(value)); - 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] != value) { - track.prevVolume[name-VOLUME0] = track.volume[name-VOLUME0] << 16; - track.volume[name-VOLUME0] = value; - if (target == VOLUME) { - track.prevVolume[name-VOLUME0] = value << 16; - track.volumeInc[name-VOLUME0] = 0; - } else { - int32_t d = (value<<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] = value << 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() -{ - 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; - } - } -} - - -status_t AudioMixer::setBufferProvider(AudioBufferProvider* buffer) -{ - mState.tracks[ mActiveTrack ].bufferProvider = buffer; - return NO_ERROR; -} - - - -void AudioMixer::process(void* output) -{ - mState.hook(&mState, output); -} - - -void AudioMixer::process__validate(state_t* state, void* output) -{ - 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.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_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, output); - - // 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 (!resampling && 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) -{ - t->resampler->setSampleRate(t->sampleRate); - - // ramp gain - resample to temp buffer and scale/mix in 2nd step - 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); - } - - // 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) -{ -} - -void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp) -{ - 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 - 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(); -} - -void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp) -{ - int16_t const *in = static_cast<int16_t const *>(t->in); - - // 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(); - } - - // 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) -{ - int16_t const *in = static_cast<int16_t const *>(t->in); - - // 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(); - } - // 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, void* output) -{ - // this assumes output 16 bits stereo, no resampling - memset(output, 0, state->frameCount*4); - uint32_t en = state->enabledTracks; - while (en) { - const int i = 31 - __builtin_clz(en); - en &= ~(1<<i); - track_t& t = state->tracks[i]; - size_t outFrames = state->frameCount; - while (outFrames) { - t.buffer.frameCount = outFrames; - t.bufferProvider->getNextBuffer(&t.buffer); - if (!t.buffer.raw) break; - outFrames -= t.buffer.frameCount; - t.bufferProvider->releaseBuffer(&t.buffer); - } - } -} - -// generic code without resampling -void AudioMixer::process__genericNoResampling(state_t* state, void* output) -{ - int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32))); - - // acquire each track's buffer - uint32_t enabledTracks = state->enabledTracks; - uint32_t en = enabledTracks; - while (en) { - const int i = 31 - __builtin_clz(en); - en &= ~(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); - } - - // this assumes output 16 bits stereo, no resampling - int32_t* out = static_cast<int32_t*>(output); - size_t numFrames = state->frameCount; - do { - memset(outTemp, 0, sizeof(outTemp)); - - en = enabledTracks; - while (en) { - const int i = 31 - __builtin_clz(en); - en &= ~(1<<i); - track_t& t = state->tracks[i]; - size_t outFrames = BLOCKSIZE; - - 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); - t.frameCount -= inFrames; - outFrames -= inFrames; - } - if (t.frameCount == 0 && outFrames) { - t.bufferProvider->releaseBuffer(&t.buffer); - t.buffer.frameCount = numFrames - (BLOCKSIZE - outFrames); - t.bufferProvider->getNextBuffer(&t.buffer); - t.in = t.buffer.raw; - if (t.in == NULL) { - enabledTracks &= ~(1<<i); - break; - } - t.frameCount = t.buffer.frameCount; - } - } - } - - ditherAndClamp(out, outTemp, BLOCKSIZE); - out += BLOCKSIZE; - numFrames -= BLOCKSIZE; - } while (numFrames); - - - // release each track's buffer - en = enabledTracks; - while (en) { - const int i = 31 - __builtin_clz(en); - en &= ~(1<<i); - track_t& t = state->tracks[i]; - t.bufferProvider->releaseBuffer(&t.buffer); - } -} - -// generic code with resampling -void AudioMixer::process__genericResampling(state_t* state, void* output) -{ - int32_t* const outTemp = state->outputTemp; - const size_t size = sizeof(int32_t) * MAX_NUM_CHANNELS * state->frameCount; - memset(outTemp, 0, size); - - int32_t* out = static_cast<int32_t*>(output); - size_t numFrames = state->frameCount; - - uint32_t en = state->enabledTracks; - while (en) { - const int i = 31 - __builtin_clz(en); - en &= ~(1<<i); - track_t& t = state->tracks[i]; - - // 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); - } else { - - size_t outFrames = numFrames; - - while (outFrames) { - t.buffer.frameCount = 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; - - (t.hook)(&t, outTemp + (numFrames-outFrames)*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp); - 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, void* output) -{ - const int i = 31 - __builtin_clz(state->enabledTracks); - const track_t& t = state->tracks[i]; - - AudioBufferProvider::Buffer& b(t.buffer); - - int32_t* out = static_cast<int32_t*>(output); - 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 -void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output) -{ - 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; - - int32_t* out = static_cast<int32_t*>(output); - 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 15766cd..0000000 --- a/libs/audioflinger/AudioMixer.h +++ /dev/null @@ -1,193 +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, - // for TARGET RESAMPLE - SAMPLE_RATE = 0x4100, - // for TARGET VOLUME (8 channels max) - VOLUME0 = 0x4200, - VOLUME1 = 0x4201, - }; - - - 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, int value); - - status_t setBufferProvider(AudioBufferProvider* bufferProvider); - void process(void* output); - - 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, - }; - - 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, - }; - - static inline int32_t applyVolume(int32_t in, int32_t v) { - return in * v; - } - - - struct state_t; - - typedef void (*mix_t)(state_t* state, void* output); - - 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]; - - uint16_t frameCount; - - uint8_t channelCount : 4; - uint8_t enabled : 1; - uint8_t reserved0 : 3; - uint8_t format; - - AudioBufferProvider* bufferProvider; - mutable AudioBufferProvider::Buffer buffer; - - void (*hook)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp); - void const* in; // current location in buffer - - AudioResampler* resampler; - uint32_t sampleRate; - - bool setResampler(uint32_t sampleRate, uint32_t devSampleRate); - bool doesResample() const; - void adjustVolumeRamp(); - }; - - // 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); - static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp); - static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp); - static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp); - static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp); - - static void process__validate(state_t* state, void* output); - static void process__nop(state_t* state, void* output); - static void process__genericNoResampling(state_t* state, void* output); - static void process__genericResampling(state_t* state, void* output); - static void process__OneTrack16BitsStereoNoResampling(state_t* state, void* output); - static void process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output); -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_AUDIO_MIXER_H diff --git a/libs/audioflinger/AudioPolicyManagerBase.cpp b/libs/audioflinger/AudioPolicyManagerBase.cpp deleted file mode 100644 index c8b3f48..0000000 --- a/libs/audioflinger/AudioPolicyManagerBase.cpp +++ /dev/null @@ -1,1972 +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) { - 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); - int refCount = a2dpOutputDesc->mRefCount[i]; - // in the case of duplicated output, the ref count is first incremented - // and then decremented on hardware output tus keeping its value - hwOutputDesc->changeRefCount((AudioSystem::stream_type)i, refCount); - a2dpOutputDesc->changeRefCount((AudioSystem::stream_type)i,-refCount); - } - } - // 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); - int refCount = hwOutputDesc->mRefCount[i]; - // in the case of duplicated output, the ref count is first incremented - // and then decremented on hardware output tus keeping its value - a2dpOutputDesc->changeRefCount((AudioSystem::stream_type)i, refCount); - hwOutputDesc->changeRefCount((AudioSystem::stream_type)i,-refCount); - } - } - } -} - -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*/ |