summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilipp Tomsich <philipp.tomsich@theobroma-systems.com>2017-08-23 19:48:09 +0200
committerPhilipp Tomsich <philipp.tomsich@theobroma-systems.com>2017-08-23 19:48:09 +0200
commitcbbcf6345b38a7c137d644240d38d9d177908b38 (patch)
treea665496c6996736d5f75b49061c69d96dda50730
Import of Rockchip Android 7.1.1 SDKHEADmaster
-rw-r--r--Android.mk11
-rwxr-xr-xlegacy_hal/A2dpAudioInterface.cpp499
-rwxr-xr-xlegacy_hal/A2dpAudioInterface.h139
-rwxr-xr-xlegacy_hal/Android.mk142
-rwxr-xr-xlegacy_hal/AudioDumpInterface.cpp573
-rwxr-xr-xlegacy_hal/AudioDumpInterface.h170
-rwxr-xr-xlegacy_hal/AudioHardware.cpp2132
-rwxr-xr-xlegacy_hal/AudioHardware.h401
-rwxr-xr-xlegacy_hal/AudioHardwareGeneric.cpp413
-rwxr-xr-xlegacy_hal/AudioHardwareGeneric.h156
-rwxr-xr-xlegacy_hal/AudioHardwareInterface.cpp169
-rwxr-xr-xlegacy_hal/AudioHardwareStub.cpp215
-rwxr-xr-xlegacy_hal/AudioHardwareStub.h108
-rwxr-xr-xlegacy_hal/AudioPolicyCompatClient.cpp147
-rwxr-xr-xlegacy_hal/AudioPolicyCompatClient.h83
-rwxr-xr-xlegacy_hal/AudioPolicyManagerBase.cpp4411
-rwxr-xr-xlegacy_hal/AudioPolicyManagerDefault.cpp34
-rwxr-xr-xlegacy_hal/AudioPolicyManagerDefault.h35
-rwxr-xr-xlegacy_hal/AudioUsbAudioHardware.h172
-rwxr-xr-xlegacy_hal/alsa_audio.h167
-rwxr-xr-xlegacy_hal/alsa_mixer.c609
-rwxr-xr-xlegacy_hal/alsa_pcm.c594
-rwxr-xr-xlegacy_hal/alsa_route.c567
-rwxr-xr-xlegacy_hal/amix.c103
-rwxr-xr-xlegacy_hal/asound.h836
-rwxr-xr-xlegacy_hal/audio_hw_hal.cpp714
-rwxr-xr-xlegacy_hal/audio_policy_hal.cpp477
-rwxr-xr-xlegacy_hal/codec_config/config.h74
-rwxr-xr-xlegacy_hal/codec_config/config_list.h62
-rwxr-xr-xlegacy_hal/codec_config/default_config.h434
-rwxr-xr-xlegacy_hal/codec_config/rk616_config.h1600
-rwxr-xr-xlegacy_hal/codec_config/rt3224_config.h3962
-rwxr-xr-xlegacy_hal/codec_config/rt3261_config.h3751
-rwxr-xr-xlegacy_hal/codec_config/rt5616_config.h901
-rw-r--r--legacy_hal/codec_config/wm8960_config.h862
-rwxr-xr-xlegacy_hal/secril-client.h175
36 files changed, 25898 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..4e04d8e
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,11 @@
+#legacy audio hal is just for debuging, and we use tinyalsa in all rk product
+#use AUDIO_FORCE_LEGACY to choose which you need.
+
+MY_LOCAL_PATH := $(call my-dir)
+
+AUDIO_FORCE_LEGACY=false
+
+ifeq ($(strip $(AUDIO_FORCE_LEGACY)), true)
+ include $(MY_LOCAL_PATH)/legacy_hal/Android.mk
+endif
+
diff --git a/legacy_hal/A2dpAudioInterface.cpp b/legacy_hal/A2dpAudioInterface.cpp
new file mode 100755
index 0000000..4ab52ba
--- /dev/null
+++ b/legacy_hal/A2dpAudioInterface.cpp
@@ -0,0 +1,499 @@
+/*
+ * 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"
+#include <hardware_legacy/power.h>
+
+
+namespace android_audio_legacy {
+
+static const char *sA2dpWakeLock = "A2dpOutputStream";
+#define MAX_WRITE_RETRIES 5
+
+// ----------------------------------------------------------------------------
+
+//AudioHardwareInterface* A2dpAudioInterface::createA2dpInterface()
+//{
+// AudioHardwareInterface* hw = 0;
+//
+// hw = AudioHardwareInterface::create();
+// ALOGD("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 (!audio_is_a2dp_out_device(devices)) {
+ ALOGV("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;
+
+ ALOGV("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());
+ }
+
+ ALOGV("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;
+
+ ALOGD("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;
+ mBufferDurationUs = ((bufferSize() * 1000 )/ frameSize() / sampleRate()) * 1000;
+ return NO_ERROR;
+}
+
+A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
+{
+ ALOGV("A2dpAudioStreamOut destructor");
+ close();
+ ALOGV("A2dpAudioStreamOut destructor returning from close()");
+}
+
+ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
+{
+ status_t status = -1;
+ {
+ Mutex::Autolock lock(mLock);
+
+ size_t remaining = bytes;
+
+ if (!mBluetoothEnabled || mClosing || mSuspended) {
+ ALOGV("A2dpAudioStreamOut::write(), but bluetooth disabled \
+ mBluetoothEnabled %d, mClosing %d, mSuspended %d",
+ mBluetoothEnabled, mClosing, mSuspended);
+ goto Error;
+ }
+
+ if (mStandby) {
+ acquire_wake_lock (PARTIAL_WAKE_LOCK, sA2dpWakeLock);
+ mStandby = false;
+ mLastWriteTime = systemTime();
+ }
+
+ status = init();
+ if (status < 0)
+ goto Error;
+
+ int retries = MAX_WRITE_RETRIES;
+ while (remaining > 0 && retries) {
+ status = a2dp_write(mData, buffer, remaining);
+ if (status < 0) {
+ ALOGE("a2dp_write failed err: %d\n", status);
+ goto Error;
+ }
+ if (status == 0) {
+ retries--;
+ }
+ remaining -= status;
+ buffer = (char *)buffer + status;
+ }
+
+ // if A2DP sink runs abnormally fast, sleep a little so that audioflinger mixer thread
+ // does no spin and starve other threads.
+ // NOTE: It is likely that the A2DP headset is being disconnected
+ nsecs_t now = systemTime();
+ if ((uint32_t)ns2us(now - mLastWriteTime) < (mBufferDurationUs >> 2)) {
+ ALOGV("A2DP sink runs too fast");
+ usleep(mBufferDurationUs - (uint32_t)ns2us(now - mLastWriteTime));
+ }
+ mLastWriteTime = now;
+ return bytes;
+
+ }
+Error:
+
+ standby();
+
+ // Simulate audio output timing in case of error
+ usleep(mBufferDurationUs);
+
+ return status;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::init()
+{
+ if (!mData) {
+ status_t status = a2dp_init(44100, 2, &mData);
+ if (status < 0) {
+ ALOGE("a2dp_init failed err: %d\n", status);
+ mData = NULL;
+ return status;
+ }
+ a2dp_set_sink(mData, mA2dpAddress);
+ }
+
+ return 0;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
+{
+ Mutex::Autolock lock(mLock);
+ return standby_l();
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::standby_l()
+{
+ int result = NO_ERROR;
+
+ if (!mStandby) {
+ ALOGV_IF(mClosing || !mBluetoothEnabled, "Standby skip stop: closing %d enabled %d",
+ mClosing, mBluetoothEnabled);
+ if (!mClosing && mBluetoothEnabled) {
+ result = a2dp_stop(mData);
+ }
+ release_wake_lock(sA2dpWakeLock);
+ 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;
+ ALOGV("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");
+ if (mClosing) {
+ standby();
+ }
+ param.remove(key);
+ }
+ key = AudioParameter::keyRouting;
+ if (param.getInt(key, device) == NO_ERROR) {
+ if (audio_is_a2dp_out_device(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);
+ }
+
+ ALOGV("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)
+{
+ ALOGD("setBluetoothEnabled %d", enabled);
+
+ Mutex::Autolock lock(mLock);
+
+ mBluetoothEnabled = enabled;
+ if (!enabled) {
+ return close_l();
+ }
+ return NO_ERROR;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::setSuspended(bool onOff)
+{
+ ALOGV("setSuspended %d", onOff);
+ mSuspended = onOff;
+ standby();
+ return NO_ERROR;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::close()
+{
+ Mutex::Autolock lock(mLock);
+ ALOGV("A2dpAudioStreamOut::close() calling close_l()");
+ return close_l();
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::close_l()
+{
+ standby_l();
+ if (mData) {
+ ALOGV("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/legacy_hal/A2dpAudioInterface.h b/legacy_hal/A2dpAudioInterface.h
new file mode 100755
index 0000000..8fe9745
--- /dev/null
+++ b/legacy_hal/A2dpAudioInterface.h
@@ -0,0 +1,139 @@
+/*
+ * 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_audio_legacy {
+ using android::Mutex;
+
+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);
+ status_t standby_l();
+
+ 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;
+ nsecs_t mLastWriteTime;
+ uint32_t mBufferDurationUs;
+ };
+
+ friend class A2dpAudioStreamOut;
+
+ A2dpAudioStreamOut* mOutput;
+ AudioHardwareInterface *mHardwareInterface;
+ char mA2dpAddress[20];
+ bool mBluetoothEnabled;
+ bool mSuspended;
+};
+
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // A2DP_AUDIO_HARDWARE_H
diff --git a/legacy_hal/Android.mk b/legacy_hal/Android.mk
new file mode 100755
index 0000000..0d6c6d5
--- /dev/null
+++ b/legacy_hal/Android.mk
@@ -0,0 +1,142 @@
+# Copyright 2011 The Android Open Source Project
+ifneq ($(strip $(BOARD_USES_ALSA_AUDIO)),true)
+#AUDIO_POLICY_TEST := true
+#ENABLE_AUDIO_DUMP := true
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ AudioHardwareInterface.cpp\
+ AudioHardware.cpp \
+ audio_hw_hal.cpp\
+ alsa_mixer.c\
+ alsa_route.c\
+ alsa_pcm.c
+
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+ LOCAL_CFLAGS += -DWITH_A2DP
+endif
+
+ifeq ($(strip $(TARGET_BOARD_HARDWARE)), rk2928board)
+ LOCAL_CFLAGS += -DTARGET_RK2928
+endif
+
+LOCAL_MODULE := audio.primary.$(TARGET_BOARD_HARDWARE)
+ifneq (1,$(strip $(shell expr $(PLATFORM_VERSION) \>= 5.0)))
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+else
+ifneq ($(strip $(TARGET_2ND_ARCH)), )
+LOCAL_MULTILIB := both
+endif
+LOCAL_MODULE_RELATIVE_PATH := hw
+endif
+LOCAL_MODULE_TAGS := optional
+LOCAL_STATIC_LIBRARIES := libmedia_helper \
+ libspeex
+
+LOCAL_C_INCLUDES := \
+ $(call include-path-for, speex)
+LOCAL_SHARED_LIBRARIES:= libc libcutils libutils libmedia libhardware_legacy libspeexresampler
+include $(BUILD_SHARED_LIBRARY)
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= amix.c alsa_mixer.c
+LOCAL_CFLAGS += -DSUPPORT_USB
+LOCAL_MODULE:= amix
+LOCAL_SHARED_LIBRARIES := libc libcutils
+LOCAL_MODULE_TAGS:= debug
+include $(BUILD_EXECUTABLE)
+
+#build the usb simple libaudio
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ AudioHardwareInterface.cpp\
+ AudioHardware.cpp \
+ audio_hw_hal.cpp\
+ alsa_mixer.c\
+ alsa_route.c\
+ alsa_pcm.c
+
+LOCAL_CFLAGS += -DSUPPORT_USB
+LOCAL_MODULE := audio.alsa_usb.$(TARGET_BOARD_HARDWARE)
+ifneq (1,$(strip $(shell expr $(PLATFORM_VERSION) \>= 5.0)))
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+else
+ifneq ($(strip $(TARGET_2ND_ARCH)), )
+LOCAL_MULTILIB := both
+endif
+LOCAL_MODULE_RELATIVE_PATH := hw
+endif
+LOCAL_MODULE_TAGS := optional
+LOCAL_STATIC_LIBRARIES := libmedia_helper \
+ libspeex
+LOCAL_CFLAGS := -Wno-unused-parameter
+LOCAL_C_INCLUDES := \
+ $(call include-path-for, speex)
+LOCAL_SHARED_LIBRARIES:= libc libcutils libutils libmedia libhardware_legacy libspeexresampler
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ AudioPolicyManagerBase.cpp \
+ AudioPolicyCompatClient.cpp \
+ audio_policy_hal.cpp
+
+ifeq ($(AUDIO_POLICY_TEST),true)
+ LOCAL_CFLAGS += -DAUDIO_POLICY_TEST
+endif
+
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+ LOCAL_CFLAGS += -DWITH_A2DP
+endif
+
+ifeq ($(strip $(TARGET_BOARD_HARDWARE)), rk2928board)
+ LOCAL_CFLAGS += -DTARGET_RK2928
+endif
+
+LOCAL_STATIC_LIBRARIES := libmedia_helper
+LOCAL_MODULE := libaudiopolicy_$(TARGET_BOARD_HARDWARE)
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_LIBRARY)
+
+# The default audio policy, for now still implemented on top of legacy
+# policy code
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ AudioPolicyManagerDefault.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libmedia \
+ liblog
+
+LOCAL_STATIC_LIBRARIES := \
+ libmedia_helper
+
+LOCAL_WHOLE_STATIC_LIBRARIES := \
+ libaudiopolicy_$(TARGET_BOARD_HARDWARE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := audio_policy.$(TARGET_BOARD_HARDWARE)
+ifneq (1,$(strip $(shell expr $(PLATFORM_VERSION) \>= 5.0)))
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+else
+ifneq ($(strip $(TARGET_2ND_ARCH)), )
+LOCAL_MULTILIB := both
+endif
+LOCAL_MODULE_RELATIVE_PATH := hw
+endif
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -Wno-unused-parameter
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+ LOCAL_CFLAGS += -DWITH_A2DP
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+endif
+
diff --git a/legacy_hal/AudioDumpInterface.cpp b/legacy_hal/AudioDumpInterface.cpp
new file mode 100755
index 0000000..62fdbd6
--- /dev/null
+++ b/legacy_hal/AudioDumpInterface.cpp
@@ -0,0 +1,573 @@
+/* //device/servers/AudioFlinger/AudioDumpInterface.cpp
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "AudioFlingerDump"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "AudioDumpInterface.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw)
+ : mPolicyCommands(String8("")), mFileName(String8(""))
+{
+ if(hw == 0) {
+ ALOGE("Dump construct hw = 0");
+ }
+ mFinalInterface = hw;
+ ALOGV("Constructor %p, mFinalInterface %p", this, mFinalInterface);
+}
+
+
+AudioDumpInterface::~AudioDumpInterface()
+{
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ closeOutputStream((AudioStreamOut *)mOutputs[i]);
+ }
+
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ closeInputStream((AudioStreamIn *)mInputs[i]);
+ }
+
+ if(mFinalInterface) delete mFinalInterface;
+}
+
+
+AudioStreamOut* AudioDumpInterface::openOutputStream(
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
+{
+ AudioStreamOut* outFinal = NULL;
+ int lFormat = AudioSystem::PCM_16_BIT;
+ uint32_t lChannels = AudioSystem::CHANNEL_OUT_STEREO;
+ uint32_t lRate = 44100;
+
+
+ outFinal = mFinalInterface->openOutputStream(devices, format, channels, sampleRate, status);
+ if (outFinal != 0) {
+ lFormat = outFinal->format();
+ lChannels = outFinal->channels();
+ lRate = outFinal->sampleRate();
+ } else {
+ if (format != 0) {
+ if (*format != 0) {
+ lFormat = *format;
+ } else {
+ *format = lFormat;
+ }
+ }
+ if (channels != 0) {
+ if (*channels != 0) {
+ lChannels = *channels;
+ } else {
+ *channels = lChannels;
+ }
+ }
+ if (sampleRate != 0) {
+ if (*sampleRate != 0) {
+ lRate = *sampleRate;
+ } else {
+ *sampleRate = lRate;
+ }
+ }
+ if (status) *status = NO_ERROR;
+ }
+ ALOGV("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) {
+ ALOGW("Attempt to close invalid output stream");
+ return;
+ }
+
+ ALOGV("closeOutputStream() output %p", out);
+
+ dumpOut->standby();
+ if (dumpOut->finalStream() != NULL) {
+ mFinalInterface->closeOutputStream(dumpOut->finalStream());
+ }
+
+ mOutputs.remove(dumpOut);
+ delete dumpOut;
+}
+
+AudioStreamIn* AudioDumpInterface::openInputStream(uint32_t devices, int *format, uint32_t *channels,
+ uint32_t *sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics)
+{
+ AudioStreamIn* inFinal = NULL;
+ int lFormat = AudioSystem::PCM_16_BIT;
+ uint32_t lChannels = AudioSystem::CHANNEL_IN_MONO;
+ uint32_t lRate = 8000;
+
+ inFinal = mFinalInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics);
+ if (inFinal != 0) {
+ lFormat = inFinal->format();
+ lChannels = inFinal->channels();
+ lRate = inFinal->sampleRate();
+ } else {
+ if (format != 0) {
+ if (*format != 0) {
+ lFormat = *format;
+ } else {
+ *format = lFormat;
+ }
+ }
+ if (channels != 0) {
+ if (*channels != 0) {
+ lChannels = *channels;
+ } else {
+ *channels = lChannels;
+ }
+ }
+ if (sampleRate != 0) {
+ if (*sampleRate != 0) {
+ lRate = *sampleRate;
+ } else {
+ *sampleRate = lRate;
+ }
+ }
+ if (status) *status = NO_ERROR;
+ }
+ ALOGV("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) {
+ ALOGW("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;
+ ALOGV("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();
+ ALOGV("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;
+
+// ALOGV("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"));
+// ALOGV("test_cmd_policy command %s read", mPolicyCommands.string());
+ }
+
+ if (param.get(String8("test_cmd_file_name"), value) == NO_ERROR) {
+ response.add(String8("test_cmd_file_name"), mFileName);
+ param.remove(String8("test_cmd_file_name"));
+ }
+
+ String8 keyValuePairs = response.toString();
+
+ if (param.size() && mFinalInterface != 0 ) {
+ keyValuePairs += ";";
+ keyValuePairs += mFinalInterface->getParameters(param.toString());
+ }
+
+ return keyValuePairs;
+}
+
+status_t AudioDumpInterface::setMode(int mode)
+{
+ return mFinalInterface->setMode(mode);
+}
+
+size_t AudioDumpInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+ return mFinalInterface->getInputBufferSize(sampleRate, format, channelCount);
+}
+
+// ----------------------------------------------------------------------------
+
+AudioStreamOutDump::AudioStreamOutDump(AudioDumpInterface *interface,
+ int id,
+ AudioStreamOut* finalStream,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t sampleRate)
+ : mInterface(interface), mId(id),
+ mSampleRate(sampleRate), mFormat(format), mChannels(channels), mLatency(0), mDevice(devices),
+ mBufferSize(1024), mFinalStream(finalStream), mFile(0), mFileCount(0)
+{
+ ALOGV("AudioStreamOutDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream);
+}
+
+
+AudioStreamOutDump::~AudioStreamOutDump()
+{
+ ALOGV("AudioStreamOutDump destructor");
+ Close();
+}
+
+ssize_t AudioStreamOutDump::write(const void* buffer, size_t bytes)
+{
+ ssize_t ret;
+
+ if (mFinalStream) {
+ ret = mFinalStream->write(buffer, bytes);
+ } else {
+ usleep((((bytes * 1000) / frameSize()) / sampleRate()) * 1000);
+ ret = bytes;
+ }
+ if(!mFile) {
+ if (mInterface->fileName() != "") {
+ char name[255];
+ sprintf(name, "%s_out_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount);
+ mFile = fopen(name, "wb");
+ ALOGV("Opening dump file %s, fh %p", name, mFile);
+ }
+ }
+ if (mFile) {
+ fwrite(buffer, bytes, 1, mFile);
+ }
+ return ret;
+}
+
+status_t AudioStreamOutDump::standby()
+{
+ ALOGV("AudioStreamOutDump standby(), mFile %p, mFinalStream %p", mFile, mFinalStream);
+
+ Close();
+ if (mFinalStream != 0 ) return mFinalStream->standby();
+ return NO_ERROR;
+}
+
+uint32_t AudioStreamOutDump::sampleRate() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->sampleRate();
+ return mSampleRate;
+}
+
+size_t AudioStreamOutDump::bufferSize() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->bufferSize();
+ return mBufferSize;
+}
+
+uint32_t AudioStreamOutDump::channels() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->channels();
+ return mChannels;
+}
+int AudioStreamOutDump::format() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->format();
+ return mFormat;
+}
+uint32_t AudioStreamOutDump::latency() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->latency();
+ return 0;
+}
+status_t AudioStreamOutDump::setVolume(float left, float right)
+{
+ if (mFinalStream != 0 ) return mFinalStream->setVolume(left, right);
+ return NO_ERROR;
+}
+status_t AudioStreamOutDump::setParameters(const String8& keyValuePairs)
+{
+ ALOGV("AudioStreamOutDump::setParameters %s", keyValuePairs.string());
+
+ if (mFinalStream != 0 ) {
+ return mFinalStream->setParameters(keyValuePairs);
+ }
+
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 value;
+ int valueInt;
+ status_t status = NO_ERROR;
+
+ if (param.getInt(String8("set_id"), valueInt) == NO_ERROR) {
+ mId = valueInt;
+ }
+
+ if (param.getInt(String8("format"), valueInt) == NO_ERROR) {
+ if (mFile == 0) {
+ mFormat = valueInt;
+ } else {
+ status = INVALID_OPERATION;
+ }
+ }
+ if (param.getInt(String8("channels"), valueInt) == NO_ERROR) {
+ if (valueInt == AudioSystem::CHANNEL_OUT_STEREO || valueInt == AudioSystem::CHANNEL_OUT_MONO) {
+ mChannels = valueInt;
+ } else {
+ status = BAD_VALUE;
+ }
+ }
+ if (param.getInt(String8("sampling_rate"), valueInt) == NO_ERROR) {
+ if (valueInt > 0 && valueInt <= 48000) {
+ if (mFile == 0) {
+ mSampleRate = valueInt;
+ } else {
+ status = INVALID_OPERATION;
+ }
+ } else {
+ status = BAD_VALUE;
+ }
+ }
+ return status;
+}
+
+String8 AudioStreamOutDump::getParameters(const String8& keys)
+{
+ if (mFinalStream != 0 ) return mFinalStream->getParameters(keys);
+
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
+}
+
+status_t AudioStreamOutDump::dump(int fd, const Vector<String16>& args)
+{
+ if (mFinalStream != 0 ) return mFinalStream->dump(fd, args);
+ return NO_ERROR;
+}
+
+void AudioStreamOutDump::Close()
+{
+ if(mFile) {
+ fclose(mFile);
+ mFile = 0;
+ }
+}
+
+status_t AudioStreamOutDump::getRenderPosition(uint32_t *dspFrames)
+{
+ if (mFinalStream != 0 ) return mFinalStream->getRenderPosition(dspFrames);
+ return INVALID_OPERATION;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioStreamInDump::AudioStreamInDump(AudioDumpInterface *interface,
+ int id,
+ AudioStreamIn* finalStream,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t sampleRate)
+ : mInterface(interface), mId(id),
+ mSampleRate(sampleRate), mFormat(format), mChannels(channels), mDevice(devices),
+ mBufferSize(1024), mFinalStream(finalStream), mFile(0), mFileCount(0)
+{
+ ALOGV("AudioStreamInDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream);
+}
+
+
+AudioStreamInDump::~AudioStreamInDump()
+{
+ Close();
+}
+
+ssize_t AudioStreamInDump::read(void* buffer, ssize_t bytes)
+{
+ ssize_t ret;
+
+ if (mFinalStream) {
+ ret = mFinalStream->read(buffer, bytes);
+ if(!mFile) {
+ if (mInterface->fileName() != "") {
+ char name[255];
+ sprintf(name, "%s_in_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount);
+ mFile = fopen(name, "wb");
+ ALOGV("Opening input dump file %s, fh %p", name, mFile);
+ }
+ }
+ if (mFile) {
+ fwrite(buffer, bytes, 1, mFile);
+ }
+ } else {
+ usleep((((bytes * 1000) / frameSize()) / sampleRate()) * 1000);
+ ret = bytes;
+ if(!mFile) {
+ char name[255];
+ strcpy(name, "/sdcard/music/sine440");
+ if (channels() == AudioSystem::CHANNEL_IN_MONO) {
+ strcat(name, "_mo");
+ } else {
+ strcat(name, "_st");
+ }
+ if (format() == AudioSystem::PCM_16_BIT) {
+ strcat(name, "_16b");
+ } else {
+ strcat(name, "_8b");
+ }
+ if (sampleRate() < 16000) {
+ strcat(name, "_8k");
+ } else if (sampleRate() < 32000) {
+ strcat(name, "_22k");
+ } else if (sampleRate() < 48000) {
+ strcat(name, "_44k");
+ } else {
+ strcat(name, "_48k");
+ }
+ strcat(name, ".wav");
+ mFile = fopen(name, "rb");
+ ALOGV("Opening input read file %s, fh %p", name, mFile);
+ if (mFile) {
+ fseek(mFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET);
+ }
+ }
+ if (mFile) {
+ ssize_t bytesRead = fread(buffer, bytes, 1, mFile);
+ if (bytesRead >=0 && bytesRead < bytes) {
+ fseek(mFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET);
+ fread((uint8_t *)buffer+bytesRead, bytes-bytesRead, 1, mFile);
+ }
+ }
+ }
+
+ return ret;
+}
+
+status_t AudioStreamInDump::standby()
+{
+ ALOGV("AudioStreamInDump standby(), mFile %p, mFinalStream %p", mFile, mFinalStream);
+
+ Close();
+ if (mFinalStream != 0 ) return mFinalStream->standby();
+ return NO_ERROR;
+}
+
+status_t AudioStreamInDump::setGain(float gain)
+{
+ if (mFinalStream != 0 ) return mFinalStream->setGain(gain);
+ return NO_ERROR;
+}
+
+uint32_t AudioStreamInDump::sampleRate() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->sampleRate();
+ return mSampleRate;
+}
+
+size_t AudioStreamInDump::bufferSize() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->bufferSize();
+ return mBufferSize;
+}
+
+uint32_t AudioStreamInDump::channels() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->channels();
+ return mChannels;
+}
+
+int AudioStreamInDump::format() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->format();
+ return mFormat;
+}
+
+status_t AudioStreamInDump::setParameters(const String8& keyValuePairs)
+{
+ ALOGV("AudioStreamInDump::setParameters()");
+ if (mFinalStream != 0 ) return mFinalStream->setParameters(keyValuePairs);
+ return NO_ERROR;
+}
+
+String8 AudioStreamInDump::getParameters(const String8& keys)
+{
+ if (mFinalStream != 0 ) return mFinalStream->getParameters(keys);
+
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
+}
+
+unsigned int AudioStreamInDump::getInputFramesLost() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->getInputFramesLost();
+ return 0;
+}
+
+status_t AudioStreamInDump::dump(int fd, const Vector<String16>& args)
+{
+ if (mFinalStream != 0 ) return mFinalStream->dump(fd, args);
+ return NO_ERROR;
+}
+
+void AudioStreamInDump::Close()
+{
+ if(mFile) {
+ fclose(mFile);
+ mFile = 0;
+ }
+}
+}; // namespace android
diff --git a/legacy_hal/AudioDumpInterface.h b/legacy_hal/AudioDumpInterface.h
new file mode 100755
index 0000000..814ce5f
--- /dev/null
+++ b/legacy_hal/AudioDumpInterface.h
@@ -0,0 +1,170 @@
+/* //device/servers/AudioFlinger/AudioDumpInterface.h
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_AUDIO_DUMP_INTERFACE_H
+#define ANDROID_AUDIO_DUMP_INTERFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/String8.h>
+#include <utils/SortedVector.h>
+
+#include <hardware_legacy/AudioHardwareBase.h>
+
+namespace android {
+
+#define AUDIO_DUMP_WAVE_HDR_SIZE 44
+
+class AudioDumpInterface;
+
+class AudioStreamOutDump : public AudioStreamOut {
+public:
+ AudioStreamOutDump(AudioDumpInterface *interface,
+ int id,
+ AudioStreamOut* finalStream,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t sampleRate);
+ ~AudioStreamOutDump();
+
+ virtual ssize_t write(const void* buffer, size_t bytes);
+ virtual uint32_t sampleRate() const;
+ virtual size_t bufferSize() const;
+ virtual uint32_t channels() const;
+ virtual int format() const;
+ virtual uint32_t latency() const;
+ virtual status_t setVolume(float left, float right);
+ virtual status_t standby();
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ void Close(void);
+ AudioStreamOut* finalStream() { return mFinalStream; }
+ uint32_t device() { return mDevice; }
+ int getId() { return mId; }
+ virtual status_t getRenderPosition(uint32_t *dspFrames);
+
+private:
+ AudioDumpInterface *mInterface;
+ int mId;
+ uint32_t mSampleRate; //
+ uint32_t mFormat; //
+ uint32_t mChannels; // output configuration
+ uint32_t mLatency; //
+ uint32_t mDevice; // current device this output is routed to
+ size_t mBufferSize;
+ AudioStreamOut *mFinalStream;
+ FILE *mFile; // output file
+ int mFileCount;
+};
+
+class AudioStreamInDump : public AudioStreamIn {
+public:
+ AudioStreamInDump(AudioDumpInterface *interface,
+ int id,
+ AudioStreamIn* finalStream,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t sampleRate);
+ ~AudioStreamInDump();
+
+ virtual uint32_t sampleRate() const;
+ virtual size_t bufferSize() const;
+ virtual uint32_t channels() const;
+ virtual int format() const;
+
+ virtual status_t setGain(float gain);
+ virtual ssize_t read(void* buffer, ssize_t bytes);
+ virtual status_t standby();
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ virtual unsigned int getInputFramesLost() const;
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ void Close(void);
+ AudioStreamIn* finalStream() { return mFinalStream; }
+ uint32_t device() { return mDevice; }
+
+private:
+ AudioDumpInterface *mInterface;
+ int mId;
+ uint32_t mSampleRate; //
+ uint32_t mFormat; //
+ uint32_t mChannels; // output configuration
+ uint32_t mDevice; // current device this output is routed to
+ size_t mBufferSize;
+ AudioStreamIn *mFinalStream;
+ FILE *mFile; // output file
+ int mFileCount;
+};
+
+class AudioDumpInterface : public AudioHardwareBase
+{
+
+public:
+ AudioDumpInterface(AudioHardwareInterface* hw);
+ virtual AudioStreamOut* openOutputStream(
+ uint32_t devices,
+ int *format=0,
+ uint32_t *channels=0,
+ uint32_t *sampleRate=0,
+ status_t *status=0);
+ virtual void closeOutputStream(AudioStreamOut* out);
+
+ virtual ~AudioDumpInterface();
+
+ virtual status_t initCheck()
+ {return mFinalInterface->initCheck();}
+ virtual status_t setVoiceVolume(float volume)
+ {return mFinalInterface->setVoiceVolume(volume);}
+ virtual status_t setMasterVolume(float volume)
+ {return mFinalInterface->setMasterVolume(volume);}
+
+ virtual status_t setMode(int mode);
+
+ // mic mute
+ virtual status_t setMicMute(bool state)
+ {return mFinalInterface->setMicMute(state);}
+ virtual status_t getMicMute(bool* state)
+ {return mFinalInterface->getMicMute(state);}
+
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+
+ virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
+
+ virtual AudioStreamIn* openInputStream(uint32_t devices, int *format, uint32_t *channels,
+ uint32_t *sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics);
+ virtual void closeInputStream(AudioStreamIn* in);
+
+ virtual status_t dump(int fd, const Vector<String16>& args) { return mFinalInterface->dumpState(fd, args); }
+
+ String8 fileName() const { return mFileName; }
+protected:
+
+ AudioHardwareInterface *mFinalInterface;
+ SortedVector<AudioStreamOutDump *> mOutputs;
+ SortedVector<AudioStreamInDump *> mInputs;
+ Mutex mLock;
+ String8 mPolicyCommands;
+ String8 mFileName;
+};
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_DUMP_INTERFACE_H
diff --git a/legacy_hal/AudioHardware.cpp b/legacy_hal/AudioHardware.cpp
new file mode 100755
index 0000000..6b8f95c
--- /dev/null
+++ b/legacy_hal/AudioHardware.cpp
@@ -0,0 +1,2132 @@
+/*
+** Copyright 2010, The Android Open-Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+//#define LOG_NDEBUG 0
+
+#define LOG_TAG "AudioHardware"
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+
+#include "AudioHardware.h"
+#include <media/AudioRecord.h>
+#include <hardware_legacy/power.h>
+
+#include <cutils/properties.h>
+
+#include "AudioUsbAudioHardware.h"
+
+extern "C" {
+#include "alsa_audio.h"
+}
+
+//when you want write the output data ,you can open this maroc.
+//#define DEBUG_ALSA_OUT
+//#define DEBUG_ALSA_IN
+#ifdef TARGET_RK2928
+#define AMP_ENABLE_TIME 230//TARGET_RK2928 codec use amplifier enable time (Unit:ms)
+#endif
+namespace android_audio_legacy {
+
+const uint32_t AudioHardware::inputSamplingRates[] = {
+ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+// trace driver operations for dump
+//
+#define DRIVER_TRACE
+
+enum {
+ DRV_NONE,
+ DRV_PCM_OPEN,
+ DRV_PCM_CLOSE,
+ DRV_PCM_WRITE,
+ DRV_PCM_READ,
+ DRV_MIXER_OPEN,
+ DRV_MIXER_CLOSE,
+ DRV_MIXER_GET,
+ DRV_MIXER_SEL
+};
+
+#ifdef DRIVER_TRACE
+#define TRACE_DRIVER_IN(op) mDriverOp = op;
+#define TRACE_DRIVER_OUT mDriverOp = DRV_NONE;
+#else
+#define TRACE_DRIVER_IN(op)
+#define TRACE_DRIVER_OUT
+#endif
+
+// ----------------------------------------------------------------------------
+
+AudioHardware::AudioHardware() :
+ mInit(false),
+ mMicMute(false),
+ mPcm(NULL),
+ mPcmOpenCnt(0),
+ mMixerOpenCnt(0),
+ mInCallAudioMode(false),
+ mVoipAudioMode(false),
+ mInputSource("Default"),
+ mBluetoothNrec(true),
+ mSecRilLibHandle(NULL),
+ mRilClient(0),
+ mActivatedCP(false),
+ mDriverOp(DRV_NONE)
+{
+ char pname[40];
+ snprintf(pname, sizeof(pname), AUDIO_HAL_VERSION_NAME);
+ property_set(pname, AUDIO_HAL_VERSION);
+
+ loadRILD();
+ mInit = true;
+
+ TRACE_DRIVER_IN(DRV_MIXER_OPEN)
+ route_init();
+ TRACE_DRIVER_OUT
+}
+
+AudioHardware::~AudioHardware()
+{
+ for (size_t index = 0; index < mInputs.size(); index++) {
+ closeInputStream(mInputs[index].get());
+ }
+ mInputs.clear();
+ closeOutputStream((android_audio_legacy::AudioStreamOut*)mOutput.get());
+
+ if (mPcm) {
+ TRACE_DRIVER_IN(DRV_PCM_CLOSE)
+ route_pcm_close(PLAYBACK_OFF_ROUTE);
+ TRACE_DRIVER_OUT
+ }
+
+ TRACE_DRIVER_IN(DRV_MIXER_CLOSE)
+ route_uninit();
+ TRACE_DRIVER_OUT
+
+ mInit = false;
+}
+
+status_t AudioHardware::initCheck()
+{
+ return mInit ? NO_ERROR : NO_INIT;
+}
+
+void AudioHardware::loadRILD(void)
+{
+ /*mSecRilLibHandle = dlopen("libsecril-client.so", RTLD_NOW);
+
+ if (mSecRilLibHandle) {
+ ALOGV("libsecril-client.so is loaded");
+
+ openClientRILD = (HRilClient (*)(void))
+ dlsym(mSecRilLibHandle, "OpenClient_RILD");
+ disconnectRILD = (int (*)(HRilClient))
+ dlsym(mSecRilLibHandle, "Disconnect_RILD");
+ closeClientRILD = (int (*)(HRilClient))
+ dlsym(mSecRilLibHandle, "CloseClient_RILD");
+ isConnectedRILD = (int (*)(HRilClient))
+ dlsym(mSecRilLibHandle, "isConnected_RILD");
+ connectRILD = (int (*)(HRilClient))
+ dlsym(mSecRilLibHandle, "Connect_RILD");
+ setCallVolume = (int (*)(HRilClient, SoundType, int))
+ dlsym(mSecRilLibHandle, "SetCallVolume");
+ setCallAudioPath = (int (*)(HRilClient, AudioPath))
+ dlsym(mSecRilLibHandle, "SetCallAudioPath");
+ setCallClockSync = (int (*)(HRilClient, SoundClockCondition))
+ dlsym(mSecRilLibHandle, "SetCallClockSync");
+
+ if (!openClientRILD || !disconnectRILD || !closeClientRILD ||
+ !isConnectedRILD || !connectRILD ||
+ !setCallVolume || !setCallAudioPath || !setCallClockSync) {
+ ALOGE("Can't load all functions from libsecril-client.so");
+
+ dlclose(mSecRilLibHandle);
+ mSecRilLibHandle = NULL;
+ } else {
+ mRilClient = openClientRILD();
+ if (!mRilClient) {
+ ALOGE("OpenClient_RILD() error");
+
+ dlclose(mSecRilLibHandle);
+ mSecRilLibHandle = NULL;
+ }
+ }
+ } else {
+ ALOGE("Can't load libsecril-client.so");
+ }*/
+}
+
+status_t AudioHardware::connectRILDIfRequired(void)
+{
+ if (!mSecRilLibHandle) {
+ ALOGE("connectIfRequired() lib is not loaded");
+ return INVALID_OPERATION;
+ }
+
+ if (isConnectedRILD(mRilClient)) {
+ return OK;
+ }
+
+ if (connectRILD(mRilClient) != RIL_CLIENT_ERR_SUCCESS) {
+ ALOGE("Connect_RILD() error");
+ return INVALID_OPERATION;
+ }
+
+ return OK;
+}
+
+android_audio_legacy::AudioStreamOut* AudioHardware::openOutputStream(
+ uint32_t devices, int *format, uint32_t *channels,
+ uint32_t *sampleRate, status_t *status)
+{
+ android::sp <AudioStreamOutALSA> out;
+ status_t rc;
+
+ { // scope for the lock
+ android::Mutex::Autolock lock(mLock);
+
+ // only one output stream allowed
+ if (mOutput != 0) {
+ if (status) {
+ *status = INVALID_OPERATION;
+ }
+ return NULL;
+ }
+
+ out = new AudioStreamOutALSA();
+
+ rc = out->set(this, devices, format, channels, sampleRate);
+ if (rc == NO_ERROR) {
+ mOutput = out;
+ }
+ }
+
+ if (rc != NO_ERROR) {
+ if (out != 0) {
+ out.clear();
+ }
+ }
+ if (status) {
+ *status = rc;
+ }
+
+ return out.get();
+}
+
+
+// default implementation calls its "without flags" counterpart
+android_audio_legacy::AudioStreamOut* AudioHardware::openOutputStreamWithFlags(uint32_t devices,
+ audio_output_flags_t flags,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
+ status_t *status)
+{
+ return openOutputStream(devices, format, channels, sampleRate, status);
+}
+
+status_t AudioHardware::setMasterMute(bool muted){
+ return INVALID_OPERATION;
+}
+
+
+int AudioHardware::createAudioPatch(unsigned int num_sources,
+ const struct audio_port_config *sources,
+ unsigned int num_sinks,
+ const struct audio_port_config *sinks,
+ audio_patch_handle_t *handle){
+ return 0;
+}
+
+int AudioHardware::releaseAudioPatch(audio_patch_handle_t handle){
+ return 0;
+}
+
+int AudioHardware::getAudioPort(struct audio_port *port) {
+ return 0;
+}
+
+int AudioHardware::setAudioPortConfig(const struct audio_port_config *config) {
+ return 0;
+}
+
+void AudioHardware::closeOutputStream(android_audio_legacy::AudioStreamOut* out) {
+ android::sp <AudioStreamOutALSA> spOut;
+ {
+ android::Mutex::Autolock lock(mLock);
+ if (mOutput == 0 || mOutput.get() != out) {
+ ALOGW("Attempt to close invalid output stream");
+ return;
+ }
+ spOut = mOutput;
+ mOutput.clear();
+ }
+ spOut.clear();
+}
+
+android_audio_legacy::AudioStreamIn* AudioHardware::openInputStream(
+ uint32_t devices, int *format, uint32_t *channels,
+ uint32_t *sampleRate, status_t *status,
+ android_audio_legacy::AudioSystem::audio_in_acoustics acoustic_flags)
+{
+ // check for valid input source
+ if (!android_audio_legacy::AudioSystem::isInputDevice((android_audio_legacy::AudioSystem::audio_devices)devices)) {
+ if (status) {
+ *status = BAD_VALUE;
+ }
+ return NULL;
+ }
+
+ status_t rc = NO_ERROR;
+ android::sp <AudioStreamInALSA> in;
+
+ { // scope for the lock
+ android::Mutex::Autolock lock(mLock);
+
+ in = new AudioStreamInALSA();
+ rc = in->set(this, devices, format, channels, sampleRate, acoustic_flags);
+ if (rc == NO_ERROR) {
+ mInputs.add(in);
+ }
+ }
+
+ if (rc != NO_ERROR) {
+ if (in != 0) {
+ in.clear();
+ }
+ }
+ if (status) {
+ *status = rc;
+ }
+
+ ALOGV("AudioHardware::openInputStream()%p", in.get());
+ return in.get();
+}
+
+void AudioHardware::closeInputStream(AudioStreamIn* in) {
+
+ android::sp<AudioStreamInALSA> spIn;
+ {
+ android::Mutex::Autolock lock(mLock);
+
+ ssize_t index = mInputs.indexOf((AudioStreamInALSA *)in);
+ if (index < 0) {
+ ALOGW("Attempt to close invalid input stream");
+ return;
+ }
+ spIn = mInputs[index];
+ mInputs.removeAt(index);
+ }
+ ALOGV("AudioHardware::closeInputStream()%p", in);
+ spIn.clear();
+}
+
+
+status_t AudioHardware::setMode(int mode)
+{
+ android::sp<AudioStreamOutALSA> spOut;
+ android::sp<AudioStreamInALSA> spIn;
+ status_t status;
+
+ // bump thread priority to speed up mutex acquisition
+ int priority = getpriority(PRIO_PROCESS, 0);
+ setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_URGENT_AUDIO);
+
+ // Mutex acquisition order is always out -> in -> hw
+ android::AutoMutex lock(mLock);
+
+ spOut = mOutput;
+ while (spOut != 0) {
+ if (!spOut->checkStandby()) {
+ int cnt = spOut->standbyCnt();
+ mLock.unlock();
+ spOut->lock();
+ mLock.lock();
+ // make sure that another thread did not change output state while the
+ // mutex is released
+ if ((spOut == mOutput) && (cnt == spOut->standbyCnt())) {
+ break;
+ }
+ spOut->unlock();
+ spOut = mOutput;
+ } else {
+ spOut.clear();
+ }
+ }
+
+ spIn = getActiveInput_l();
+ while (spIn != 0) {
+ int cnt = spIn->standbyCnt();
+ mLock.unlock();
+ spIn->lock();
+ mLock.lock();
+ // make sure that another thread did not change input state while the
+ // mutex is released
+ if ((spIn == getActiveInput_l()) && (cnt == spIn->standbyCnt())) {
+ break;
+ }
+ spIn->unlock();
+ spIn = getActiveInput_l();
+ }
+
+ setpriority(PRIO_PROCESS, 0, priority);
+
+ int prevMode = mMode;
+ status = AudioHardwareBase::setMode(mode);
+ ALOGV("setMode() : new %d, old %d", mMode, prevMode);
+ if (status == NO_ERROR) {
+ // activate call clock in radio when entering in call or ringtone mode
+ if (prevMode == AudioSystem::MODE_NORMAL)
+ {
+ if ((!mActivatedCP) && (mSecRilLibHandle) && (connectRILDIfRequired() == OK)) {
+ setCallClockSync(mRilClient, SOUND_CLOCK_START);
+ mActivatedCP = true;
+ }
+ }
+
+ //close voip before incall opening
+ if ((mMode != AudioSystem::MODE_IN_COMMUNICATION)
+ && mVoipAudioMode) {
+ setInputSource_l(mInputSource);
+ TRACE_DRIVER_IN(DRV_MIXER_SEL)
+ route_set_controls(VOIP_OFF_ROUTE);//close voip
+ TRACE_DRIVER_OUT
+
+ mVoipAudioMode = false;
+ }
+
+ if (mMode == AudioSystem::MODE_IN_CALL && !mInCallAudioMode) {
+ //sleep latency time to finish music
+ if (mOutput != 0) {
+ mLock.unlock();
+ usleep((mOutput->latency() + 70) * 1000);
+ mLock.lock();
+ }
+
+ ALOGV("setMode() openPcmOut_l()");
+ openPcmOut_l();
+ setInputSource_l(String8("Default"));
+ if (mOutput != 0 && AudioSystem::popCount(mOutput->device()) == 1)
+ setIncallPath_l(mOutput->device());
+ mInCallAudioMode = true;
+ }
+
+ if (mMode != AudioSystem::MODE_IN_CALL && mInCallAudioMode) {
+ setInputSource_l(mInputSource);
+
+ TRACE_DRIVER_IN(DRV_MIXER_SEL)
+ route_pcm_close(INCALL_OFF_ROUTE);//close incall
+ TRACE_DRIVER_OUT
+
+ ALOGV("setMode() closePcmOut_l()");
+ closePcmOut_l();
+
+ mInCallAudioMode = false;
+ }
+
+ if (mMode == AudioSystem::MODE_IN_COMMUNICATION && !mVoipAudioMode) {
+ setInputSource_l(String8("Default"));
+ if (mOutput != 0) {
+ mOutput->doStandby_l();
+ }
+ mVoipAudioMode = true;
+ }
+
+ if (mMode == AudioSystem::MODE_NORMAL) {
+ if(mActivatedCP)
+ mActivatedCP = false;
+ }
+ }
+
+ if (spIn != 0) {
+ spIn->unlock();
+ }
+ if (spOut != 0) {
+ spOut->unlock();
+ }
+
+ return status;
+}
+
+status_t AudioHardware::setMicMute(bool state)
+{
+ ALOGV("setMicMute(%d) mMicMute %d", state, mMicMute);
+ android::sp<AudioStreamInALSA> spIn;
+ {
+ android::AutoMutex lock(mLock);
+ if (mMicMute != state) {
+ mMicMute = state;
+ // in call mute is handled by RIL
+ if (mMode != AudioSystem::MODE_IN_CALL) {
+ spIn = getActiveInput_l();
+ }
+ }
+ }
+
+ if (spIn != 0) {
+ spIn->setGain(mMicMute?0.0:1.0);
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioHardware::getMicMute(bool* state)
+{
+ *state = mMicMute;
+ return NO_ERROR;
+}
+
+status_t AudioHardware::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 value;
+ String8 key;
+ const char BT_NREC_KEY[] = "bt_headset_nrec";
+ const char BT_NREC_VALUE_ON[] = "on";
+
+ key = String8(BT_NREC_KEY);
+ if (param.get(key, value) == NO_ERROR) {
+ if (value == BT_NREC_VALUE_ON) {
+ mBluetoothNrec = true;
+ } else {
+ mBluetoothNrec = false;
+ ALOGD("Turning noise reduction and echo cancellation off for BT "
+ "headset");
+ }
+ }
+
+ return NO_ERROR;
+}
+
+String8 AudioHardware::getParameters(const String8& keys)
+{
+ AudioParameter request = AudioParameter(keys);
+ AudioParameter reply = AudioParameter();
+
+ ALOGV("getParameters() %s", keys.string());
+
+ return reply.toString();
+}
+
+size_t AudioHardware::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+ if (format != AudioSystem::PCM_16_BIT) {
+ ALOGW("getInputBufferSize bad format: %d", format);
+ return 0;
+ }
+ if (channelCount < 1 || channelCount > 2) {
+ ALOGW("getInputBufferSize bad channel count: %d", channelCount);
+ return 0;
+ }
+ if (sampleRate != 8000 && sampleRate != 11025 && sampleRate != 16000 &&
+ sampleRate != 22050 && sampleRate != 44100 && sampleRate != 48000) {
+ ALOGW("getInputBufferSize bad sample rate: %d", sampleRate);
+ return 0;
+ }
+
+ return AudioStreamInALSA::getBufferSize(sampleRate, channelCount);
+}
+
+
+status_t AudioHardware::setVoiceVolume(float volume)
+{
+ ALOGV("setVoiceVolume() volume %f", volume);
+
+ android::AutoMutex lock(mLock);
+ if (AudioSystem::MODE_IN_CALL == mMode) {
+
+ uint32_t device = AudioSystem::DEVICE_OUT_EARPIECE;
+ char ctlName[44] = "";
+ if (mOutput != 0) {
+ device = mOutput->device();
+ }
+
+ ALOGV("setVoiceVolume() route(%d)", device);
+ switch (device) {
+ case AudioSystem::DEVICE_OUT_EARPIECE:
+ ALOGV("earpiece call volume");
+ strcpy(ctlName, "Earpiece Playback Volume");
+ break;
+
+ case AudioSystem::DEVICE_OUT_SPEAKER:
+ ALOGV("speaker call volume");
+ strcpy(ctlName, "Speaker Playback Volume");
+ break;
+
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO:
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+ ALOGV("bluetooth call volume");
+ break;
+
+ case AudioSystem::DEVICE_OUT_WIRED_HEADSET:
+ case AudioSystem::DEVICE_OUT_WIRED_HEADPHONE: // Use receive path with 3 pole headset.
+ ALOGV("headset call volume");
+ strcpy(ctlName, "Headphone Playback Volume");
+ break;
+
+ default:
+ ALOGW("Call volume setting error!!!0x%08x \n", device);
+ strcpy(ctlName, "Earpiece Playback Volume");
+ break;
+ }
+ TRACE_DRIVER_IN(DRV_MIXER_SEL)
+ route_set_voice_volume(ctlName, volume);
+ TRACE_DRIVER_OUT
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioHardware::setMasterVolume(float volume)
+{
+ ALOGV("Set master volume to %f.\n", volume);
+ // We return an error code here to let the audioflinger do in-software
+ // volume on top of the maximum volume that we set through the SND API.
+ // return error - software mixer will handle it
+ return -1;
+}
+
+static const int kDumpLockRetries = 50;
+static const int kDumpLockSleep = 20000;
+
+static bool tryLock( android::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 AudioHardware::dump(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, "\n\tAudioHardware maybe deadlocked\n");
+ } else {
+ mLock.unlock();
+ }
+
+ snprintf(buffer, SIZE, "\tInit %s\n", (mInit) ? "OK" : "Failed");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tMic Mute %s\n", (mMicMute) ? "ON" : "OFF");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmPcm: %p\n", mPcm);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmPcmOpenCnt: %d\n", mPcmOpenCnt);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmMixerOpenCnt: %d\n", mMixerOpenCnt);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tIn Call Audio Mode %s\n",
+ (mInCallAudioMode) ? "ON" : "OFF");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tInput source %s\n", mInputSource.string());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmSecRilLibHandle: %p\n", mSecRilLibHandle);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmRilClient: %p\n", mRilClient);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tCP %s\n",
+ (mActivatedCP) ? "Activated" : "Deactivated");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmDriverOp: %d\n", mDriverOp);
+ result.append(buffer);
+
+ snprintf(buffer, SIZE, "\n\tmOutput %p dump:\n", mOutput.get());
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ if (mOutput != 0) {
+ mOutput->dump(fd, args);
+ }
+
+ snprintf(buffer, SIZE, "\n\t%d inputs opened:\n", mInputs.size());
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ snprintf(buffer, SIZE, "\t- input %d dump:\n", i);
+ write(fd, buffer, strlen(buffer));
+ mInputs[i]->dump(fd, args);
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioHardware::setIncallPath_l(uint32_t device)
+{
+ ALOGV("setIncallPath_l: device %x", device);
+
+ if (mMode == AudioSystem::MODE_IN_CALL) {
+ TRACE_DRIVER_IN(DRV_PCM_OPEN)
+ if (!mPcm)
+ openPcmOut_l();
+ else
+ mPcm = route_pcm_open(getRouteFromDevice(device), mPcm->flags);
+ TRACE_DRIVER_OUT
+ }
+
+ return NO_ERROR;
+}
+
+struct pcm *AudioHardware::openPcmOut_l()
+{
+ ALOGD("openPcmOut_l() mPcmOpenCnt: %d", mPcmOpenCnt);
+ if (mPcmOpenCnt++ == 0) {
+ if (mPcm != NULL) {
+ ALOGE("openPcmOut_l() mPcmOpenCnt == 0 and mPcm == %p\n", mPcm);
+ mPcmOpenCnt--;
+ return NULL;
+ }
+ unsigned flags = PCM_OUT;
+
+ flags |= (AUDIO_HW_OUT_PERIOD_MULT - 1) << PCM_PERIOD_SZ_SHIFT;
+ flags |= (AUDIO_HW_OUT_PERIOD_CNT - PCM_PERIOD_CNT_MIN) << PCM_PERIOD_CNT_SHIFT;
+
+ if (mOutput->sampleRate() == 48000) {
+ flags |= PCM_48000HZ;
+ }
+
+ TRACE_DRIVER_IN(DRV_PCM_OPEN)
+ mPcm = route_pcm_open(getRouteFromDevice(mOutput->device()), flags);
+ TRACE_DRIVER_OUT
+ if (!pcm_ready(mPcm)) {
+ ALOGE("openPcmOut_l() cannot open pcm_out driver: %s\n", pcm_error(mPcm));
+ TRACE_DRIVER_IN(DRV_PCM_CLOSE)
+ route_pcm_close(PLAYBACK_OFF_ROUTE);
+ TRACE_DRIVER_OUT
+ mPcmOpenCnt--;
+ mPcm = NULL;
+ }
+ }
+ return mPcm;
+}
+
+void AudioHardware::closePcmOut_l()
+{
+ ALOGD("closePcmOut_l() mPcmOpenCnt: %d", mPcmOpenCnt);
+ if (mPcmOpenCnt == 0) {
+ ALOGE("closePcmOut_l() mPcmOpenCnt == 0");
+ return;
+ }
+
+ if (--mPcmOpenCnt == 0) {
+ ALOGV("close_l() reset Playback Path to OFF");
+ TRACE_DRIVER_IN(DRV_PCM_CLOSE)
+ route_pcm_close(PLAYBACK_OFF_ROUTE);
+ TRACE_DRIVER_OUT
+ mPcm = NULL;
+ }
+}
+
+unsigned AudioHardware::getOutputRouteFromDevice(uint32_t device)
+{
+ if (mMode != AudioSystem::MODE_RINGTONE && mMode != AudioSystem::MODE_NORMAL)
+ return PLAYBACK_OFF_ROUTE;
+
+ switch (device) {
+ case AudioSystem::DEVICE_OUT_EARPIECE:
+ return EARPIECE_NORMAL_ROUTE;
+ case AudioSystem::DEVICE_OUT_SPEAKER:
+ if (mMode == AudioSystem::MODE_RINGTONE) return SPEAKER_RINGTONE_ROUTE;
+ else return SPEAKER_NORMAL_ROUTE;
+ case AudioSystem::DEVICE_OUT_WIRED_HEADPHONE:
+ if (mMode == AudioSystem::MODE_RINGTONE) return HEADPHONE_RINGTONE_ROUTE;
+ else return HEADPHONE_NORMAL_ROUTE;
+ case AudioSystem::DEVICE_OUT_WIRED_HEADSET:
+ if (mMode == AudioSystem::MODE_RINGTONE) return HEADSET_RINGTONE_ROUTE;
+ else return HEADSET_NORMAL_ROUTE;
+ case (AudioSystem::DEVICE_OUT_SPEAKER|AudioSystem::DEVICE_OUT_WIRED_HEADPHONE):
+ case (AudioSystem::DEVICE_OUT_SPEAKER|AudioSystem::DEVICE_OUT_WIRED_HEADSET):
+ if (mMode == AudioSystem::MODE_RINGTONE) return SPEAKER_HEADPHONE_RINGTONE_ROUTE;
+ else return SPEAKER_HEADPHONE_NORMAL_ROUTE;
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO:
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+ return BLUETOOTH_NORMAL_ROUTE;
+ case AudioSystem::DEVICE_OUT_AUX_DIGITAL:
+ return HDMI_NORMAL_ROUTE;
+ case AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET:
+ case AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET:
+ return USB_NORMAL_ROUTE;
+ default:
+ return PLAYBACK_OFF_ROUTE;
+ }
+}
+
+unsigned AudioHardware::getVoiceRouteFromDevice(uint32_t device)
+{
+ if (mMode != AudioSystem::MODE_IN_CALL && mMode != AudioSystem::MODE_IN_COMMUNICATION)
+ return INCALL_OFF_ROUTE;
+
+ if (device & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO ||
+ device & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET ||
+ device & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT) {
+ if (mMode == AudioSystem::MODE_IN_CALL) return BLUETOOTH_INCALL_ROUTE;
+ else return BLUETOOTH_VOIP_ROUTE;
+ } else if (device & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) {
+ if (mMode == AudioSystem::MODE_IN_CALL) return HEADPHONE_INCALL_ROUTE;
+ else return HEADPHONE_VOIP_ROUTE;
+ } else if (device & AudioSystem::DEVICE_OUT_WIRED_HEADSET) {
+ if (mMode == AudioSystem::MODE_IN_CALL) return HEADSET_INCALL_ROUTE;
+ else return HEADSET_VOIP_ROUTE;
+ } else if (device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET ||
+ device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET) {
+ if (mMode == AudioSystem::MODE_IN_CALL) return EARPIECE_INCALL_ROUTE;
+ else return USB_NORMAL_ROUTE;
+ } else if (device & AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
+ if (mMode == AudioSystem::MODE_IN_CALL) return EARPIECE_INCALL_ROUTE;
+ else return HDMI_NORMAL_ROUTE;
+ } else if (device & AudioSystem::DEVICE_OUT_EARPIECE) {
+ if (mMode == AudioSystem::MODE_IN_CALL) return EARPIECE_INCALL_ROUTE;
+ else return EARPIECE_VOIP_ROUTE;
+ } else if (device & AudioSystem::DEVICE_OUT_SPEAKER) {
+ if (mMode == AudioSystem::MODE_IN_CALL) return SPEAKER_INCALL_ROUTE;
+ else return SPEAKER_VOIP_ROUTE;
+ } else {
+ if (mMode == AudioSystem::MODE_IN_CALL) return INCALL_OFF_ROUTE;
+ else return VOIP_OFF_ROUTE;
+ }
+}
+
+unsigned AudioHardware::getInputRouteFromDevice(uint32_t device)
+{
+ if (mMicMute) {
+ return CAPTURE_OFF_ROUTE;
+ }
+
+ switch (device) {
+ case AudioSystem::DEVICE_IN_BUILTIN_MIC:
+ return MAIN_MIC_CAPTURE_ROUTE;
+ case AudioSystem::DEVICE_IN_WIRED_HEADSET:
+ return HANDS_FREE_MIC_CAPTURE_ROUTE;
+ case AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET:
+ return BLUETOOTH_SOC_MIC_CAPTURE_ROUTE;
+ case AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET:
+ return USB_CAPTURE_ROUTE;
+ default:
+ return CAPTURE_OFF_ROUTE;
+ }
+}
+
+unsigned AudioHardware::getRouteFromDevice(uint32_t device)
+{
+ if (device & AudioSystem::DEVICE_IN_ALL)
+ return getInputRouteFromDevice(device);
+
+ switch (mMode) {
+ case AudioSystem::MODE_IN_CALL:
+ case AudioSystem::MODE_IN_COMMUNICATION:
+ return getVoiceRouteFromDevice(device);
+ default:
+ return getOutputRouteFromDevice(device);
+ }
+}
+
+uint32_t AudioHardware::getInputSampleRate(uint32_t sampleRate)
+{
+ uint32_t i;
+ uint32_t prevDelta;
+ uint32_t delta;
+
+ for (i = 0, prevDelta = 0xFFFFFFFF; i < sizeof(inputSamplingRates)/sizeof(uint32_t); i++, prevDelta = delta) {
+ delta = abs(sampleRate - inputSamplingRates[i]);
+ if (delta > prevDelta) break;
+ }
+ // i is always > 0 here
+ return inputSamplingRates[i-1];
+}
+
+// getActiveInput_l() must be called with mLock held
+ android::sp <AudioHardware::AudioStreamInALSA> AudioHardware::getActiveInput_l()
+{
+ android::sp< AudioHardware::AudioStreamInALSA> spIn;
+
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ // return first input found not being in standby mode
+ // as only one input can be in this state
+ if (!mInputs[i]->checkStandby()) {
+ spIn = mInputs[i];
+ break;
+ }
+ }
+
+ return spIn;
+}
+
+status_t AudioHardware::setInputSource_l(String8 source)
+{
+ ALOGV("setInputSource_l(%s)", source.string());
+ if (source != mInputSource) {
+ if ((source == "Default") || (mMode != AudioSystem::MODE_IN_CALL)) {
+ ALOGV("mixer_ctl_select, Input Source, (%s)", source.string());
+ TRACE_DRIVER_IN(DRV_MIXER_SEL)
+ route_set_input_source(source.string());
+ TRACE_DRIVER_OUT
+ }
+ mInputSource = source;
+ }
+
+ return NO_ERROR;
+}
+
+
+//------------------------------------------------------------------------------
+// AudioStreamOutALSA
+//------------------------------------------------------------------------------
+#ifdef DEBUG_ALSA_OUT
+static FILE * alsa_out_fp = NULL;
+#endif
+
+AudioHardware::AudioStreamOutALSA::AudioStreamOutALSA() :
+ mHardware(0), mRouteCtl(0),
+ mStandby(true), mDevices(0), mChannels(AUDIO_HW_OUT_CHANNELS),
+ mSampleRate(AUDIO_HW_OUT_SAMPLERATE), mBufferSize(AUDIO_HW_OUT_PERIOD_BYTES),
+ mDriverOp(DRV_NONE), mStandbyCnt(0)
+{
+#ifdef DEBUG_ALSA_OUT
+ if(alsa_out_fp== NULL)
+ alsa_out_fp = fopen("/data/data/out.pcm","a+");
+ if(alsa_out_fp)
+ ALOGI("------------>openfile success");
+#endif
+}
+
+status_t AudioHardware::AudioStreamOutALSA::set(
+ AudioHardware* hw, 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;
+
+ mHardware = hw;
+ mDevices = devices;
+
+ // fix up defaults
+ if (lFormat == 0) lFormat = format();
+ if (lChannels == 0) lChannels = channels();
+ if (lRate == 0) lRate = sampleRate();
+
+ if (devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET ||
+ devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET) {
+ uint32_t usbChannels = (lChannels == AudioSystem::CHANNEL_OUT_MONO) ? 1 : 2;
+ mSampleRate = get_USBAudio_sampleRate(UA_Playback_type, lRate);
+ mChannels = (get_USBAudio_Channels(UA_Playback_type, usbChannels) == 1) ?
+ AudioSystem::CHANNEL_OUT_MONO : AudioSystem::CHANNEL_OUT_STEREO;
+ }
+
+ if (pFormat) *pFormat = format();
+ if (pChannels) *pChannels = channels();
+ if (pRate) *pRate = sampleRate();
+
+ mBufferSize = AUDIO_HW_OUT_PERIOD_BYTES;
+
+ return NO_ERROR;
+}
+
+AudioHardware::AudioStreamOutALSA::~AudioStreamOutALSA()
+{
+ standby();
+#ifdef DEBUG_ALSA_OUT
+ if(alsa_out_fp)
+ fclose(alsa_out_fp);
+#endif
+}
+
+
+ssize_t AudioHardware::AudioStreamOutALSA::write(const void* buffer, size_t bytes)
+{
+ // ALOGV("AudioStreamOutALSA::write(%p, %u)", buffer, bytes);
+ status_t status = NO_INIT;
+ const uint8_t* p = static_cast<const uint8_t*>(buffer);
+ int ret;
+
+#ifdef DEBUG_ALSA_OUT
+ if(alsa_out_fp)
+ fwrite(buffer,1,bytes,alsa_out_fp);
+#endif
+
+ if (mHardware == NULL) return NO_INIT;
+
+ { // scope for the lock
+
+ android::AutoMutex lock(mLock);
+
+ if (mStandby) {
+ android::AutoMutex hwLock(mHardware->lock());
+
+ ALOGD("AudioHardware pcm playback is exiting standby.");
+ acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioOutLock");
+
+ /* android::sp<AudioStreamInALSA> spIn = mHardware->getActiveInput_l();
+ while (spIn != 0) {
+ int cnt = spIn->standbyCnt();
+ mHardware->lock().unlock();
+ // Mutex acquisition order is always out -> in -> hw
+ spIn->lock();
+ mHardware->lock().lock();
+ // make sure that another thread did not change input state
+ // while the mutex is released
+ if ((spIn == mHardware->getActiveInput_l()) &&
+ (cnt == spIn->standbyCnt())) {
+ ALOGV("AudioStreamOutALSA::write() force input standby");
+ spIn->close_l();
+ break;
+ }
+ spIn->unlock();
+ spIn = mHardware->getActiveInput_l();
+ }*/
+ // spIn is not 0 here only if the input was active and has been
+ // closed above
+
+ // open output before input
+ open_l();
+
+ /* if (spIn != 0) {
+ if (spIn->open_l() != NO_ERROR) {
+ spIn->doStandby_l();
+ }
+ spIn->unlock();
+ }*/
+ if (mHardware->getPcm() == NULL) {
+ release_wake_lock("AudioOutLock");
+ goto Error;
+ }
+ mStandby = false;
+#ifdef TARGET_RK2928
+ usleep(AMP_ENABLE_TIME*1000);
+#endif
+ }
+
+ TRACE_DRIVER_IN(DRV_PCM_WRITE)
+ ret = pcm_write(mHardware->getPcm(),(void*) p, bytes);
+ TRACE_DRIVER_OUT
+
+ if (ret == 0) {
+ return bytes;
+ }
+ ALOGW("write error: %d", errno);
+ status = -errno;
+ }
+Error:
+
+ standby();
+
+ // Simulate audio output timing in case of error
+ usleep((((bytes * 1000) / frameSize()) * 1000) / sampleRate());
+
+ return status;
+}
+
+status_t AudioHardware::AudioStreamOutALSA::standby()
+{
+ if (mHardware == NULL) return NO_INIT;
+
+ android::AutoMutex lock(mLock);
+
+ { // scope for the AudioHardware lock
+ android::AutoMutex hwLock(mHardware->lock());
+ if (mHardware->mode() != AudioSystem::MODE_IN_CALL)
+ doStandby_l();
+ }
+
+ return NO_ERROR;
+}
+
+void AudioHardware::AudioStreamOutALSA::doStandby_l()
+{
+ mStandbyCnt++;
+
+ if (!mStandby) {
+ ALOGD("AudioHardware pcm playback is going to standby.");
+ release_wake_lock("AudioOutLock");
+ mStandby = true;
+ }
+
+ close_l();
+}
+
+void AudioHardware::AudioStreamOutALSA::close_l()
+{
+ if (mHardware->getPcm()) {
+ mHardware->closePcmOut_l();
+ }
+}
+
+status_t AudioHardware::AudioStreamOutALSA::open_l()
+{
+ ALOGV("open pcm_out driver");
+ mHardware->openPcmOut_l();
+ if (mHardware->getPcm() == NULL) {
+ return NO_INIT;
+ }
+ return NO_ERROR;
+}
+
+status_t AudioHardware::AudioStreamOutALSA::dump(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, "\n\t\tAudioStreamOutALSA maybe deadlocked\n");
+ } else {
+ mLock.unlock();
+ }
+
+ snprintf(buffer, SIZE, "\t\tmHardware: %p\n", mHardware);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmRouteCtl: %p\n", mRouteCtl);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tStandby %s\n", (mStandby) ? "ON" : "OFF");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmDevices: 0x%08x\n", mDevices);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmChannels: 0x%08x\n", mChannels);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmSampleRate: %d\n", mSampleRate);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmBufferSize: %d\n", mBufferSize);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmDriverOp: %d\n", mDriverOp);
+ result.append(buffer);
+
+ ::write(fd, result.string(), result.size());
+
+ return NO_ERROR;
+}
+
+bool AudioHardware::AudioStreamOutALSA::checkStandby()
+{
+ return mStandby;
+}
+
+status_t AudioHardware::AudioStreamOutALSA::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ status_t status = NO_ERROR;
+ int value;
+ ALOGD("AudioStreamOutALSA::setParameters() %s", keyValuePairs.string());
+
+ if (mHardware == NULL) return NO_INIT;
+
+ {
+ bool needStandby = false;
+ android::AutoMutex lock(mLock);
+
+ if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR)
+ {
+ //for MID alsa ,not have a routing change.
+ android::AutoMutex hwLock(mHardware->lock());
+
+ if (mDevices != (uint32_t)value && value != AUDIO_DEVICE_NONE) {
+ mDevices = (uint32_t)value;
+ if (mHardware->mode() == AudioSystem::MODE_IN_CALL) {
+ mHardware->setIncallPath_l(mDevices);
+ } else
+ needStandby = true;
+ }
+
+ param.remove(String8(AudioParameter::keyRouting));
+ }
+
+ if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR)
+ {
+ if (mSampleRate != (uint32_t)value && value != 0 &&
+ (value == 48000 || value == 44100)) {
+ mSampleRate = (uint32_t)value;
+
+ android::AutoMutex hwLock(mHardware->lock());
+ if (mHardware->mode() != AudioSystem::MODE_IN_CALL) {
+ needStandby = true;
+ }
+ }
+ param.remove(String8(AudioParameter::keySamplingRate));
+ }
+
+ if (needStandby){
+ android::AutoMutex hwLock(mHardware->lock());
+ doStandby_l();
+ }
+ }
+
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+
+
+ return status;
+
+}
+
+String8 AudioHardware::AudioStreamOutALSA::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)mDevices);
+ }
+
+ if (param.get(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
+ param.addInt(String8(AudioParameter::keySamplingRate), (int)mSampleRate);
+ }
+
+ ALOGV("AudioStreamOutALSA::getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
+status_t AudioHardware::AudioStreamOutALSA::getRenderPosition(uint32_t *dspFrames)
+{
+ //TODO
+ return INVALID_OPERATION;
+}
+
+
+
+//------------------------------------------------------------------------------
+// AudioStreamInALSA
+//------------------------------------------------------------------------------
+
+#ifdef DEBUG_ALSA_IN
+static FILE * alsa_in_fp = NULL;
+#endif
+
+AudioHardware::AudioStreamInALSA::AudioStreamInALSA() :
+ mHardware(0), mPcm(0), mRouteCtl(0),
+ mStandby(true), mDevices(0), mChannels(AUDIO_HW_IN_CHANNELS), mChannelCount(1),
+ mSampleRate(AUDIO_HW_IN_SAMPLERATE), mReqSampleRate(AUDIO_HW_IN_SAMPLERATE),
+ mInSampleRate(AUDIO_HW_IN_SAMPLERATE), mBufferSize(AUDIO_HW_IN_PERIOD_BYTES),
+ mDownSampler(NULL), mReadStatus(NO_ERROR),mMicMute(false), mDriverOp(DRV_NONE),
+ mStandbyCnt(0), mDropCnt(0)
+{
+#ifdef DEBUG_ALSA_IN
+ alsa_in_fp = fopen("/data/data/in.pcm","wb");
+ if(alsa_in_fp)
+ ALOGI("alsa_streamin open /sdcard/in.pcm file success");
+#endif
+#if (SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE)
+ mSpeexState = NULL;
+ mSpeexFrameSize = 0;
+ mSpeexPcmIn = NULL;
+#endif//SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE
+
+}
+
+status_t AudioHardware::AudioStreamInALSA::set(
+ AudioHardware* hw, uint32_t devices, int *pFormat,
+ uint32_t *pChannels, uint32_t *pRate, AudioSystem::audio_in_acoustics acoustics)
+{
+ if (pFormat == 0 || *pFormat != AUDIO_HW_IN_FORMAT) {
+ *pFormat = AUDIO_HW_IN_FORMAT;
+ return BAD_VALUE;
+ }
+ if (pRate == 0) {
+ return BAD_VALUE;
+ }
+
+ if (*pRate == 0) *pRate = sampleRate();
+
+ uint32_t rate = AudioHardware::getInputSampleRate(*pRate);
+
+ if (rate != *pRate) {
+ *pRate = rate;
+ return BAD_VALUE;
+ }
+
+ if (devices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) {
+ mInSampleRate = get_USBAudio_sampleRate(UA_Record_type, *pRate);
+ }
+
+ if (pChannels == 0 || (*pChannels != AudioSystem::CHANNEL_IN_MONO &&
+ *pChannels != AudioSystem::CHANNEL_IN_STEREO)) {
+ *pChannels = AUDIO_HW_IN_CHANNELS;
+ return BAD_VALUE;
+ }
+
+ if (devices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) {
+ uint32_t usbChannels = (*pChannels == AudioSystem::CHANNEL_IN_MONO) ? 1 : 2;
+ *pChannels = (get_USBAudio_Channels(UA_Record_type, usbChannels) == 1) ?
+ AudioSystem::CHANNEL_IN_MONO : AudioSystem::CHANNEL_IN_STEREO;
+ } else
+ *pChannels = AudioSystem::CHANNEL_IN_STEREO;
+
+ mHardware = hw;
+
+ ALOGV("AudioStreamInALSA::set(%d, %d, %u)", *pFormat, *pChannels, *pRate);
+
+ mDevices = devices;
+ mChannels = *pChannels;
+ mChannelCount = AudioSystem::popCount(mChannels);
+ mReqSampleRate = rate;
+ if (rate >= mInSampleRate) {
+ mSampleRate = mInSampleRate;
+ } else {
+ mSampleRate = rate;
+ }
+ mBufferSize = getBufferSize(mSampleRate, AudioSystem::popCount(*pChannels));
+
+ ALOGV("mInSampleRate %d, mSampleRate %d", mInSampleRate, mSampleRate);
+ if (mSampleRate < mInSampleRate) {
+ mDownSampler = new AudioHardware::DownSampler(mSampleRate,
+ mInSampleRate,
+ mChannelCount,
+ AUDIO_HW_IN_PERIOD_SZ,
+ this);
+ status_t status = mDownSampler->initCheck();
+ if (status != NO_ERROR) {
+ delete mDownSampler;
+ mDownSampler = NULL;
+ ALOGW("AudioStreamInALSA::set() downsampler init failed: %d", status);
+ return status;
+ }
+
+ mPcmIn = new int16_t[AUDIO_HW_IN_PERIOD_SZ * mChannelCount];
+ }
+#if (SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE)
+ mSpeexFrameSize = mBufferSize/((mChannelCount*sizeof(int16_t))*2);//
+ mSpeexPcmIn = new int16_t[mSpeexFrameSize];
+ mSpeexState = speex_preprocess_state_init(mSpeexFrameSize, mSampleRate);
+ if(mSpeexState == NULL)
+ return BAD_VALUE;
+#if SPEEX_AGC_ENABLE
+ int agc = 1;
+ float q= 27000; //取值范围可以自己改不要超过30000;
+ //actually default is 8000(0,32768),here make it louder for voice is not loudy enough by default. 8000
+ speex_preprocess_ctl(mSpeexState, SPEEX_PREPROCESS_SET_AGC, &agc);//增益
+ speex_preprocess_ctl(mSpeexState, SPEEX_PREPROCESS_SET_AGC_LEVEL,&q);
+#endif//SPEEX_AGC_ENABLE
+
+#if SPEEX_DENOISE_ENABLE
+ int denoise = 1;
+#if SPEEX_AGC_ENABLE
+ int noiseSuppress = -32;//DB值可以自己改, 根据具体产品修改出适合的值,-25~-45
+#else
+ int noiseSuppress = -24;
+#endif
+ speex_preprocess_ctl(mSpeexState, SPEEX_PREPROCESS_SET_DENOISE, &denoise);
+ speex_preprocess_ctl(mSpeexState, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS, &noiseSuppress);
+#endif//SPEEX_DENOISE_ENABLE
+
+#endif//SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE
+ return NO_ERROR;
+}
+
+AudioHardware::AudioStreamInALSA::~AudioStreamInALSA()
+{
+ standby();
+ if (mDownSampler != NULL) {
+ delete mDownSampler;
+ mDownSampler = NULL;
+ if (mPcmIn != NULL) {
+ delete[] mPcmIn;
+ mPcmIn = NULL;
+ }
+ }
+
+#if (SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE)
+ if (mSpeexState) {
+ speex_preprocess_state_destroy(mSpeexState);
+ mSpeexState = NULL;
+ }
+ if(mSpeexPcmIn) {
+ delete[] mSpeexPcmIn;
+ mSpeexPcmIn = NULL;
+ }
+#endif //SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE
+
+#ifdef DEBUG_ALSA_IN
+ if(alsa_in_fp)
+ fclose(alsa_in_fp);
+#endif
+}
+status_t AudioHardware::AudioStreamInALSA::setGain(float gain)
+{
+ if(gain == 0.0)
+ mMicMute= true;
+ else
+ mMicMute = false;
+
+ return NO_ERROR;
+}
+
+ssize_t AudioHardware::AudioStreamInALSA::read(void* buffer, ssize_t bytes)
+{
+ // ALOGV("AudioStreamInALSA::read(%p, %u)", buffer, bytes);
+ status_t status = NO_INIT;
+ int ret;
+
+ if (mHardware == NULL) return NO_INIT;
+
+ { // scope for the lock
+ android::AutoMutex lock(mLock);
+
+ if (mStandby) {
+ android::AutoMutex hwLock(mHardware->lock());
+
+ ALOGD("AudioHardware pcm capture is exiting standby.");
+ acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioInLock");
+
+ /* android::sp<AudioStreamOutALSA> spOut = mHardware->output();
+ while (spOut != 0) {
+ if (!spOut->checkStandby()) {
+ int cnt = spOut->standbyCnt();
+ mHardware->lock().unlock();
+ mLock.unlock();
+ // Mutex acquisition order is always out -> in -> hw
+ spOut->lock();
+ mLock.lock();
+ mHardware->lock().lock();
+ // make sure that another thread did not change output state
+ // while the mutex is released
+ if ((spOut == mHardware->output()) && (cnt == spOut->standbyCnt())) {
+ ALOGV("AudioStreamInALSA::read() force output standby");
+ spOut->close_l();
+ break;
+ }
+ spOut->unlock();
+ spOut = mHardware->output();
+ } else {
+ spOut.clear();
+ }
+ }
+ // spOut is not 0 here only if the output was active and has been
+ // closed above
+
+ // open output before input
+ if (spOut != 0) {
+ if (spOut->open_l() != NO_ERROR) {
+ spOut->doStandby_l();
+ }
+ spOut->unlock();
+ }*/
+
+ open_l();
+
+ if (mPcm == NULL) {
+ release_wake_lock("AudioInLock");
+ goto Error;
+ }
+ mStandby = false;
+ }
+
+
+ if (mDownSampler != NULL) {
+ size_t frames = bytes / frameSize();
+ size_t framesIn = 0;
+ mReadStatus = 0;
+ do {
+ size_t outframes = frames - framesIn;
+ mDownSampler->resample(
+ (int16_t *)buffer + (framesIn * mChannelCount),
+ &outframes);
+ framesIn += outframes;
+ } while ((framesIn < frames) && mReadStatus == 0);
+ ret = mReadStatus;
+ bytes = framesIn * frameSize();
+ } else {
+ TRACE_DRIVER_IN(DRV_PCM_READ)
+ ret = pcm_read(mPcm, buffer, bytes);
+ TRACE_DRIVER_OUT
+ }
+
+ if (ret == 0) {
+ //drop 0.5S input data
+ if(mDropCnt < mSampleRate/2)
+ {
+ memset(buffer,0,bytes);
+ mDropCnt += bytes/frameSize();
+ }
+ else if (mMicMute)
+ {
+ memset(buffer,0,bytes);
+ }
+
+#ifdef DEBUG_ALSA_IN
+ if(alsa_in_fp)
+ fwrite(buffer,1,bytes,alsa_in_fp);
+#endif
+
+#if (SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE)
+ if(!mMicMute)
+ {
+ int index = 0;
+ int startPos = 0;
+ spx_int16_t* data = (spx_int16_t*) buffer;
+
+ int curFrameSize = bytes/(mChannelCount*sizeof(int16_t));
+
+ if(curFrameSize != 2*mSpeexFrameSize)
+ ALOGV("the current request have some error mSpeexFrameSize %d bytes %d ",mSpeexFrameSize,bytes);
+
+ while(curFrameSize >= startPos+mSpeexFrameSize)
+ {
+
+ for(index = startPos; index< startPos + mSpeexFrameSize ;index++ )
+ mSpeexPcmIn[index-startPos] = data[index*mChannelCount]/2 + data[index*mChannelCount+1]/2;
+
+ speex_preprocess_run(mSpeexState,mSpeexPcmIn);
+#ifndef TARGET_RK2928
+ for(unsigned long ch = 0 ; ch < mChannelCount;ch++)
+ for(index = startPos; index< startPos + mSpeexFrameSize ;index++ )
+ {
+ data[index*mChannelCount+ch] = mSpeexPcmIn[index-startPos];
+ }
+#else
+ for(index = startPos; index< startPos + mSpeexFrameSize ;index++ )
+ {
+ int tmp = (int)mSpeexPcmIn[index-startPos]+ mSpeexPcmIn[index-startPos]/2;
+ data[index*mChannelCount+0] = tmp > 32767 ? 32767 : (tmp < -32768 ? -32768 : tmp);
+ }
+ for(int ch = 1 ; ch < mChannelCount;ch++)
+ for(index = startPos; index< startPos + mSpeexFrameSize ;index++ )
+ {
+ data[index*mChannelCount+ch] = data[index*mChannelCount+0];
+ }
+#endif
+ startPos += mSpeexFrameSize;
+ }
+ }
+#endif//(SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE)
+ return bytes;
+ }
+
+ ALOGW("read error: %d", ret);
+ status = ret;
+ }
+
+Error:
+
+ standby();
+
+ // Simulate audio output timing in case of error
+ usleep((((bytes * 1000) / frameSize()) * 1000) / sampleRate());
+
+ return status;
+}
+
+status_t AudioHardware::AudioStreamInALSA::standby()
+{
+ if (mHardware == NULL) return NO_INIT;
+
+ android::AutoMutex lock(mLock);
+
+ { // scope for AudioHardware lock
+ android::AutoMutex hwLock(mHardware->lock());
+ doStandby_l();
+ }
+ return NO_ERROR;
+}
+
+void AudioHardware::AudioStreamInALSA::doStandby_l()
+{
+ mStandbyCnt++;
+
+ if (!mStandby) {
+ ALOGD("AudioHardware pcm capture is going to standby.");
+ release_wake_lock("AudioInLock");
+ mStandby = true;
+ }
+ close_l();
+}
+
+void AudioHardware::AudioStreamInALSA::close_l()
+{
+ if (mPcm) {
+ ALOGV("close_l() reset Capture MIC Path to OFF");
+
+ TRACE_DRIVER_IN(DRV_PCM_CLOSE)
+ route_pcm_close(CAPTURE_OFF_ROUTE);
+ TRACE_DRIVER_OUT
+ mPcm = NULL;
+ }
+}
+
+status_t AudioHardware::AudioStreamInALSA::open_l()
+{
+ unsigned flags = PCM_IN;
+
+ flags |= (AUDIO_HW_IN_PERIOD_MULT * mInSampleRate / AUDIO_HW_IN_SAMPLERATE - 1) << PCM_PERIOD_SZ_SHIFT;
+ flags |= (AUDIO_HW_IN_PERIOD_CNT - PCM_PERIOD_CNT_MIN)
+ << PCM_PERIOD_CNT_SHIFT;
+
+ if (mChannels == AudioSystem::CHANNEL_IN_MONO)
+ flags |= PCM_MONO;
+
+ if (mInSampleRate == 8000)
+ flags |= PCM_8000HZ;
+ else if (mInSampleRate == 48000)
+ flags |= PCM_48000HZ;
+
+ ALOGV("open pcm_in driver");
+ TRACE_DRIVER_IN(DRV_PCM_OPEN)
+ mPcm = route_pcm_open(mHardware->getRouteFromDevice(mDevices), flags);
+ TRACE_DRIVER_OUT
+ if (!pcm_ready(mPcm)) {
+ ALOGE("cannot open pcm_in driver: %s\n", pcm_error(mPcm));
+ TRACE_DRIVER_IN(DRV_PCM_CLOSE)
+ route_pcm_close(CAPTURE_OFF_ROUTE);
+ TRACE_DRIVER_OUT
+ mPcm = NULL;
+ return NO_INIT;
+ }
+
+ if (mDownSampler != NULL) {
+ mInPcmInBuf = 0;
+ mDownSampler->reset();
+ }
+
+ if (mHardware->mode() != AudioSystem::MODE_IN_CALL) {
+ ALOGV("read() wakeup setting Capture route");
+ TRACE_DRIVER_IN(DRV_MIXER_SEL)
+ route_set_controls(mHardware->getRouteFromDevice(mDevices));
+ TRACE_DRIVER_OUT
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioHardware::AudioStreamInALSA::dump(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, "\n\t\tAudioStreamInALSA maybe deadlocked\n");
+ } else {
+ mLock.unlock();
+ }
+
+ snprintf(buffer, SIZE, "\t\tmHardware: %p\n", mHardware);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmPcm: %p\n", mPcm);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tStandby %s\n", (mStandby) ? "ON" : "OFF");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmDevices: 0x%08x\n", mDevices);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmChannels: 0x%08x\n", mChannels);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmSampleRate: %d\n", mSampleRate);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmBufferSize: %d\n", mBufferSize);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmDriverOp: %d\n", mDriverOp);
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+
+ return NO_ERROR;
+}
+
+bool AudioHardware::AudioStreamInALSA::checkStandby()
+{
+ return mStandby;
+}
+
+status_t AudioHardware::AudioStreamInALSA::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ status_t status = NO_ERROR;
+ int value;
+ String8 source;
+ bool reconfig = false;
+
+ ALOGD("AudioStreamInALSA::setParameters() %s", keyValuePairs.string());
+
+ if (mHardware == NULL) return NO_INIT;
+
+ {
+ bool needStandby = false;
+ android::AutoMutex lock(mLock);
+
+ if (param.get(String8(INPUT_SOURCE_KEY), source) == NO_ERROR) {
+ android::AutoMutex hwLock(mHardware->lock());
+
+ mHardware->setInputSource_l(source);
+
+ param.remove(String8(INPUT_SOURCE_KEY));
+ }
+
+ if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR)
+ {
+ if (mInSampleRate != (uint32_t)value && value != 0 &&
+ (value == 8000 || value == 44100 || value == 48000)) {
+ mInSampleRate = (uint32_t)value;
+ reconfig = true;
+ if (mHardware->mode() != AudioSystem::MODE_IN_CALL) {
+ needStandby = true;
+ }
+ }
+ param.remove(String8(AudioParameter::keySamplingRate));
+ }
+
+ if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR)
+ {
+ if (mChannels != (uint32_t)value && (uint32_t)value != 0 &&
+ (value == AudioSystem::CHANNEL_IN_STEREO || value == AudioSystem::CHANNEL_IN_MONO)) {
+ mChannels = (uint32_t)value;
+ reconfig = true;
+ if (mHardware->mode() != AudioSystem::MODE_IN_CALL) {
+ needStandby = true;
+ }
+ }
+ param.remove(String8(AudioParameter::keyChannels));
+ }
+
+ if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR)
+ {
+ if (mDevices != (uint32_t)value && (uint32_t)value != AUDIO_DEVICE_NONE) {
+ mDevices = (uint32_t)value;
+ if (mHardware->mode() != AudioSystem::MODE_IN_CALL) {
+ needStandby = true;
+ }
+ }
+ param.remove(String8(AudioParameter::keyRouting));
+ }
+
+ if (needStandby){
+ android::AutoMutex hwLock(mHardware->lock());
+ doStandby_l();
+ }
+
+ //close downsampler and open again to update params
+ if (reconfig) {
+ android::AutoMutex hwLock(mHardware->lock());
+ if (mDownSampler != NULL) {
+ delete mDownSampler;
+ mDownSampler = NULL;
+ if (mPcmIn != NULL) {
+ delete[] mPcmIn;
+ mPcmIn = NULL;
+ }
+ }
+#if (SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE)
+ if (mSpeexState) {
+ speex_preprocess_state_destroy(mSpeexState);
+ mSpeexState = NULL;
+ }
+ if(mSpeexPcmIn) {
+ delete[] mSpeexPcmIn;
+ mSpeexPcmIn = NULL;
+ }
+#endif //SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE
+
+ int pFormat = AUDIO_HW_IN_FORMAT;
+ uint32_t pChannels = mChannels;
+ uint32_t pRate = mReqSampleRate;
+
+ if (set(mHardware, mDevices, &pFormat, &pChannels, &pRate, (AudioSystem::audio_in_acoustics)0) != NO_ERROR) {
+ ALOGE("AudioStreamInALSA; call set error!");
+ return BAD_VALUE;
+ }
+ }
+ }
+
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+
+ return status;
+
+}
+
+String8 AudioHardware::AudioStreamInALSA::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)mDevices);
+ }
+
+ if (param.get(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
+ param.addInt(String8(AudioParameter::keySamplingRate), (int)mInSampleRate);
+ }
+
+ if (param.get(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
+ param.addInt(String8(AudioParameter::keyChannels), (int)mChannels);
+ }
+
+ ALOGV("AudioStreamInALSA::getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
+status_t AudioHardware::AudioStreamInALSA::getNextBuffer(AudioHardware::BufferProvider::Buffer* buffer)
+{
+ if (mPcm == NULL) {
+ buffer->raw = NULL;
+ buffer->frameCount = 0;
+ mReadStatus = NO_INIT;
+ return NO_INIT;
+ }
+
+ if (mInPcmInBuf == 0) {
+ TRACE_DRIVER_IN(DRV_PCM_READ)
+ mReadStatus = pcm_read(mPcm,(void*) mPcmIn, AUDIO_HW_IN_PERIOD_SZ * frameSize() * mInSampleRate / AUDIO_HW_IN_SAMPLERATE);
+ TRACE_DRIVER_OUT
+ if (mReadStatus != 0) {
+ buffer->raw = NULL;
+ buffer->frameCount = 0;
+ return mReadStatus;
+ }
+ mInPcmInBuf = AUDIO_HW_IN_PERIOD_SZ * mInSampleRate / AUDIO_HW_IN_SAMPLERATE;
+ }
+
+ buffer->frameCount = (buffer->frameCount > mInPcmInBuf) ? mInPcmInBuf : buffer->frameCount;
+ buffer->i16 = mPcmIn + (AUDIO_HW_IN_PERIOD_SZ * mInSampleRate / AUDIO_HW_IN_SAMPLERATE - mInPcmInBuf) * mChannelCount;
+
+ return mReadStatus;
+}
+
+void AudioHardware::AudioStreamInALSA::releaseBuffer(Buffer* buffer)
+{
+ mInPcmInBuf -= buffer->frameCount;
+}
+
+size_t AudioHardware::AudioStreamInALSA::getBufferSize(uint32_t sampleRate, int channelCount)
+{
+ size_t ratio;
+
+ switch (sampleRate) {
+ case 8000:
+ case 11025:
+ case 12000:
+ ratio = 4;
+ break;
+ case 16000:
+ case 22050:
+ case 24000:
+ ratio = 2;
+ break;
+ case 32000:
+ case 44100:
+ case 48000:
+ default:
+ ratio = 1;
+ break;
+ }
+
+ return (AUDIO_HW_IN_PERIOD_SZ * channelCount * sizeof(int16_t)) / ratio ;
+}
+
+//------------------------------------------------------------------------------
+// DownSampler
+//------------------------------------------------------------------------------
+
+/*
+ * 2.30 fixed point FIR filter coefficients for conversion 44100 -> 22050.
+ * (Works equivalently for 22010 -> 11025 or any other halving, of course.)
+ *
+ * Transition band from about 18 kHz, passband ripple < 0.1 dB,
+ * stopband ripple at about -55 dB, linear phase.
+ *
+ * Design and display in MATLAB or Octave using:
+ *
+ * filter = fir1(19, 0.5); filter = round(filter * 2**30); freqz(filter * 2**-30);
+ */
+static const int32_t filter_22khz_coeff[] = {
+ 2089257, 2898328, -5820678, -10484531,
+ 19038724, 30542725, -50469415, -81505260,
+ 152544464, 478517512, 478517512, 152544464,
+ -81505260, -50469415, 30542725, 19038724,
+ -10484531, -5820678, 2898328, 2089257,
+};
+#define NUM_COEFF_22KHZ (sizeof(filter_22khz_coeff) / sizeof(filter_22khz_coeff[0]))
+#define OVERLAP_22KHZ (NUM_COEFF_22KHZ - 2)
+
+/*
+ * Convolution of signals A and reverse(B). (In our case, the filter response
+ * is symmetric, so the reversing doesn't matter.)
+ * A is taken to be in 0.16 fixed-point, and B is taken to be in 2.30 fixed-point.
+ * The answer will be in 16.16 fixed-point, unclipped.
+ *
+ * This function would probably be the prime candidate for SIMD conversion if
+ * you want more speed.
+ */
+int32_t fir_convolve(const int16_t* a, const int32_t* b, int num_samples)
+{
+ int32_t sum = 1 << 13;
+ for (int i = 0; i < num_samples; ++i) {
+ sum += a[i] * (b[i] >> 16);
+ }
+ return sum >> 14;
+}
+
+/* Clip from 16.16 fixed-point to 0.16 fixed-point. */
+int16_t clip(int32_t x)
+{
+ if (x < -32768) {
+ return -32768;
+ } else if (x > 32767) {
+ return 32767;
+ } else {
+ return x;
+ }
+}
+
+/*
+ * Convert a chunk from 44 kHz to 22 kHz. Will update num_samples_in and num_samples_out
+ * accordingly, since it may leave input samples in the buffer due to overlap.
+ *
+ * Input and output are taken to be in 0.16 fixed-point.
+ */
+void resample_2_1(int16_t* input, int16_t* output, int* num_samples_in, int* num_samples_out)
+{
+ if (*num_samples_in < (int)NUM_COEFF_22KHZ) {
+ *num_samples_out = 0;
+ return;
+ }
+
+ int odd_smp = *num_samples_in & 0x1;
+ int num_samples = *num_samples_in - odd_smp - OVERLAP_22KHZ;
+
+ for (int i = 0; i < num_samples; i += 2) {
+ output[i / 2] = clip(fir_convolve(input + i, filter_22khz_coeff, NUM_COEFF_22KHZ));
+ }
+
+ memmove(input, input + num_samples, (OVERLAP_22KHZ + odd_smp) * sizeof(*input));
+ *num_samples_out = num_samples / 2;
+ *num_samples_in = OVERLAP_22KHZ + odd_smp;
+}
+
+/*
+ * 2.30 fixed point FIR filter coefficients for conversion 22050 -> 16000,
+ * or 11025 -> 8000.
+ *
+ * Transition band from about 14 kHz, passband ripple < 0.1 dB,
+ * stopband ripple at about -50 dB, linear phase.
+ *
+ * Design and display in MATLAB or Octave using:
+ *
+ * filter = fir1(23, 16000 / 22050); filter = round(filter * 2**30); freqz(filter * 2**-30);
+ */
+static const int32_t filter_16khz_coeff[] = {
+ 2057290, -2973608, 1880478, 4362037,
+ -14639744, 18523609, -1609189, -38502470,
+ 78073125, -68353935, -59103896, 617555440,
+ 617555440, -59103896, -68353935, 78073125,
+ -38502470, -1609189, 18523609, -14639744,
+ 4362037, 1880478, -2973608, 2057290,
+};
+#define NUM_COEFF_16KHZ (sizeof(filter_16khz_coeff) / sizeof(filter_16khz_coeff[0]))
+#define OVERLAP_16KHZ (NUM_COEFF_16KHZ - 1)
+
+/*
+ * Convert a chunk from 22 kHz to 16 kHz. Will update num_samples_in and
+ * num_samples_out accordingly, since it may leave input samples in the buffer
+ * due to overlap.
+ *
+ * This implementation is rather ad-hoc; it first low-pass filters the data
+ * into a temporary buffer, and then converts chunks of 441 input samples at a
+ * time into 320 output samples by simple linear interpolation. A better
+ * implementation would use a polyphase filter bank to do these two operations
+ * in one step.
+ *
+ * Input and output are taken to be in 0.16 fixed-point.
+ */
+
+#define RESAMPLE_16KHZ_SAMPLES_IN 441
+#define RESAMPLE_16KHZ_SAMPLES_OUT 320
+
+void resample_441_320(int16_t* input, int16_t* output, int* num_samples_in, int* num_samples_out)
+{
+ const int num_blocks = (*num_samples_in - OVERLAP_16KHZ) / RESAMPLE_16KHZ_SAMPLES_IN;
+ if (num_blocks < 1) {
+ *num_samples_out = 0;
+ return;
+ }
+
+ for (int i = 0; i < num_blocks; ++i) {
+ uint32_t tmp[RESAMPLE_16KHZ_SAMPLES_IN];
+ for (int j = 0; j < RESAMPLE_16KHZ_SAMPLES_IN; ++j) {
+ tmp[j] = fir_convolve(input + i * RESAMPLE_16KHZ_SAMPLES_IN + j,
+ filter_16khz_coeff,
+ NUM_COEFF_16KHZ);
+ }
+
+ const float step_float = (float)RESAMPLE_16KHZ_SAMPLES_IN / (float)RESAMPLE_16KHZ_SAMPLES_OUT;
+
+ uint32_t in_sample_num = 0; // 16.16 fixed point
+ const uint32_t step = (uint32_t)(step_float * 65536.0f + 0.5f); // 16.16 fixed point
+ for (int j = 0; j < RESAMPLE_16KHZ_SAMPLES_OUT; ++j, in_sample_num += step) {
+ const uint32_t whole = in_sample_num >> 16;
+ const uint32_t frac = (in_sample_num & 0xffff); // 0.16 fixed point
+ const int32_t s1 = tmp[whole];
+ const int32_t s2 = tmp[whole + 1];
+ *output++ = clip(s1 + (((s2 - s1) * (int32_t)frac) >> 16));
+ }
+ }
+
+ const int samples_consumed = num_blocks * RESAMPLE_16KHZ_SAMPLES_IN;
+ memmove(input, input + samples_consumed, (*num_samples_in - samples_consumed) * sizeof(*input));
+ *num_samples_in -= samples_consumed;
+ *num_samples_out = RESAMPLE_16KHZ_SAMPLES_OUT * num_blocks;
+}
+
+
+AudioHardware::DownSampler::DownSampler(uint32_t outSampleRate,
+ uint32_t inSampleRate,
+ uint32_t channelCount,
+ uint32_t frameCount,
+ AudioHardware::BufferProvider* provider)
+ : mStatus(NO_INIT), mProvider(provider), mSampleRate(outSampleRate),
+ mChannelCount(channelCount), mFrameCount(frameCount),
+ mTmpOutBuf(NULL),mInResampler(NULL)
+
+{
+ ALOGV("AudioHardware::DownSampler() cstor %p SR %d channels %d frames %d",
+ this, mSampleRate, mChannelCount, mFrameCount);
+
+ if (mSampleRate != 8000 && mSampleRate != 11025 && mSampleRate != 12000&&mSampleRate != 16000 &&
+ mSampleRate != 22050 && mSampleRate != 24000 &&mSampleRate != 32000 && mSampleRate != 44100&& mSampleRate != 48000) {
+ ALOGW("AudioHardware::DownSampler cstor: bad sampling rate: %d", mSampleRate);
+ return;
+ }
+
+ mTmpOutBuf= new int16_t[mFrameCount*mChannelCount];
+ int error;
+ ALOGI("--->speex_resampler_init ch=%d in =%d,out =%d",mChannelCount,inSampleRate,mSampleRate);
+ mInResampler = speex_resampler_init(mChannelCount,
+ inSampleRate,
+ mSampleRate,
+ RESAMPLER_QUALITY,
+ &error);
+ if (mInResampler == NULL) {
+ ALOGW("Session_SetConfig Cannot create speex resampler: %s",
+ speex_resampler_strerror(error));
+ return ;
+ }
+
+ mStatus = NO_ERROR;
+}
+
+AudioHardware::DownSampler::~DownSampler()
+{
+ if (mTmpOutBuf) delete[] mTmpOutBuf;
+ if (mInResampler) speex_resampler_destroy(mInResampler);
+}
+
+void AudioHardware::DownSampler::reset()
+{
+ mOutBufPos = 0;
+ mInOutBuf = 0;
+}
+
+
+int AudioHardware::DownSampler::resample(int16_t* out, size_t *outFrameCount)
+{
+ if (mStatus != NO_ERROR) {
+ return mStatus;
+ }
+
+ if (out == NULL || outFrameCount == NULL) {
+ return BAD_VALUE;
+ }
+
+
+ int outFrames = 0;
+ int remaingFrames = *outFrameCount;
+
+ if (mInOutBuf) {
+ //ALOGV("mInOutBuf = %d remaingFrames =%d",mInOutBuf,remaingFrames);
+ int frames = (remaingFrames > mInOutBuf) ? mInOutBuf : remaingFrames;
+
+ memcpy((void*)out, (void*)(mTmpOutBuf+mOutBufPos*mChannelCount),frames*mChannelCount*sizeof(int16_t));
+
+ remaingFrames -= frames;
+ mInOutBuf -= frames;
+ mOutBufPos += frames;
+ outFrames += frames;
+ }
+
+ while (remaingFrames) {
+ ALOGW_IF((mInOutBuf != 0), "mInOutBuf should be 0 here");
+
+ AudioHardware::BufferProvider::Buffer buf;
+ buf.frameCount = mFrameCount;
+ int ret = mProvider->getNextBuffer(&buf);
+ if (buf.raw == NULL) {
+ *outFrameCount = outFrames;
+ return ret;
+ }
+
+ uint inFrameCount = buf.frameCount;
+ uint outFrameCount = mFrameCount*mChannelCount;
+ //ALOGV("before resample inFrameCount = %d",inFrameCount);
+ if (mChannelCount == 1) {
+ speex_resampler_process_int(mInResampler,
+ 0,
+ (const spx_int16_t *)buf.raw,
+ &inFrameCount,
+ mTmpOutBuf,
+ &outFrameCount);
+ } else {
+ speex_resampler_process_interleaved_int(mInResampler,
+ (const spx_int16_t *)buf.raw,
+ &inFrameCount,
+ mTmpOutBuf,
+ &outFrameCount);
+ }
+ //ALOGV("after resample inFrameCount use = %d outFrameCount = %d",inFrameCount,outFrameCount);
+ buf.frameCount = inFrameCount;
+ mProvider->releaseBuffer(&buf);
+
+ mInOutBuf = outFrameCount;
+
+ int frames = (remaingFrames > mInOutBuf) ? mInOutBuf : remaingFrames;
+
+ memcpy((void*)(out+outFrames*mChannelCount), (void*)mTmpOutBuf,frames*mChannelCount*sizeof(int16_t));
+
+ remaingFrames -= frames;
+ outFrames += frames;
+ mOutBufPos = frames;
+ mInOutBuf -= frames;
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+// Factory
+//------------------------------------------------------------------------------
+
+extern "C" AudioHardwareInterface* createAudioHardware(void) {
+ return new AudioHardware();
+}
+
+}; // namespace android
diff --git a/legacy_hal/AudioHardware.h b/legacy_hal/AudioHardware.h
new file mode 100755
index 0000000..d8dcb75
--- /dev/null
+++ b/legacy_hal/AudioHardware.h
@@ -0,0 +1,401 @@
+/*
+** 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.
+*/
+
+/*
+**
+**
+**
+** Audio Hardware Commit log
+**
+**V1.0.0
+** 1)Merge from 4.4 and fix some compile error
+**
+*/
+
+//AudioHardware Version
+#define AUDIO_HAL_VERSION_NAME "sys.audio.version"
+#define AUDIO_HAL_VERSION "1.0.0"
+
+#ifndef ANDROID_AUDIO_HARDWARE_H
+#define ANDROID_AUDIO_HARDWARE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+#include <utils/SortedVector.h>
+
+#include <hardware_legacy/AudioHardwareBase.h>
+
+#include "secril-client.h"
+
+#include <speex/speex.h>
+#include <speex/speex_preprocess.h>
+#include <speex/speex_resampler.h>
+extern "C" {
+ struct pcm;
+ struct mixer;
+ struct mixer_ctl;
+};
+
+namespace android_audio_legacy {
+
+// TODO: determine actual audio DSP and hardware latency
+// Additionnal latency introduced by audio DSP and hardware in ms
+#define AUDIO_HW_OUT_LATENCY_MS 0
+// Default audio output sample rate
+#define AUDIO_HW_OUT_SAMPLERATE 44100
+// Default audio output channel mask
+#define AUDIO_HW_OUT_CHANNELS (AudioSystem::CHANNEL_OUT_STEREO)
+// Default audio output sample format
+#define AUDIO_HW_OUT_FORMAT (AudioSystem::PCM_16_BIT)
+// Kernel pcm out buffer size in frames at 44.1kHz
+#define AUDIO_HW_OUT_PERIOD_MULT 16 // (16 * 64 = 1024 frames)
+#define AUDIO_HW_OUT_PERIOD_SZ (PCM_PERIOD_SZ_MIN * AUDIO_HW_OUT_PERIOD_MULT)
+#define AUDIO_HW_OUT_PERIOD_CNT 4
+// Default audio output buffer size in bytes
+#define AUDIO_HW_OUT_PERIOD_BYTES (AUDIO_HW_OUT_PERIOD_SZ * 2 * sizeof(int16_t))
+
+// Default audio input sample rate
+#define AUDIO_HW_IN_SAMPLERATE 44100
+// Default audio input channel mask
+#define AUDIO_HW_IN_CHANNELS (AudioSystem::CHANNEL_IN_STEREO)
+// Default audio input sample format
+#define AUDIO_HW_IN_FORMAT (AudioSystem::PCM_16_BIT)
+// Number of buffers in audio driver for input
+#define AUDIO_HW_NUM_IN_BUF 4
+// Kernel pcm in buffer size in frames at 44.1kHz (before resampling)
+#define AUDIO_HW_IN_PERIOD_MULT 16 // (8* 64 = 512 frames)
+#define AUDIO_HW_IN_PERIOD_SZ (PCM_PERIOD_SZ_MIN * AUDIO_HW_IN_PERIOD_MULT)
+#define AUDIO_HW_IN_PERIOD_CNT 6
+// Default audio input buffer size in bytes (8kHz mono)
+#define AUDIO_HW_IN_PERIOD_BYTES ((AUDIO_HW_IN_PERIOD_SZ*sizeof(int16_t))/8)
+
+#define INPUT_SOURCE_KEY "Input Source"
+
+
+//1:Enable the AGC funtion ;0: disable the AGC function
+#define SPEEX_AGC_ENABLE 0
+
+//1:Enable the denoise funtion ;0: disable the denoise function
+
+#define SPEEX_DENOISE_ENABLE 1
+
+#define RESAMPLER_QUALITY SPEEX_RESAMPLER_QUALITY_DEFAULT
+
+
+class AudioHardware : public AudioHardwareBase
+{
+ class AudioStreamOutALSA;
+ class AudioStreamInALSA;
+public:
+
+ AudioHardware();
+ virtual ~AudioHardware();
+ virtual status_t initCheck();
+
+ virtual status_t setVoiceVolume(float volume);
+ virtual status_t setMasterVolume(float volume);
+
+ virtual status_t setMode(int mode);
+
+ 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 android_audio_legacy::AudioStreamOut* openOutputStream(
+ uint32_t devices, int *format=0, uint32_t *channels=0,
+ uint32_t *sampleRate=0, status_t *status=0);
+
+ virtual android_audio_legacy::AudioStreamIn* openInputStream(
+ uint32_t devices, int *format, uint32_t *channels,
+ uint32_t *sampleRate, status_t *status,
+ AudioSystem::audio_in_acoustics acoustics);
+
+ virtual status_t setMasterMute(bool muted) ;
+
+
+ virtual int createAudioPatch(unsigned int num_sources,
+ const struct audio_port_config *sources,
+ unsigned int num_sinks,
+ const struct audio_port_config *sinks,
+ audio_patch_handle_t *handle) ;
+
+ virtual int releaseAudioPatch(audio_patch_handle_t handle) ;
+
+ virtual int getAudioPort(struct audio_port *port) ;
+
+ virtual int setAudioPortConfig(const struct audio_port_config *config) ;
+
+
+ virtual android_audio_legacy::AudioStreamOut* openOutputStreamWithFlags(uint32_t devices,
+ audio_output_flags_t flags,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
+ status_t *status);
+ virtual void closeOutputStream(android_audio_legacy::AudioStreamOut* out);
+ virtual void closeInputStream(android_audio_legacy::AudioStreamIn* in);
+
+ virtual size_t getInputBufferSize(
+ uint32_t sampleRate, int format, int channelCount);
+
+ int mode() { return mMode; }
+ unsigned getOutputRouteFromDevice(uint32_t device);
+ unsigned getInputRouteFromDevice(uint32_t device);
+ unsigned getVoiceRouteFromDevice(uint32_t device);
+ unsigned getRouteFromDevice(uint32_t device);
+
+ status_t setIncallPath_l(uint32_t device);
+
+ status_t setInputSource_l(String8 source);
+
+ static uint32_t getInputSampleRate(uint32_t sampleRate);
+ android::sp <AudioStreamInALSA> getActiveInput_l();
+
+ android::Mutex& lock() { return mLock; }
+
+ struct pcm *openPcmOut_l();
+ void closePcmOut_l();
+
+ struct pcm *getPcm() { return mPcm; };
+
+ android::sp <AudioStreamOutALSA> output() { return mOutput; }
+
+protected:
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+private:
+
+ bool mInit;
+ bool mMicMute;
+ android::sp <AudioStreamOutALSA> mOutput;
+ android::SortedVector < android::sp<AudioStreamInALSA> > mInputs;
+ android::Mutex mLock;
+ struct pcm* mPcm;
+ uint32_t mPcmOpenCnt;
+ uint32_t mMixerOpenCnt;
+ bool mInCallAudioMode;
+ bool mVoipAudioMode;
+
+ String8 mInputSource;
+ bool mBluetoothNrec;
+ void* mSecRilLibHandle;
+ HRilClient mRilClient;
+ bool mActivatedCP;
+ HRilClient (*openClientRILD) (void);
+ int (*disconnectRILD) (HRilClient);
+ int (*closeClientRILD) (HRilClient);
+ int (*isConnectedRILD) (HRilClient);
+ int (*connectRILD) (HRilClient);
+ int (*setCallVolume) (HRilClient, SoundType, int);
+ int (*setCallAudioPath)(HRilClient, AudioPath);
+ int (*setCallClockSync)(HRilClient, SoundClockCondition);
+ void loadRILD(void);
+ status_t connectRILDIfRequired(void);
+
+ // trace driver operations for dump
+ int mDriverOp;
+
+ static uint32_t checkInputSampleRate(uint32_t sampleRate);
+ static const uint32_t inputSamplingRates[];
+
+ class AudioStreamOutALSA : public AudioStreamOut, public android::RefBase
+ {
+ public:
+ AudioStreamOutALSA();
+ virtual ~AudioStreamOutALSA();
+ status_t set(AudioHardware* mHardware,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate);
+ virtual uint32_t sampleRate()
+ const { return mSampleRate; }
+ virtual size_t bufferSize()
+ const { return mBufferSize; }
+ virtual uint32_t channels()
+ const { return mChannels; }
+ virtual int format()
+ const { return AUDIO_HW_OUT_FORMAT; }
+ virtual uint32_t latency()
+ const { return (1000 * AUDIO_HW_OUT_PERIOD_CNT *
+ (bufferSize()/frameSize()))/sampleRate() +
+ AUDIO_HW_OUT_LATENCY_MS; }
+ 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();
+ bool checkStandby();
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ uint32_t device() { return mDevices; }
+ virtual status_t getRenderPosition(uint32_t *dspFrames);
+
+ void doStandby_l();
+ void close_l();
+ status_t open_l();
+ int standbyCnt() { return mStandbyCnt; }
+
+ void lock() { mLock.lock(); }
+ void unlock() { mLock.unlock(); }
+
+ private:
+
+ android::Mutex mLock;
+ AudioHardware* mHardware;
+ struct mixer_ctl *mRouteCtl;
+ const char *next_route;
+ bool mStandby;
+ uint32_t mDevices;
+ uint32_t mChannels;
+ uint32_t mSampleRate;
+ size_t mBufferSize;
+ // trace driver operations for dump
+ int mDriverOp;
+ int mStandbyCnt;
+ };
+
+ class DownSampler;
+
+ class BufferProvider
+ {
+ public:
+
+ struct Buffer {
+ union {
+ void* raw;
+ short* i16;
+ int8_t* i8;
+ };
+ size_t frameCount;
+ };
+
+ virtual ~BufferProvider() {}
+
+ virtual status_t getNextBuffer(Buffer* buffer) = 0;
+ virtual void releaseBuffer(Buffer* buffer) = 0;
+ };
+
+ class DownSampler {
+ public:
+ DownSampler(uint32_t outSampleRate,
+ uint32_t inSampleRate,
+ uint32_t channelCount,
+ uint32_t frameCount,
+ BufferProvider* provider);
+
+ virtual ~DownSampler();
+
+ void reset();
+ status_t initCheck() { return mStatus; }
+ int resample(int16_t* out, size_t *outFrameCount);
+
+ private:
+ status_t mStatus;
+ BufferProvider* mProvider;
+ uint32_t mSampleRate;
+ uint32_t mChannelCount;
+ uint32_t mFrameCount;
+ int16_t *mTmpOutBuf;
+ int mOutBufPos;
+ int mInOutBuf;
+ int mInInBuf;
+ SpeexResamplerState *mInResampler; // handle on input speex resampler
+ };
+
+
+ class AudioStreamInALSA : public AudioStreamIn, public BufferProvider, public android::RefBase
+ {
+
+ public:
+ AudioStreamInALSA();
+ virtual ~AudioStreamInALSA();
+ status_t set(AudioHardware* hw,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate,
+ AudioSystem::audio_in_acoustics acoustics);
+ virtual size_t bufferSize() const { return mBufferSize; }
+ virtual uint32_t channels() const { return mChannels; }
+ virtual int format() const { return AUDIO_HW_IN_FORMAT; }
+ virtual uint32_t sampleRate() const { return mSampleRate; }
+ 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();
+ bool checkStandby();
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ virtual unsigned int getInputFramesLost() const { return 0; }
+ uint32_t device() { return mDevices; }
+ void doStandby_l();
+ void close_l();
+ status_t open_l();
+ int standbyCnt() { return mStandbyCnt; }
+
+ static size_t getBufferSize(uint32_t sampleRate, int channelCount);
+
+ // BufferProvider
+ virtual status_t getNextBuffer(BufferProvider::Buffer* buffer);
+ virtual void releaseBuffer(BufferProvider::Buffer* buffer);
+
+ void lock() { mLock.lock(); }
+ void unlock() { mLock.unlock(); }
+
+ virtual status_t addAudioEffect(effect_handle_t effect){return 0;};
+ virtual status_t removeAudioEffect(effect_handle_t effect){return 0;};
+
+ private:
+ android::Mutex mLock;
+ AudioHardware* mHardware;
+ struct pcm *mPcm;
+ struct mixer_ctl *mRouteCtl;
+ const char *next_route;
+ bool mStandby;
+ uint32_t mDevices;
+ uint32_t mChannels;
+ uint32_t mChannelCount;
+ uint32_t mSampleRate;
+ uint32_t mReqSampleRate;
+ uint32_t mInSampleRate;
+ size_t mBufferSize;
+ DownSampler *mDownSampler;
+ status_t mReadStatus;
+ size_t mInPcmInBuf;
+ int16_t *mPcmIn;
+ bool mMicMute;
+ // trace driver operations for dump
+ int mDriverOp;
+ int mStandbyCnt;
+ uint32_t mDropCnt;
+#if (SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE)
+ SpeexPreprocessState* mSpeexState;
+ int mSpeexFrameSize;
+ int16_t *mSpeexPcmIn;
+#endif//SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE
+ };
+
+};
+
+}; // namespace android
+
+#endif
diff --git a/legacy_hal/AudioHardwareGeneric.cpp b/legacy_hal/AudioHardwareGeneric.cpp
new file mode 100755
index 0000000..a2b00f8
--- /dev/null
+++ b/legacy_hal/AudioHardwareGeneric.cpp
@@ -0,0 +1,413 @@
+/*
+**
+** 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>
+
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+namespace android_audio_legacy {
+
+// ----------------------------------------------------------------------------
+
+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;
+ ALOGV("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);
+ }
+
+ ALOGV("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;
+ ALOGV("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, *pFormat, *pChannels, *pRate);
+ // check values
+ if ((*pFormat != format()) ||
+ (*pChannels != channels()) ||
+ (*pRate != sampleRate())) {
+ ALOGE("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) {
+ ALOGE("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;
+ ALOGV("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);
+ }
+
+ ALOGV("getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/legacy_hal/AudioHardwareGeneric.h b/legacy_hal/AudioHardwareGeneric.h
new file mode 100755
index 0000000..55498dc
--- /dev/null
+++ b/legacy_hal/AudioHardwareGeneric.h
@@ -0,0 +1,156 @@
+/*
+**
+** 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/AudioSystemLegacy.h>
+#include <hardware_legacy/AudioHardwareBase.h>
+
+namespace android_audio_legacy {
+ using android::Mutex;
+ using android::AutoMutex;
+
+// ----------------------------------------------------------------------------
+
+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; }
+ virtual status_t addAudioEffect(effect_handle_t effect) { return NO_ERROR; }
+ virtual status_t removeAudioEffect(effect_handle_t effect) { return NO_ERROR; }
+
+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/legacy_hal/AudioHardwareInterface.cpp b/legacy_hal/AudioHardwareInterface.cpp
new file mode 100755
index 0000000..43c2442
--- /dev/null
+++ b/legacy_hal/AudioHardwareInterface.cpp
@@ -0,0 +1,169 @@
+/*
+**
+** 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 ENABLE_AUDIO_DUMP
+#include "AudioDumpInterface.h"
+#endif
+
+
+// change to 1 to log routing calls
+#define LOG_ROUTING_CALLS 1
+
+namespace android_audio_legacy {
+
+#if LOG_ROUTING_CALLS
+static const char* routingModeStrings[] =
+{
+ "OUT OF RANGE",
+ "INVALID",
+ "CURRENT",
+ "NORMAL",
+ "RINGTONE",
+ "IN_CALL",
+ "IN_COMMUNICATION"
+};
+
+static const char* routeNone = "NONE";
+
+static const char* displayMode(int mode)
+{
+ if ((mode < AudioSystem::MODE_INVALID) || (mode >= AudioSystem::NUM_MODES))
+ return routingModeStrings[0];
+ return routingModeStrings[mode+3];
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+AudioHardwareInterface* AudioHardwareInterface::create()
+{
+ return NULL;
+}
+
+AudioStreamOut::~AudioStreamOut()
+{
+}
+
+// default implementation is unsupported
+status_t AudioStreamOut::getNextWriteTimestamp(int64_t *timestamp)
+{
+ return INVALID_OPERATION;
+}
+
+status_t AudioStreamOut::getPresentationPosition(uint64_t *frames, struct timespec *timestamp)
+{
+ return INVALID_OPERATION;
+}
+
+AudioStreamIn::~AudioStreamIn() {}
+
+AudioHardwareBase::AudioHardwareBase()
+{
+ mMode = 0;
+}
+
+status_t AudioHardwareBase::setMode(int mode)
+{
+#if LOG_ROUTING_CALLS
+ ALOGD("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) {
+ ALOGW("getInputBufferSize bad sampling rate: %d", sampleRate);
+ return 0;
+ }
+ if (format != AudioSystem::PCM_16_BIT) {
+ ALOGW("getInputBufferSize bad format: %d", format);
+ return 0;
+ }
+ if (channelCount != 1) {
+ ALOGW("getInputBufferSize bad channel count: %d", channelCount);
+ return 0;
+ }
+
+ return 320;
+}
+
+// default implementation is unsupported
+status_t AudioHardwareBase::getMasterVolume(float *volume)
+{
+ return INVALID_OPERATION;
+}
+
+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;
+}
+
+// default implementation calls its "without flags" counterpart
+AudioStreamOut* AudioHardwareInterface::openOutputStreamWithFlags(uint32_t devices,
+ audio_output_flags_t flags,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
+ status_t *status)
+{
+ return openOutputStream(devices, format, channels, sampleRate, status);
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/legacy_hal/AudioHardwareStub.cpp b/legacy_hal/AudioHardwareStub.cpp
new file mode 100755
index 0000000..fd647d5
--- /dev/null
+++ b/legacy_hal/AudioHardwareStub.cpp
@@ -0,0 +1,215 @@
+/* //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_audio_legacy {
+
+// ----------------------------------------------------------------------------
+
+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) /
+ audio_channel_count_from_out_mask(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) /
+ audio_channel_count_from_in_mask(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();
+}
+
+AudioHardwareInterface* createAudioHardware(void) {
+ return new AudioHardwareStub();
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/legacy_hal/AudioHardwareStub.h b/legacy_hal/AudioHardwareStub.h
new file mode 100755
index 0000000..c5f7a80
--- /dev/null
+++ b/legacy_hal/AudioHardwareStub.h
@@ -0,0 +1,108 @@
+/* //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_audio_legacy {
+
+// ----------------------------------------------------------------------------
+
+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; }
+ virtual status_t addAudioEffect(effect_handle_t effect) { return NO_ERROR; }
+ virtual status_t removeAudioEffect(effect_handle_t effect) { return NO_ERROR; }
+};
+
+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/legacy_hal/AudioPolicyCompatClient.cpp b/legacy_hal/AudioPolicyCompatClient.cpp
new file mode 100755
index 0000000..9d02d98
--- /dev/null
+++ b/legacy_hal/AudioPolicyCompatClient.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2011 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 "AudioPolicyCompatClient"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <system/audio_policy.h>
+#include <hardware/audio_policy.h>
+
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+#include "AudioPolicyCompatClient.h"
+
+namespace android_audio_legacy {
+
+audio_module_handle_t AudioPolicyCompatClient::loadHwModule(const char *moduleName)
+{
+ return mServiceOps->load_hw_module(mService, moduleName);
+}
+
+audio_io_handle_t AudioPolicyCompatClient::openOutput(audio_module_handle_t module,
+ audio_devices_t *pDevices,
+ uint32_t *pSamplingRate,
+ audio_format_t *pFormat,
+ audio_channel_mask_t *pChannelMask,
+ uint32_t *pLatencyMs,
+ audio_output_flags_t flags,
+ const audio_offload_info_t *offloadInfo)
+{
+ return mServiceOps->open_output_on_module(mService, module, pDevices, pSamplingRate,
+ pFormat, pChannelMask, pLatencyMs,
+ flags, offloadInfo);
+}
+
+audio_io_handle_t AudioPolicyCompatClient::openDuplicateOutput(audio_io_handle_t output1,
+ audio_io_handle_t output2)
+{
+ return mServiceOps->open_duplicate_output(mService, output1, output2);
+}
+
+status_t AudioPolicyCompatClient::closeOutput(audio_io_handle_t output)
+{
+ return mServiceOps->close_output(mService, output);
+}
+
+status_t AudioPolicyCompatClient::suspendOutput(audio_io_handle_t output)
+{
+ return mServiceOps->suspend_output(mService, output);
+}
+
+status_t AudioPolicyCompatClient::restoreOutput(audio_io_handle_t output)
+{
+ return mServiceOps->restore_output(mService, output);
+}
+
+audio_io_handle_t AudioPolicyCompatClient::openInput(audio_module_handle_t module,
+ audio_devices_t *pDevices,
+ uint32_t *pSamplingRate,
+ audio_format_t *pFormat,
+ audio_channel_mask_t *pChannelMask)
+{
+ return mServiceOps->open_input_on_module(mService, module, pDevices,
+ pSamplingRate, pFormat, pChannelMask);
+}
+
+status_t AudioPolicyCompatClient::closeInput(audio_io_handle_t input)
+{
+ return mServiceOps->close_input(mService, input);
+}
+
+status_t AudioPolicyCompatClient::invalidateStream(AudioSystem::stream_type stream)
+{
+ return mServiceOps->invalidate_stream(mService, (audio_stream_type_t)stream);
+}
+
+status_t AudioPolicyCompatClient::moveEffects(int session, audio_io_handle_t srcOutput,
+ audio_io_handle_t dstOutput)
+{
+ return mServiceOps->move_effects(mService, session, srcOutput, dstOutput);
+}
+
+String8 AudioPolicyCompatClient::getParameters(audio_io_handle_t ioHandle, const String8& keys)
+{
+ char *str;
+ String8 out_str8;
+
+ str = mServiceOps->get_parameters(mService, ioHandle, keys.string());
+ out_str8 = String8(str);
+ free(str);
+
+ return out_str8;
+}
+
+void AudioPolicyCompatClient::setParameters(audio_io_handle_t ioHandle,
+ const String8& keyValuePairs,
+ int delayMs)
+{
+ mServiceOps->set_parameters(mService, ioHandle, keyValuePairs.string(),
+ delayMs);
+}
+
+status_t AudioPolicyCompatClient::setStreamVolume(
+ AudioSystem::stream_type stream,
+ float volume,
+ audio_io_handle_t output,
+ int delayMs)
+{
+ return mServiceOps->set_stream_volume(mService, (audio_stream_type_t)stream,
+ volume, output, delayMs);
+}
+
+status_t AudioPolicyCompatClient::startTone(ToneGenerator::tone_type tone,
+ AudioSystem::stream_type stream)
+{
+ return mServiceOps->start_tone(mService,
+ AUDIO_POLICY_TONE_IN_CALL_NOTIFICATION,
+ (audio_stream_type_t)stream);
+}
+
+status_t AudioPolicyCompatClient::stopTone()
+{
+ return mServiceOps->stop_tone(mService);
+}
+
+status_t AudioPolicyCompatClient::setVoiceVolume(float volume, int delayMs)
+{
+ return mServiceOps->set_voice_volume(mService, volume, delayMs);
+}
+
+}; // namespace android_audio_legacy
diff --git a/legacy_hal/AudioPolicyCompatClient.h b/legacy_hal/AudioPolicyCompatClient.h
new file mode 100755
index 0000000..19f76e1
--- /dev/null
+++ b/legacy_hal/AudioPolicyCompatClient.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2011 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_AUDIOPOLICYCLIENTLEGACY_H
+#define ANDROID_AUDIOPOLICYCLIENTLEGACY_H
+
+#include <system/audio.h>
+#include <system/audio_policy.h>
+#include <hardware/audio_policy.h>
+
+#include <hardware_legacy/AudioSystemLegacy.h>
+#include <hardware_legacy/AudioPolicyInterface.h>
+
+/************************************/
+/* FOR BACKWARDS COMPATIBILITY ONLY */
+/************************************/
+namespace android_audio_legacy {
+
+class AudioPolicyCompatClient : public AudioPolicyClientInterface {
+public:
+ AudioPolicyCompatClient(struct audio_policy_service_ops *serviceOps,
+ void *service) :
+ mServiceOps(serviceOps) , mService(service) {}
+
+ virtual audio_module_handle_t loadHwModule(const char *moduleName);
+
+ virtual audio_io_handle_t openOutput(audio_module_handle_t module,
+ audio_devices_t *pDevices,
+ uint32_t *pSamplingRate,
+ audio_format_t *pFormat,
+ audio_channel_mask_t *pChannelMask,
+ uint32_t *pLatencyMs,
+ audio_output_flags_t flags,
+ const audio_offload_info_t *offloadInfo);
+ 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(audio_module_handle_t module,
+ audio_devices_t *pDevices,
+ uint32_t *pSamplingRate,
+ audio_format_t *pFormat,
+ audio_channel_mask_t *pChannelMask);
+ virtual status_t closeInput(audio_io_handle_t input);
+ virtual status_t invalidateStream(AudioSystem::stream_type stream);
+ virtual status_t moveEffects(int session,
+ audio_io_handle_t srcOutput,
+ audio_io_handle_t dstOutput);
+
+ virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys);
+ virtual void setParameters(audio_io_handle_t ioHandle,
+ const String8& keyValuePairs,
+ int delayMs = 0);
+ virtual status_t setStreamVolume(AudioSystem::stream_type stream,
+ float volume,
+ audio_io_handle_t output,
+ int delayMs = 0);
+ 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:
+ struct audio_policy_service_ops* mServiceOps;
+ void* mService;
+};
+
+}; // namespace android_audio_legacy
+
+#endif // ANDROID_AUDIOPOLICYCLIENTLEGACY_H
diff --git a/legacy_hal/AudioPolicyManagerBase.cpp b/legacy_hal/AudioPolicyManagerBase.cpp
new file mode 100755
index 0000000..cf7daed
--- /dev/null
+++ b/legacy_hal/AudioPolicyManagerBase.cpp
@@ -0,0 +1,4411 @@
+/*
+ * 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
+
+//#define VERY_VERBOSE_LOGGING
+#ifdef VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+// A device mask for all audio input devices that are considered "virtual" when evaluating
+// active inputs in getActiveInput()
+#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL AUDIO_DEVICE_IN_REMOTE_SUBMIX
+// A device mask for all audio output devices that are considered "remote" when evaluating
+// active output devices in isStreamActiveRemotely()
+#define APM_AUDIO_OUT_DEVICE_REMOTE_ALL AUDIO_DEVICE_OUT_REMOTE_SUBMIX
+
+#include <inttypes.h>
+#include <math.h>
+
+#include <cutils/properties.h>
+#include <utils/Log.h>
+
+#include <hardware/audio.h>
+#include <hardware/audio_effect.h>
+#include <hardware_legacy/audio_policy_conf.h>
+#include <hardware_legacy/AudioPolicyManagerBase.h>
+#include "AudioUsbAudioHardware.h"
+
+namespace android_audio_legacy {
+
+// ----------------------------------------------------------------------------
+// AudioPolicyInterface implementation
+// ----------------------------------------------------------------------------
+
+status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device,
+ AudioSystem::device_connection_state state,
+ const char *device_address)
+{
+ ALOGV("setDeviceConnectionState() device: 0x%X, state %d, address %s", device, state, device_address);
+
+ // connect/disconnect only 1 device at a time
+ if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE;
+
+ if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) {
+ ALOGE("setDeviceConnectionState() invalid address: %s", device_address);
+ return BAD_VALUE;
+ }
+
+ // handle output devices
+ if (audio_is_output_device(device)) {
+ SortedVector <audio_io_handle_t> outputs;
+
+ if (!mHasA2dp && audio_is_a2dp_out_device(device)) {
+ ALOGE("setDeviceConnectionState() invalid A2DP device: %x", device);
+ return BAD_VALUE;
+ }
+ if (!mHasUsb && audio_is_usb_out_device(device)) {
+ ALOGE("setDeviceConnectionState() invalid USB audio device: %x", device);
+ return BAD_VALUE;
+ }
+ if (!mHasRemoteSubmix && audio_is_remote_submix_device((audio_devices_t)device)) {
+ ALOGE("setDeviceConnectionState() invalid remote submix audio device: %x", device);
+ return BAD_VALUE;
+ }
+
+ // save a copy of the opened output descriptors before any output is opened or closed
+ // by checkOutputsForDevice(). This will be needed by checkOutputForAllStrategies()
+ mPreviousOutputs = mOutputs;
+ String8 paramStr;
+ switch (state)
+ {
+ // handle output device connection
+ case AudioSystem::DEVICE_STATE_AVAILABLE:
+ if (mAvailableOutputDevices & device) {
+ ALOGW("setDeviceConnectionState() device already connected: %x", device);
+ return INVALID_OPERATION;
+ }
+ ALOGV("setDeviceConnectionState() connecting device %x", device);
+
+ if (mHasA2dp && audio_is_a2dp_out_device(device)) {
+ // handle A2DP device connection
+ AudioParameter param;
+ param.add(String8(AUDIO_PARAMETER_A2DP_SINK_ADDRESS), String8(device_address));
+ paramStr = param.toString();
+ } else if (mHasUsb && audio_is_usb_out_device(device)) {
+ // handle USB device connection
+ paramStr = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+ }
+
+ if (checkOutputsForDevice(device, state, outputs, paramStr) != NO_ERROR) {
+ return INVALID_OPERATION;
+ }
+ ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %zu outputs",
+ outputs.size());
+ // register new device as available
+ mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices | device);
+
+ if (mHasA2dp && audio_is_a2dp_out_device(device)) {
+ // handle A2DP device connection
+ mA2dpDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+ mA2dpSuspended = false;
+ } else if (audio_is_bluetooth_sco_device(device)) {
+ // handle SCO device connection
+ mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+ } else if (mHasUsb && audio_is_usb_out_device(device)) {
+ // handle USB device connection
+ mUsbOutCardAndDevice = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+ }
+
+ break;
+ // handle output device disconnection
+ case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
+ if (!(mAvailableOutputDevices & device)) {
+ ALOGW("setDeviceConnectionState() device not connected: %x", device);
+ return INVALID_OPERATION;
+ }
+
+ ALOGV("setDeviceConnectionState() disconnecting device %x", device);
+ // remove device from available output devices
+ mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices & ~device);
+ checkOutputsForDevice(device, state, outputs, paramStr);
+
+ if (mHasA2dp && audio_is_a2dp_out_device(device)) {
+ // handle A2DP device disconnection
+ mA2dpDeviceAddress = "";
+ mA2dpSuspended = false;
+ } else if (audio_is_bluetooth_sco_device(device)) {
+ // handle SCO device disconnection
+ mScoDeviceAddress = "";
+ } else if (mHasUsb && audio_is_usb_out_device(device)) {
+ // handle USB device disconnection
+ mUsbOutCardAndDevice = "";
+ }
+ // not currently handling multiple simultaneous submixes: ignoring remote submix
+ // case and address
+ } break;
+
+ default:
+ ALOGE("setDeviceConnectionState() invalid state: %x", state);
+ return BAD_VALUE;
+ }
+
+ checkA2dpSuspend();
+ checkOutputForAllStrategies();
+ // outputs must be closed after checkOutputForAllStrategies() is executed
+ if (!outputs.isEmpty()) {
+ for (size_t i = 0; i < outputs.size(); i++) {
+ AudioOutputDescriptor *desc = mOutputs.valueFor(outputs[i]);
+ // close unused outputs after device disconnection or direct outputs that have been
+ // opened by checkOutputsForDevice() to query dynamic parameters
+ if ((state == AudioSystem::DEVICE_STATE_UNAVAILABLE) ||
+ (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) &&
+ (desc->mDirectOpenCount == 0))) {
+ closeOutput(outputs[i]);
+ }
+ }
+ }
+
+ updateDevicesAndOutputs();
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ // do not force device change on duplicated output because if device is 0, it will
+ // also force a device 0 for the two outputs it is duplicated to which may override
+ // a valid device selection on those outputs.
+ setOutputDevice(mOutputs.keyAt(i),
+ getNewDevice(mOutputs.keyAt(i), true /*fromCache*/),
+ !mOutputs.valueAt(i)->isDuplicated(),
+ 0);
+ }
+
+ return NO_ERROR;
+ } // end if is output device
+
+ // handle input devices
+ if (audio_is_input_device(device)) {
+ SortedVector <audio_io_handle_t> inputs;
+
+ String8 paramStr;
+ switch (state)
+ {
+ // handle input device connection
+ case AudioSystem::DEVICE_STATE_AVAILABLE: {
+ if (mAvailableInputDevices & device) {
+ ALOGW("setDeviceConnectionState() device already connected: %d", device);
+ return INVALID_OPERATION;
+ }
+
+ if (mHasUsb && audio_is_usb_in_device(device)) {
+ // handle USB device connection
+ paramStr = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+ } else if (mHasA2dp && audio_is_a2dp_in_device(device)) {
+ // handle A2DP device connection
+ AudioParameter param;
+ param.add(String8(AUDIO_PARAMETER_A2DP_SOURCE_ADDRESS), String8(device_address));
+ paramStr = param.toString();
+ }
+
+ if (checkInputsForDevice(device, state, inputs, paramStr) != NO_ERROR) {
+ return INVALID_OPERATION;
+ }
+ mAvailableInputDevices = mAvailableInputDevices | (device & ~AUDIO_DEVICE_BIT_IN);
+ }
+ break;
+
+ // handle input device disconnection
+ case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
+ if (!(mAvailableInputDevices & device)) {
+ ALOGW("setDeviceConnectionState() device not connected: %d", device);
+ return INVALID_OPERATION;
+ }
+ checkInputsForDevice(device, state, inputs, paramStr);
+ mAvailableInputDevices = (audio_devices_t) (mAvailableInputDevices & ~device);
+ } break;
+
+ default:
+ ALOGE("setDeviceConnectionState() invalid state: %x", state);
+ return BAD_VALUE;
+ }
+
+ closeAllInputs();
+
+ return NO_ERROR;
+ } // end if is input device
+
+ ALOGW("setDeviceConnectionState() invalid device: %x", device);
+ return BAD_VALUE;
+}
+
+AudioSystem::device_connection_state AudioPolicyManagerBase::getDeviceConnectionState(audio_devices_t device,
+ const char *device_address)
+{
+ AudioSystem::device_connection_state state = AudioSystem::DEVICE_STATE_UNAVAILABLE;
+ String8 address = String8(device_address);
+ if (audio_is_output_device(device)) {
+ if (device & mAvailableOutputDevices) {
+ if (audio_is_a2dp_out_device(device) &&
+ (!mHasA2dp || (address != "" && mA2dpDeviceAddress != address))) {
+ return state;
+ }
+ if (audio_is_bluetooth_sco_device(device) &&
+ address != "" && mScoDeviceAddress != address) {
+ return state;
+ }
+ if (audio_is_usb_out_device(device) &&
+ (!mHasUsb || (address != "" && mUsbOutCardAndDevice != address))) {
+ ALOGE("getDeviceConnectionState() invalid device: %x", device);
+ return state;
+ }
+ if (audio_is_remote_submix_device((audio_devices_t)device) && !mHasRemoteSubmix) {
+ return state;
+ }
+ state = AudioSystem::DEVICE_STATE_AVAILABLE;
+ }
+ } else if (audio_is_input_device(device)) {
+ if (device & mAvailableInputDevices) {
+ state = AudioSystem::DEVICE_STATE_AVAILABLE;
+ }
+ }
+
+ return state;
+}
+
+void AudioPolicyManagerBase::setPhoneState(int state)
+{
+ ALOGV("setPhoneState() state %d", state);
+ audio_devices_t newDevice = AUDIO_DEVICE_NONE;
+ if (state < 0 || state >= AudioSystem::NUM_MODES) {
+ ALOGW("setPhoneState() invalid state %d", state);
+ return;
+ }
+
+ if (state == mPhoneState ) {
+ ALOGW("setPhoneState() setting same state %d", state);
+ return;
+ }
+
+ // if leaving call state, handle special case of active streams
+ // pertaining to sonification strategy see handleIncallSonification()
+ if (isInCall()) {
+ ALOGV("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 (!isStateInCall(oldState) && isStateInCall(state)) {
+ ALOGV(" Entering call in setPhoneState()");
+ // force routing command to audio hardware when starting a call
+ // even if no device change is needed
+ force = true;
+ for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
+ mStreams[AUDIO_STREAM_DTMF].mVolumeCurve[j] =
+ sVolumeProfiles[AUDIO_STREAM_VOICE_CALL][j];
+ }
+ } else if (isStateInCall(oldState) && !isStateInCall(state)) {
+ ALOGV(" Exiting call in setPhoneState()");
+ // force routing command to audio hardware when exiting a call
+ // even if no device change is needed
+ force = true;
+ for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
+ mStreams[AUDIO_STREAM_DTMF].mVolumeCurve[j] =
+ sVolumeProfiles[AUDIO_STREAM_DTMF][j];
+ }
+ } else if (isStateInCall(state) && (state != oldState)) {
+ ALOGV(" Switching between telephony and VoIP in setPhoneState()");
+ // force routing command to audio hardware when switching between telephony and VoIP
+ // even if no device change is needed
+ force = true;
+ }
+
+ // check for device and output changes triggered by new phone state
+ newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/);
+ checkA2dpSuspend();
+ checkOutputForAllStrategies();
+ updateDevicesAndOutputs();
+
+ AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mPrimaryOutput);
+
+ // force routing command to audio hardware when ending call
+ // even if no device change is needed
+ if (isStateInCall(oldState) && newDevice == AUDIO_DEVICE_NONE) {
+ 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 (isStateInCall(state) && 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, mPrimaryOutput);
+ }
+
+ if (isStateInCall(state)) {
+ nsecs_t sysTime = systemTime();
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+ // mute media and sonification strategies and delay device switch by the largest
+ // latency of any output where either strategy is active.
+ // This avoid sending the ring tone or music tail into the earpiece or headset.
+ if ((desc->isStrategyActive(STRATEGY_MEDIA,
+ SONIFICATION_HEADSET_MUSIC_DELAY,
+ sysTime) ||
+ desc->isStrategyActive(STRATEGY_SONIFICATION,
+ SONIFICATION_HEADSET_MUSIC_DELAY,
+ sysTime)) &&
+ (delayMs < (int)desc->mLatency*2)) {
+ delayMs = desc->mLatency*2;
+ }
+ setStrategyMute(STRATEGY_MEDIA, true, mOutputs.keyAt(i));
+ setStrategyMute(STRATEGY_MEDIA, false, mOutputs.keyAt(i), MUTE_TIME_MS,
+ getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/));
+ setStrategyMute(STRATEGY_SONIFICATION, true, mOutputs.keyAt(i));
+ setStrategyMute(STRATEGY_SONIFICATION, false, mOutputs.keyAt(i), MUTE_TIME_MS,
+ getDeviceForStrategy(STRATEGY_SONIFICATION, true /*fromCache*/));
+ }
+ }
+
+ // change routing is necessary
+ setOutputDevice(mPrimaryOutput, newDevice, force, delayMs);
+
+ // if entering in call state, handle special case of active streams
+ // pertaining to sonification strategy see handleIncallSonification()
+ if (isStateInCall(state)) {
+ ALOGV("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, mPrimaryOutput, 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 &&
+ isStreamActive(AudioSystem::MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY)) {
+ mLimitRingtoneVolume = true;
+ } else {
+ mLimitRingtoneVolume = false;
+ }
+}
+
+void AudioPolicyManagerBase::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
+{
+ ALOGV("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) {
+ ALOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config);
+ return;
+ }
+ forceVolumeReeval = true;
+ 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_ANALOG_DOCK &&
+ config != AudioSystem::FORCE_DIGITAL_DOCK && config != AudioSystem::FORCE_NONE &&
+ config != AudioSystem::FORCE_NO_BT_A2DP) {
+ ALOGW("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) {
+ ALOGW("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 &&
+ config != AudioSystem::FORCE_ANALOG_DOCK &&
+ config != AudioSystem::FORCE_DIGITAL_DOCK) {
+ ALOGW("setForceUse() invalid config %d for FOR_DOCK", config);
+ }
+ forceVolumeReeval = true;
+ mForceUse[usage] = config;
+ break;
+ case AudioSystem::FOR_SYSTEM:
+ if (config != AudioSystem::FORCE_NONE &&
+ config != AudioSystem::FORCE_SYSTEM_ENFORCED) {
+ ALOGW("setForceUse() invalid config %d for FOR_SYSTEM", config);
+ }
+ forceVolumeReeval = true;
+ mForceUse[usage] = config;
+ break;
+ default:
+ ALOGW("setForceUse() invalid usage %d", usage);
+ break;
+ }
+
+ // check for device and output changes triggered by new force usage
+ checkA2dpSuspend();
+ checkOutputForAllStrategies();
+ updateDevicesAndOutputs();
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ audio_io_handle_t output = mOutputs.keyAt(i);
+ audio_devices_t newDevice = getNewDevice(output, true /*fromCache*/);
+ setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE));
+ if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) {
+ applyStreamVolumes(output, newDevice, 0, true);
+ }
+ }
+
+ audio_io_handle_t activeInput = getActiveInput();
+ if (activeInput != 0) {
+ AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
+ audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+ if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
+ ALOGV("setForceUse() 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());
+ }
+ }
+
+}
+
+AudioSystem::forced_config AudioPolicyManagerBase::getForceUse(AudioSystem::force_use usage)
+{
+ return mForceUse[usage];
+}
+
+void AudioPolicyManagerBase::setSystemProperty(const char* property, const char* value)
+{
+ ALOGV("setSystemProperty() property %s, value %s", property, value);
+}
+
+// Find a direct output profile compatible with the parameters passed, even if the input flags do
+// not explicitly request a direct output
+AudioPolicyManagerBase::IOProfile *AudioPolicyManagerBase::getProfileForDirectOutput(
+ audio_devices_t device,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_output_flags_t flags)
+{
+ for (size_t i = 0; i < mHwModules.size(); i++) {
+ if (mHwModules[i]->mHandle == 0) {
+ continue;
+ }
+ for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) {
+ IOProfile *profile = mHwModules[i]->mOutputProfiles[j];
+ if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+ if (profile->isCompatibleProfile(device, samplingRate, format,
+ channelMask,
+ AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
+ if (mAvailableOutputDevices & profile->mSupportedDevices) {
+ return mHwModules[i]->mOutputProfiles[j];
+ }
+ }
+ } else {
+ if (profile->isCompatibleProfile(device, samplingRate, format,
+ channelMask,
+ AUDIO_OUTPUT_FLAG_DIRECT)) {
+ if (mAvailableOutputDevices & profile->mSupportedDevices) {
+ return mHwModules[i]->mOutputProfiles[j];
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type stream,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ AudioSystem::output_flags flags,
+ const audio_offload_info_t *offloadInfo)
+{
+ audio_io_handle_t output = 0;
+ uint32_t latency = 0;
+ routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream);
+ audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
+ ALOGV("getOutput() device %d, stream %d, samplingRate %d, format %x, channelMask %x, flags %x",
+ device, stream, samplingRate, format, channelMask, flags);
+
+#ifdef AUDIO_POLICY_TEST
+ if (mCurOutput != 0) {
+ ALOGV("getOutput() test output mCurOutput %d, samplingRate %d, format %d, channelMask %x, mDirectOutput %d",
+ mCurOutput, mTestSamplingRate, mTestFormat, mTestChannels, mDirectOutput);
+
+ if (mTestOutputs[mCurOutput] == 0) {
+ ALOGV("getOutput() opening test output");
+ AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(NULL);
+ outputDesc->mDevice = mTestDevice;
+ outputDesc->mSamplingRate = mTestSamplingRate;
+ outputDesc->mFormat = mTestFormat;
+ outputDesc->mChannelMask = mTestChannels;
+ outputDesc->mLatency = mTestLatencyMs;
+ outputDesc->mFlags = (audio_output_flags_t)(mDirectOutput ? AudioSystem::OUTPUT_FLAG_DIRECT : 0);
+ outputDesc->mRefCount[stream] = 0;
+ mTestOutputs[mCurOutput] = mpClientInterface->openOutput(0, &outputDesc->mDevice,
+ &outputDesc->mSamplingRate,
+ &outputDesc->mFormat,
+ &outputDesc->mChannelMask,
+ &outputDesc->mLatency,
+ outputDesc->mFlags,
+ offloadInfo);
+ 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
+ //force direct flag if offload flag is set: offloading implies a direct output stream
+ // and all common behaviors are driven by checking only the direct flag
+ // this should normally be set appropriately in the policy configuration file
+ if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+ flags = (AudioSystem::output_flags)(flags | AUDIO_OUTPUT_FLAG_DIRECT);
+ }
+
+ // Do not allow offloading if one non offloadable effect is enabled. This prevents from
+ // creating an offloaded track and tearing it down immediately after start when audioflinger
+ // detects there is an active non offloadable effect.
+ // FIXME: We should check the audio session here but we do not have it in this context.
+ // This may prevent offloading in rare situations where effects are left active by apps
+ // in the background.
+ IOProfile *profile = NULL;
+ if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) ||
+ !isNonOffloadableEffectEnabled()) {
+ profile = getProfileForDirectOutput(device,
+ samplingRate,
+ format,
+ channelMask,
+ (audio_output_flags_t)flags);
+ }
+
+ if (profile != NULL) {
+ AudioOutputDescriptor *outputDesc = NULL;
+
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+ if (!desc->isDuplicated() && (profile == desc->mProfile)) {
+ outputDesc = desc;
+ // reuse direct output if currently open and configured with same parameters
+ if ((samplingRate == outputDesc->mSamplingRate) &&
+ (format == outputDesc->mFormat) &&
+ (channelMask == outputDesc->mChannelMask)) {
+ outputDesc->mDirectOpenCount++;
+ ALOGV("getOutput() reusing direct output %d", mOutputs.keyAt(i));
+ return mOutputs.keyAt(i);
+ }
+ }
+ }
+ // close direct output if currently open and configured with different parameters
+ if (outputDesc != NULL) {
+ closeOutput(outputDesc->mId);
+ }
+ outputDesc = new AudioOutputDescriptor(profile);
+ outputDesc->mDevice = device;
+ outputDesc->mSamplingRate = samplingRate;
+ outputDesc->mFormat = format;
+ outputDesc->mChannelMask = channelMask;
+ outputDesc->mLatency = 0;
+ outputDesc->mFlags =(audio_output_flags_t) (outputDesc->mFlags | flags);
+ outputDesc->mRefCount[stream] = 0;
+ outputDesc->mStopTime[stream] = 0;
+ outputDesc->mDirectOpenCount = 1;
+ output = mpClientInterface->openOutput(profile->mModule->mHandle,
+ &outputDesc->mDevice,
+ &outputDesc->mSamplingRate,
+ &outputDesc->mFormat,
+ &outputDesc->mChannelMask,
+ &outputDesc->mLatency,
+ outputDesc->mFlags,
+ offloadInfo);
+
+ // only accept an output with the requested parameters
+ if (output == 0 ||
+ (samplingRate != 0 && samplingRate != outputDesc->mSamplingRate) ||
+ (format != AUDIO_FORMAT_DEFAULT && format != outputDesc->mFormat) ||
+ (channelMask != 0 && channelMask != outputDesc->mChannelMask)) {
+ ALOGV("getOutput() failed opening direct output: output %d samplingRate %d %d,"
+ "format %d %d, channelMask %04x %04x", output, samplingRate,
+ outputDesc->mSamplingRate, format, outputDesc->mFormat, channelMask,
+ outputDesc->mChannelMask);
+ if (output != 0) {
+ mpClientInterface->closeOutput(output);
+ }
+ delete outputDesc;
+ return 0;
+ }
+ audio_io_handle_t srcOutput = getOutputForEffect();
+ addOutput(output, outputDesc);
+ audio_io_handle_t dstOutput = getOutputForEffect();
+ if (dstOutput == output) {
+ mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, srcOutput, dstOutput);
+ }
+ mPreviousOutputs = mOutputs;
+ ALOGV("getOutput() returns new direct output %d", output);
+ return output;
+ }
+
+ // ignoring channel mask due to downmix capability in mixer
+
+ // open a non direct output
+
+ // for non direct outputs, only PCM is supported
+ if (audio_is_linear_pcm(format)) {
+ // get which output is suitable for the specified stream. The actual
+ // routing change will happen when startOutput() will be called
+ SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs);
+
+ output = selectOutput(outputs, flags);
+ }
+
+ ALOGW_IF((output == 0), "getOutput() could not find output for stream %d, samplingRate %d,"
+ "format %d, channels %x, flags %x", stream, samplingRate, format, channelMask, flags);
+
+ ALOGV("getOutput() returns output %d", output);
+
+ return output;
+}
+
+audio_io_handle_t AudioPolicyManagerBase::selectOutput(const SortedVector<audio_io_handle_t>& outputs,
+ AudioSystem::output_flags flags)
+{
+ // select one output among several that provide a path to a particular device or set of
+ // devices (the list was previously build by getOutputsForDevice()).
+ // The priority is as follows:
+ // 1: the output with the highest number of requested policy flags
+ // 2: the primary output
+ // 3: the first output in the list
+
+ if (outputs.size() == 0) {
+ return 0;
+ }
+ if (outputs.size() == 1) {
+ return outputs[0];
+ }
+
+ int maxCommonFlags = 0;
+ audio_io_handle_t outputFlags = 0;
+ audio_io_handle_t outputPrimary = 0;
+
+ for (size_t i = 0; i < outputs.size(); i++) {
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(outputs[i]);
+ if (!outputDesc->isDuplicated()) {
+ int commonFlags = (int)AudioSystem::popCount(outputDesc->mProfile->mFlags & flags);
+ if (commonFlags > maxCommonFlags) {
+ outputFlags = outputs[i];
+ maxCommonFlags = commonFlags;
+ ALOGV("selectOutput() commonFlags for output %d, %04x", outputs[i], commonFlags);
+ }
+ if (outputDesc->mProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
+ outputPrimary = outputs[i];
+ }
+ }
+ }
+
+ if (outputFlags != 0) {
+ return outputFlags;
+ }
+ if (outputPrimary != 0) {
+ return outputPrimary;
+ }
+
+ return outputs[0];
+}
+
+status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output,
+ AudioSystem::stream_type stream,
+ int session)
+{
+ ALOGV("startOutput() output %d, stream %d, session %d", output, stream, session);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ ALOGW("startOutput() unknown output %d", output);
+ return BAD_VALUE;
+ }
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+
+ // increment 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
+ // necessary for a correct control of hardware output routing by startOutput() and stopOutput()
+ outputDesc->changeRefCount(stream, 1);
+
+ if (outputDesc->mRefCount[stream] == 1) {
+ audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);
+ routing_strategy strategy = getStrategy(stream);
+ bool shouldWait = (strategy == STRATEGY_SONIFICATION) ||
+ (strategy == STRATEGY_SONIFICATION_RESPECTFUL);
+ uint32_t waitMs = 0;
+ bool force = false;
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+ if (desc != outputDesc) {
+ // force a device change if any other output is managed by the same hw
+ // module and has a current device selection that differs from selected device.
+ // In this case, the audio HAL must receive the new device selection so that it can
+ // change the device currently selected by the other active output.
+ if (outputDesc->sharesHwModuleWith(desc) &&
+ desc->device() != newDevice) {
+ force = true;
+ }
+ // wait for audio on other active outputs to be presented when starting
+ // a notification so that audio focus effect can propagate.
+ uint32_t latency = desc->latency();
+ if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) {
+ waitMs = latency;
+ }
+ }
+ }
+ uint32_t muteWaitMs = setOutputDevice(output, newDevice, force);
+
+ // handle special case for sonification while in call
+ if (isInCall()) {
+ handleIncallSonification(stream, true, false);
+ }
+
+ // apply volume rules for current stream and device if necessary
+ checkAndSetVolume(stream,
+ mStreams[stream].getVolumeIndex(newDevice),
+ output,
+ newDevice);
+
+ // update the outputs if starting an output with a stream that can affect notification
+ // routing
+ handleNotificationRoutingForStream(stream);
+ if (waitMs > muteWaitMs) {
+ usleep((waitMs - muteWaitMs) * 2 * 1000);
+ }
+ }
+ return NO_ERROR;
+}
+
+
+status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output,
+ AudioSystem::stream_type stream,
+ int session)
+{
+ ALOGV("stopOutput() output %d, stream %d, session %d", output, stream, session);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ ALOGW("stopOutput() unknown output %d", output);
+ return BAD_VALUE;
+ }
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+
+ // handle special case for sonification while in call
+ if (isInCall()) {
+ 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 stream was stopped - see isStreamActive()
+ if (outputDesc->mRefCount[stream] == 0) {
+ outputDesc->mStopTime[stream] = systemTime();
+ audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);
+ // delay the device switch by twice the latency because stopOutput() is executed when
+ // the track stop() command is received and at that time the audio track buffer can
+ // still contain data that needs to be drained. The latency only covers the audio HAL
+ // and kernel buffers. Also the latency does not always include additional delay in the
+ // audio path (audio DSP, CODEC ...)
+ setOutputDevice(output, newDevice, false, outputDesc->mLatency*2);
+
+ // force restoring the device selection on other active outputs if it differs from the
+ // one being selected for this output
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ audio_io_handle_t curOutput = mOutputs.keyAt(i);
+ AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+ if (curOutput != output &&
+ desc->isActive() &&
+ outputDesc->sharesHwModuleWith(desc) &&
+ (newDevice != desc->device())) {
+ setOutputDevice(curOutput,
+ getNewDevice(curOutput, false /*fromCache*/),
+ true,
+ outputDesc->mLatency*2);
+ }
+ }
+ // update the outputs if stopping one with a stream that can affect notification routing
+ handleNotificationRoutingForStream(stream);
+ }
+ return NO_ERROR;
+ } else {
+ ALOGW("stopOutput() refcount is already 0 for output %d", output);
+ return INVALID_OPERATION;
+ }
+}
+
+void AudioPolicyManagerBase::releaseOutput(audio_io_handle_t output)
+{
+ ALOGV("releaseOutput() %d", output);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ ALOGW("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->isActive()) {
+ mpClientInterface->closeOutput(output);
+ delete mOutputs.valueAt(index);
+ mOutputs.removeItem(output);
+ mTestOutputs[testIndex] = 0;
+ }
+ return;
+ }
+#endif //AUDIO_POLICY_TEST
+
+ AudioOutputDescriptor *desc = mOutputs.valueAt(index);
+ if (desc->mFlags & AudioSystem::OUTPUT_FLAG_DIRECT) {
+ if (desc->mDirectOpenCount <= 0) {
+ ALOGW("releaseOutput() invalid open count %d for output %d",
+ desc->mDirectOpenCount, output);
+ return;
+ }
+ if (--desc->mDirectOpenCount == 0) {
+ closeOutput(output);
+ // If effects where present on the output, audioflinger moved them to the primary
+ // output by default: move them back to the appropriate output.
+ audio_io_handle_t dstOutput = getOutputForEffect();
+ if (dstOutput != mPrimaryOutput) {
+ mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, mPrimaryOutput, dstOutput);
+ }
+ }
+ }
+}
+
+
+audio_io_handle_t AudioPolicyManagerBase::getInput(int inputSource,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ AudioSystem::audio_in_acoustics acoustics)
+{
+ audio_io_handle_t input = 0;
+ audio_devices_t device = getDeviceForInputSource(inputSource);
+
+ ALOGV("getInput() inputSource %d, samplingRate %d, format %d, channelMask %x, acoustics %x",
+ inputSource, samplingRate, format, channelMask, acoustics);
+
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGW("getInput() could not find device for inputSource %d", inputSource);
+ return 0;
+ }
+
+ // adapt channel selection to input source
+ switch(inputSource) {
+ case AUDIO_SOURCE_VOICE_UPLINK:
+ channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK;
+ break;
+ case AUDIO_SOURCE_VOICE_DOWNLINK:
+ channelMask = AUDIO_CHANNEL_IN_VOICE_DNLINK;
+ break;
+ case AUDIO_SOURCE_VOICE_CALL:
+ channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK | AUDIO_CHANNEL_IN_VOICE_DNLINK;
+ break;
+ default:
+ break;
+ }
+
+ IOProfile *profile = getInputProfile(device,
+ samplingRate,
+ format,
+ channelMask);
+ if (profile == NULL) {
+ ALOGW("getInput() could not find profile for device 0x%X, samplingRate %d, format %d, "
+ "channelMask 0x%X",
+ device, samplingRate, format, channelMask);
+ return 0;
+ }
+
+ if (profile->mModule->mHandle == 0) {
+ ALOGE("getInput(): HW module %s not opened", profile->mModule->mName);
+ return 0;
+ }
+
+ AudioInputDescriptor *inputDesc = new AudioInputDescriptor(profile);
+
+ inputDesc->mInputSource = inputSource;
+ inputDesc->mDevice = device;
+ inputDesc->mSamplingRate = samplingRate;
+ inputDesc->mFormat = format;
+ inputDesc->mChannelMask = channelMask;
+ inputDesc->mRefCount = 0;
+
+ input = mpClientInterface->openInput(profile->mModule->mHandle,
+ &inputDesc->mDevice,
+ &inputDesc->mSamplingRate,
+ &inputDesc->mFormat,
+ &inputDesc->mChannelMask);
+
+ // only accept input with the exact requested set of parameters
+ if (input == 0 ||
+ (samplingRate != inputDesc->mSamplingRate) ||
+ (format != inputDesc->mFormat) ||
+ (channelMask != inputDesc->mChannelMask)) {
+ ALOGI("getInput() failed opening input: samplingRate %d, format %d, channelMask 0x%X",
+ samplingRate, format, channelMask);
+ if (input != 0) {
+ mpClientInterface->closeInput(input);
+ }
+ delete inputDesc;
+ return 0;
+ }
+ addInput(input, inputDesc);
+
+ return input;
+}
+
+status_t AudioPolicyManagerBase::startInput(audio_io_handle_t input)
+{
+ ALOGV("startInput() input %d", input);
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ ALOGW("startInput() unknown 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 except if the active input
+ // uses AUDIO_SOURCE_HOTWORD in which case it is closed.
+ audio_io_handle_t activeInput = getActiveInput();
+ if (!isVirtualInputDevice(inputDesc->mDevice) && activeInput != 0) {
+ AudioInputDescriptor *activeDesc = mInputs.valueFor(activeInput);
+ if (activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) {
+ ALOGW("startInput() preempting already started low-priority input %d", activeInput);
+ stopInput(activeInput);
+ releaseInput(activeInput);
+ } else {
+ ALOGW("startInput() input %d failed: other input already started", input);
+ return INVALID_OPERATION;
+ }
+ }
+ }
+
+ audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+ if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
+ inputDesc->mDevice = newDevice;
+ }
+
+ // automatically enable the remote submix output when input is started
+ if (audio_is_remote_submix_device(inputDesc->mDevice)) {
+ setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ AudioSystem::DEVICE_STATE_AVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS);
+ }
+
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice);
+
+ int aliasSource = (inputDesc->mInputSource == AUDIO_SOURCE_HOTWORD) ?
+ AUDIO_SOURCE_VOICE_RECOGNITION : inputDesc->mInputSource;
+
+ param.addInt(String8(AudioParameter::keyInputSource), aliasSource);
+ ALOGV("AudioPolicyManager::startInput() input source = %d", inputDesc->mInputSource);
+
+ mpClientInterface->setParameters(input, param.toString());
+
+ inputDesc->mRefCount = 1;
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManagerBase::stopInput(audio_io_handle_t input)
+{
+ ALOGV("stopInput() input %d", input);
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ ALOGW("stopInput() unknown input %d", input);
+ return BAD_VALUE;
+ }
+ AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+
+ if (inputDesc->mRefCount == 0) {
+ ALOGW("stopInput() input %d already stopped", input);
+ return INVALID_OPERATION;
+ } else {
+ // automatically disable the remote submix output when input is stopped
+ if (audio_is_remote_submix_device(inputDesc->mDevice)) {
+ setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ AudioSystem::DEVICE_STATE_UNAVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS);
+ }
+
+ 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)
+{
+ ALOGV("releaseInput() %d", input);
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ ALOGW("releaseInput() releasing unknown input %d", input);
+ return;
+ }
+ mpClientInterface->closeInput(input);
+ delete mInputs.valueAt(index);
+ mInputs.removeItem(input);
+
+ ALOGV("releaseInput() exit");
+}
+
+void AudioPolicyManagerBase::closeAllInputs() {
+ for(size_t input_index = 0; input_index < mInputs.size(); input_index++) {
+ mpClientInterface->closeInput(mInputs.keyAt(input_index));
+ }
+ mInputs.clear();
+}
+
+void AudioPolicyManagerBase::initStreamVolume(AudioSystem::stream_type stream,
+ int indexMin,
+ int indexMax)
+{
+ ALOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
+ if (indexMin < 0 || indexMin >= indexMax) {
+ ALOGW("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,
+ audio_devices_t device)
+{
+
+ if ((index < mStreams[stream].mIndexMin) || (index > mStreams[stream].mIndexMax)) {
+ return BAD_VALUE;
+ }
+ if (!audio_is_output_device(device)) {
+ return BAD_VALUE;
+ }
+
+ // Force max volume if stream cannot be muted
+ if (!mStreams[stream].mCanBeMuted) index = mStreams[stream].mIndexMax;
+
+ ALOGV("setStreamVolumeIndex() stream %d, device %04x, index %d",
+ stream, device, index);
+
+ // if device is AUDIO_DEVICE_OUT_DEFAULT set default value and
+ // clear all device specific values
+ if (device == AUDIO_DEVICE_OUT_DEFAULT) {
+ mStreams[stream].mIndexCur.clear();
+ }
+ mStreams[stream].mIndexCur.add(device, 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++) {
+ audio_devices_t curDevice =
+ getDeviceForVolume(mOutputs.valueAt(i)->device());
+ if ((device == AUDIO_DEVICE_OUT_DEFAULT) || (device == curDevice)) {
+ status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice);
+ if (volStatus != NO_ERROR) {
+ status = volStatus;
+ }
+ }
+ }
+ return status;
+}
+
+status_t AudioPolicyManagerBase::getStreamVolumeIndex(AudioSystem::stream_type stream,
+ int *index,
+ audio_devices_t device)
+{
+ if (index == NULL) {
+ return BAD_VALUE;
+ }
+ if (!audio_is_output_device(device)) {
+ return BAD_VALUE;
+ }
+ // if device is AUDIO_DEVICE_OUT_DEFAULT, return volume for device corresponding to
+ // the strategy the stream belongs to.
+ if (device == AUDIO_DEVICE_OUT_DEFAULT) {
+ device = getDeviceForStrategy(getStrategy(stream), true /*fromCache*/);
+ }
+ device = getDeviceForVolume(device);
+
+ *index = mStreams[stream].getVolumeIndex(device);
+ ALOGV("getStreamVolumeIndex() stream %d device %08x index %d", stream, device, *index);
+ return NO_ERROR;
+}
+
+audio_io_handle_t AudioPolicyManagerBase::selectOutputForEffects(
+ const SortedVector<audio_io_handle_t>& outputs)
+{
+ // select one output among several suitable for global effects.
+ // The priority is as follows:
+ // 1: An offloaded output. If the effect ends up not being offloadable,
+ // AudioFlinger will invalidate the track and the offloaded output
+ // will be closed causing the effect to be moved to a PCM output.
+ // 2: A deep buffer output
+ // 3: the first output in the list
+
+ if (outputs.size() == 0) {
+ return 0;
+ }
+
+ audio_io_handle_t outputOffloaded = 0;
+ audio_io_handle_t outputDeepBuffer = 0;
+
+ for (size_t i = 0; i < outputs.size(); i++) {
+ AudioOutputDescriptor *desc = mOutputs.valueFor(outputs[i]);
+ ALOGV("selectOutputForEffects outputs[%zu] flags %x", i, desc->mFlags);
+ if ((desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+ outputOffloaded = outputs[i];
+ }
+ if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) != 0) {
+ outputDeepBuffer = outputs[i];
+ }
+ }
+
+ ALOGV("selectOutputForEffects outputOffloaded %d outputDeepBuffer %d",
+ outputOffloaded, outputDeepBuffer);
+ if (outputOffloaded != 0) {
+ return outputOffloaded;
+ }
+ if (outputDeepBuffer != 0) {
+ return outputDeepBuffer;
+ }
+
+ return outputs[0];
+}
+
+audio_io_handle_t AudioPolicyManagerBase::getOutputForEffect(const effect_descriptor_t *desc)
+{
+ // apply simple rule where global effects are attached to the same output as MUSIC streams
+
+ routing_strategy strategy = getStrategy(AudioSystem::MUSIC);
+ audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
+ SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevice(device, mOutputs);
+
+ audio_io_handle_t output = selectOutputForEffects(dstOutputs);
+ ALOGV("getOutputForEffect() got output %d for fx %s flags %x",
+ output, (desc == NULL) ? "unspecified" : desc->name, (desc == NULL) ? 0 : desc->flags);
+
+ return output;
+}
+
+status_t AudioPolicyManagerBase::registerEffect(const effect_descriptor_t *desc,
+ audio_io_handle_t io,
+ uint32_t strategy,
+ int session,
+ int id)
+{
+ ssize_t index = mOutputs.indexOfKey(io);
+ if (index < 0) {
+ index = mInputs.indexOfKey(io);
+ if (index < 0) {
+ ALOGW("registerEffect() unknown io %d", io);
+ return INVALID_OPERATION;
+ }
+ }
+
+ if (mTotalEffectsMemory + desc->memoryUsage > getMaxEffectsMemory()) {
+ ALOGW("registerEffect() memory limit exceeded for Fx %s, Memory %d KB",
+ desc->name, desc->memoryUsage);
+ return INVALID_OPERATION;
+ }
+ mTotalEffectsMemory += desc->memoryUsage;
+ ALOGV("registerEffect() effect %s, io %d, strategy %d session %d id %d",
+ desc->name, io, strategy, session, id);
+ ALOGV("registerEffect() memory %d, total memory %d", desc->memoryUsage, mTotalEffectsMemory);
+
+ EffectDescriptor *pDesc = new EffectDescriptor();
+ memcpy (&pDesc->mDesc, desc, sizeof(effect_descriptor_t));
+ pDesc->mIo = io;
+ pDesc->mStrategy = (routing_strategy)strategy;
+ pDesc->mSession = session;
+ pDesc->mEnabled = false;
+
+ mEffects.add(id, pDesc);
+
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManagerBase::unregisterEffect(int id)
+{
+ ssize_t index = mEffects.indexOfKey(id);
+ if (index < 0) {
+ ALOGW("unregisterEffect() unknown effect ID %d", id);
+ return INVALID_OPERATION;
+ }
+
+ EffectDescriptor *pDesc = mEffects.valueAt(index);
+
+ setEffectEnabled(pDesc, false);
+
+ if (mTotalEffectsMemory < pDesc->mDesc.memoryUsage) {
+ ALOGW("unregisterEffect() memory %d too big for total %d",
+ pDesc->mDesc.memoryUsage, mTotalEffectsMemory);
+ pDesc->mDesc.memoryUsage = mTotalEffectsMemory;
+ }
+ mTotalEffectsMemory -= pDesc->mDesc.memoryUsage;
+ ALOGV("unregisterEffect() effect %s, ID %d, memory %d total memory %d",
+ pDesc->mDesc.name, id, pDesc->mDesc.memoryUsage, mTotalEffectsMemory);
+
+ mEffects.removeItem(id);
+ delete pDesc;
+
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManagerBase::setEffectEnabled(int id, bool enabled)
+{
+ ssize_t index = mEffects.indexOfKey(id);
+ if (index < 0) {
+ ALOGW("unregisterEffect() unknown effect ID %d", id);
+ return INVALID_OPERATION;
+ }
+
+ return setEffectEnabled(mEffects.valueAt(index), enabled);
+}
+
+status_t AudioPolicyManagerBase::setEffectEnabled(EffectDescriptor *pDesc, bool enabled)
+{
+ if (enabled == pDesc->mEnabled) {
+ ALOGV("setEffectEnabled(%s) effect already %s",
+ enabled?"true":"false", enabled?"enabled":"disabled");
+ return INVALID_OPERATION;
+ }
+
+ if (enabled) {
+ if (mTotalEffectsCpuLoad + pDesc->mDesc.cpuLoad > getMaxEffectsCpuLoad()) {
+ ALOGW("setEffectEnabled(true) CPU Load limit exceeded for Fx %s, CPU %f MIPS",
+ pDesc->mDesc.name, (float)pDesc->mDesc.cpuLoad/10);
+ return INVALID_OPERATION;
+ }
+ mTotalEffectsCpuLoad += pDesc->mDesc.cpuLoad;
+ ALOGV("setEffectEnabled(true) total CPU %d", mTotalEffectsCpuLoad);
+ } else {
+ if (mTotalEffectsCpuLoad < pDesc->mDesc.cpuLoad) {
+ ALOGW("setEffectEnabled(false) CPU load %d too high for total %d",
+ pDesc->mDesc.cpuLoad, mTotalEffectsCpuLoad);
+ pDesc->mDesc.cpuLoad = mTotalEffectsCpuLoad;
+ }
+ mTotalEffectsCpuLoad -= pDesc->mDesc.cpuLoad;
+ ALOGV("setEffectEnabled(false) total CPU %d", mTotalEffectsCpuLoad);
+ }
+ pDesc->mEnabled = enabled;
+ return NO_ERROR;
+}
+
+bool AudioPolicyManagerBase::isNonOffloadableEffectEnabled()
+{
+ for (size_t i = 0; i < mEffects.size(); i++) {
+ const EffectDescriptor * const pDesc = mEffects.valueAt(i);
+ if (pDesc->mEnabled && (pDesc->mStrategy == STRATEGY_MEDIA) &&
+ ((pDesc->mDesc.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) == 0)) {
+ ALOGV("isNonOffloadableEffectEnabled() non offloadable effect %s enabled on session %d",
+ pDesc->mDesc.name, pDesc->mSession);
+ return true;
+ }
+ }
+ return false;
+}
+bool AudioPolicyManagerBase::isStreamActive(int stream, uint32_t inPastMs) const
+{
+ nsecs_t sysTime = systemTime();
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ const AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i);
+ if (outputDesc->isStreamActive((AudioSystem::stream_type)stream, inPastMs, sysTime)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AudioPolicyManagerBase::isStreamActiveRemotely(int stream, uint32_t inPastMs) const
+{
+ nsecs_t sysTime = systemTime();
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ const AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i);
+ if (((outputDesc->device() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) != 0) &&
+ outputDesc->isStreamActive((AudioSystem::stream_type)stream, inPastMs, sysTime)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AudioPolicyManagerBase::isSourceActive(audio_source_t source) const
+{
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ const AudioInputDescriptor * inputDescriptor = mInputs.valueAt(i);
+ if ((inputDescriptor->mInputSource == (int)source ||
+ (source == (audio_source_t)AUDIO_SOURCE_VOICE_RECOGNITION &&
+ inputDescriptor->mInputSource == AUDIO_SOURCE_HOTWORD))
+ && (inputDescriptor->mRefCount > 0)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+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, " Primary Output: %d\n", mPrimaryOutput);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " A2DP device address: %s\n", mA2dpDeviceAddress.string());
+ result.append(buffer);
+ snprintf(buffer, SIZE, " SCO device address: %s\n", mScoDeviceAddress.string());
+ result.append(buffer);
+ snprintf(buffer, SIZE, " USB audio ALSA %s\n", mUsbOutCardAndDevice.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, " 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);
+ snprintf(buffer, SIZE, " Force use for system %d\n", mForceUse[AudioSystem::FOR_SYSTEM]);
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+
+
+ snprintf(buffer, SIZE, "\nHW Modules dump:\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < mHwModules.size(); i++) {
+ snprintf(buffer, SIZE, "- HW Module %zu:\n", i + 1);
+ write(fd, buffer, strlen(buffer));
+ mHwModules[i]->dump(fd);
+ }
+
+ 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 Can be muted Index Min Index Max Index Cur [device : index]...\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
+ snprintf(buffer, SIZE, " %02zu ", i);
+ write(fd, buffer, strlen(buffer));
+ mStreams[i].dump(fd);
+ }
+
+ snprintf(buffer, SIZE, "\nTotal Effects CPU: %f MIPS, Total Effects memory: %d KB\n",
+ (float)mTotalEffectsCpuLoad/10, mTotalEffectsMemory);
+ write(fd, buffer, strlen(buffer));
+
+ snprintf(buffer, SIZE, "Registered effects:\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < mEffects.size(); i++) {
+ snprintf(buffer, SIZE, "- Effect %d dump:\n", mEffects.keyAt(i));
+ write(fd, buffer, strlen(buffer));
+ mEffects.valueAt(i)->dump(fd);
+ }
+
+
+ return NO_ERROR;
+}
+
+// This function checks for the parameters which can be offloaded.
+// This can be enhanced depending on the capability of the DSP and policy
+// of the system.
+bool AudioPolicyManagerBase::isOffloadSupported(const audio_offload_info_t& offloadInfo)
+{
+ ALOGV("isOffloadSupported: SR=%u, CM=0x%x, Format=0x%x, StreamType=%d,"
+ " BitRate=%u, duration=%" PRId64 " us, has_video=%d",
+ offloadInfo.sample_rate, offloadInfo.channel_mask,
+ offloadInfo.format,
+ offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us,
+ offloadInfo.has_video);
+
+ // Check if offload has been disabled
+ char propValue[PROPERTY_VALUE_MAX];
+ if (property_get("audio.offload.disable", propValue, "0")) {
+ if (atoi(propValue) != 0) {
+ ALOGV("offload disabled by audio.offload.disable=%s", propValue );
+ return false;
+ }
+ }
+
+ // Check if stream type is music, then only allow offload as of now.
+ if (offloadInfo.stream_type != AUDIO_STREAM_MUSIC)
+ {
+ ALOGV("isOffloadSupported: stream_type != MUSIC, returning false");
+ return false;
+ }
+
+ //TODO: enable audio offloading with video when ready
+ if (offloadInfo.has_video)
+ {
+ ALOGV("isOffloadSupported: has_video == true, returning false");
+ return false;
+ }
+
+ //If duration is less than minimum value defined in property, return false
+ if (property_get("audio.offload.min.duration.secs", propValue, NULL)) {
+ if (offloadInfo.duration_us < (atoi(propValue) * 1000000 )) {
+ ALOGV("Offload denied by duration < audio.offload.min.duration.secs(=%s)", propValue);
+ return false;
+ }
+ } else if (offloadInfo.duration_us < OFFLOAD_DEFAULT_MIN_DURATION_SECS * 1000000) {
+ ALOGV("Offload denied by duration < default min(=%u)", OFFLOAD_DEFAULT_MIN_DURATION_SECS);
+ return false;
+ }
+
+ // Do not allow offloading if one non offloadable effect is enabled. This prevents from
+ // creating an offloaded track and tearing it down immediately after start when audioflinger
+ // detects there is an active non offloadable effect.
+ // FIXME: We should check the audio session here but we do not have it in this context.
+ // This may prevent offloading in rare situations where effects are left active by apps
+ // in the background.
+ if (isNonOffloadableEffectEnabled()) {
+ return false;
+ }
+ // See if there is a profile to support this.
+ // AUDIO_DEVICE_NONE
+ IOProfile *profile = getProfileForDirectOutput(AUDIO_DEVICE_NONE /*ignore device */,
+ offloadInfo.sample_rate,
+ offloadInfo.format,
+ offloadInfo.channel_mask,
+ AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
+ ALOGV("isOffloadSupported() profile %sfound", profile != NULL ? "" : "NOT ");
+ return (profile != NULL);
+}
+
+// ----------------------------------------------------------------------------
+// AudioPolicyManagerBase
+// ----------------------------------------------------------------------------
+
+AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface)
+ :
+#ifdef AUDIO_POLICY_TEST
+ Thread(false),
+#endif //AUDIO_POLICY_TEST
+ mPrimaryOutput((audio_io_handle_t)0),
+ mAvailableOutputDevices(AUDIO_DEVICE_NONE),
+ mPhoneState(AudioSystem::MODE_NORMAL),
+ mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
+ mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0),
+ mA2dpSuspended(false), mHasA2dp(false), mHasUsb(false), mHasRemoteSubmix(false),
+ mSpeakerDrcEnabled(false),isCaptureRateChange(false)
+{
+ mpClientInterface = clientInterface;
+
+ for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {
+ mForceUse[i] = AudioSystem::FORCE_NONE;
+ }
+
+ mA2dpDeviceAddress = String8("");
+ mScoDeviceAddress = String8("");
+ mUsbOutCardAndDevice = String8("");
+ mStreams[AudioSystem::MUSIC].mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT, mStreams[AudioSystem::MUSIC].mIndexMax);
+ if (loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE) != NO_ERROR) {
+ if (loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE) != NO_ERROR) {
+ ALOGE("could not load audio policy configuration file, setting defaults");
+ defaultAudioPolicyConfig();
+ }
+ }
+
+ // must be done after reading the policy
+ initializeVolumeCurves();
+
+ // open all output streams needed to access attached devices
+ for (size_t i = 0; i < mHwModules.size(); i++) {
+ mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->mName);
+ if (mHwModules[i]->mHandle == 0) {
+ ALOGW("could not open HW module %s", mHwModules[i]->mName);
+ continue;
+ }
+ // open all output streams needed to access attached devices
+ // except for direct output streams that are only opened when they are actually
+ // required by an app.
+ for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
+ {
+ const IOProfile *outProfile = mHwModules[i]->mOutputProfiles[j];
+
+ if ((outProfile->mSupportedDevices & mAttachedOutputDevices) &&
+ ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0)) {
+ AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(outProfile);
+ outputDesc->mDevice = (audio_devices_t)(mDefaultOutputDevice &
+ outProfile->mSupportedDevices);
+ audio_io_handle_t output = mpClientInterface->openOutput(
+ outProfile->mModule->mHandle,
+ &outputDesc->mDevice,
+ &outputDesc->mSamplingRate,
+ &outputDesc->mFormat,
+ &outputDesc->mChannelMask,
+ &outputDesc->mLatency,
+ outputDesc->mFlags);
+ if (output == 0) {
+ delete outputDesc;
+ } else {
+ mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices |
+ (outProfile->mSupportedDevices & mAttachedOutputDevices));
+ if (mPrimaryOutput == 0 &&
+ outProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
+ mPrimaryOutput = output;
+ }
+ addOutput(output, outputDesc);
+ setOutputDevice(output,
+ (audio_devices_t)(mDefaultOutputDevice &
+ outProfile->mSupportedDevices),
+ true);
+ }
+ }
+ }
+ }
+
+ ALOGE_IF((mAttachedOutputDevices & ~mAvailableOutputDevices),
+ "Not output found for attached devices %08x",
+ (mAttachedOutputDevices & ~mAvailableOutputDevices));
+
+ ALOGE_IF((mPrimaryOutput == 0), "Failed to open primary output");
+
+ updateDevicesAndOutputs();
+
+#ifdef AUDIO_POLICY_TEST
+ if (mPrimaryOutput != 0) {
+ AudioParameter outputCmd = AudioParameter();
+ outputCmd.addInt(String8("set_id"), 0);
+ mpClientInterface->setParameters(mPrimaryOutput, outputCmd.toString());
+
+ mTestDevice = AUDIO_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
+
+ char soundCardID[20] = "";
+ static FILE * fp;
+ size_t readSize;
+
+ fp = fopen("/proc/asound/card0/id", "rt");
+ if (!fp) {
+ ALOGD("Open sound card0 id error!");
+ } else {
+ readSize = fread(soundCardID, sizeof(char), sizeof(soundCardID), fp);
+ fclose(fp);
+
+ if (soundCardID[readSize - 1] == '\n')
+ soundCardID[readSize - 1] = '\0';
+
+ if (strncmp("RKRK616", soundCardID, 7) == 0) {
+ fp = fopen("/proc/asound/card1/id", "rt");
+ if (!fp) {
+ ALOGD("Open sound card1 id error!");
+ } else {
+ readSize = fread(soundCardID, sizeof(char), sizeof(soundCardID), fp);
+ fclose(fp);
+
+ if (soundCardID[readSize - 1] == '\n')
+ soundCardID[readSize - 1] = '\0';
+
+ if (strncmp("ROCKCHIPSPDIF", soundCardID, 13) == 0) {
+ ALOGD("sound card0 is RK616, sound card1 is ROCKCHIPSPDIF, set audio capture with 8KHz.");
+ isCaptureRateChange = true;
+ }
+ }
+ }
+ }
+}
+
+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);
+ }
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ mpClientInterface->closeInput(mInputs.keyAt(i));
+ delete mInputs.valueAt(i);
+ }
+ for (size_t i = 0; i < mHwModules.size(); i++) {
+ delete mHwModules[i];
+ }
+}
+
+status_t AudioPolicyManagerBase::initCheck()
+{
+ return (mPrimaryOutput == 0) ? NO_INIT : NO_ERROR;
+}
+
+#ifdef AUDIO_POLICY_TEST
+bool AudioPolicyManagerBase::threadLoop()
+{
+ ALOGV("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) {
+ ALOGV("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"));
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mPrimaryOutput);
+ mpClientInterface->closeOutput(mPrimaryOutput);
+
+ audio_module_handle_t moduleHandle = outputDesc->mModule->mHandle;
+
+ delete mOutputs.valueFor(mPrimaryOutput);
+ mOutputs.removeItem(mPrimaryOutput);
+
+ AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(NULL);
+ outputDesc->mDevice = AUDIO_DEVICE_OUT_SPEAKER;
+ mPrimaryOutput = mpClientInterface->openOutput(moduleHandle,
+ &outputDesc->mDevice,
+ &outputDesc->mSamplingRate,
+ &outputDesc->mFormat,
+ &outputDesc->mChannelMask,
+ &outputDesc->mLatency,
+ outputDesc->mFlags);
+ if (mPrimaryOutput == 0) {
+ ALOGE("Failed to reopen hardware output stream, samplingRate: %d, format %d, channels %d",
+ outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannelMask);
+ } else {
+ AudioParameter outputCmd = AudioParameter();
+ outputCmd.addInt(String8("set_id"), 0);
+ mpClientInterface->setParameters(mPrimaryOutput, outputCmd.toString());
+ addOutput(mPrimaryOutput, 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);
+}
+
+void AudioPolicyManagerBase::addInput(audio_io_handle_t id, AudioInputDescriptor *inputDesc)
+{
+ inputDesc->mId = id;
+ mInputs.add(id, inputDesc);
+}
+
+status_t AudioPolicyManagerBase::checkOutputsForDevice(audio_devices_t device,
+ AudioSystem::device_connection_state state,
+ SortedVector<audio_io_handle_t>& outputs,
+ const String8 paramStr)
+{
+ AudioOutputDescriptor *desc;
+
+ if (state == AudioSystem::DEVICE_STATE_AVAILABLE) {
+ // first list already open outputs that can be routed to this device
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ desc = mOutputs.valueAt(i);
+ if (!desc->isDuplicated() && (desc->mProfile->mSupportedDevices & device)) {
+ ALOGV("checkOutputsForDevice(): adding opened output %d", mOutputs.keyAt(i));
+ outputs.add(mOutputs.keyAt(i));
+ }
+ }
+ // then look for output profiles that can be routed to this device
+ SortedVector<IOProfile *> profiles;
+ for (size_t i = 0; i < mHwModules.size(); i++)
+ {
+ if (mHwModules[i]->mHandle == 0) {
+ continue;
+ }
+ for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
+ {
+ if (mHwModules[i]->mOutputProfiles[j]->mSupportedDevices & device) {
+ ALOGV("checkOutputsForDevice(): adding profile %zu from module %zu", j, i);
+ profiles.add(mHwModules[i]->mOutputProfiles[j]);
+ }
+ }
+ }
+
+ if (profiles.isEmpty() && outputs.isEmpty()) {
+ ALOGW("checkOutputsForDevice(): No output available for device %04x", device);
+ return BAD_VALUE;
+ }
+
+ // open outputs for matching profiles if needed. Direct outputs are also opened to
+ // query for dynamic parameters and will be closed later by setDeviceConnectionState()
+ for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) {
+ IOProfile *profile = profiles[profile_index];
+
+ // nothing to do if one output is already opened for this profile
+ size_t j;
+ for (j = 0; j < mOutputs.size(); j++) {
+ desc = mOutputs.valueAt(j);
+ if (!desc->isDuplicated() && desc->mProfile == profile) {
+ break;
+ }
+ }
+ if (j != mOutputs.size()) {
+ continue;
+ }
+
+ ALOGV("opening output for device %08x with params %s", device, paramStr.string());
+ desc = new AudioOutputDescriptor(profile);
+ desc->mDevice = device;
+ audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
+ offloadInfo.sample_rate = desc->mSamplingRate;
+ offloadInfo.format = desc->mFormat;
+ offloadInfo.channel_mask = desc->mChannelMask;
+
+ audio_io_handle_t output = mpClientInterface->openOutput(profile->mModule->mHandle,
+ &desc->mDevice,
+ &desc->mSamplingRate,
+ &desc->mFormat,
+ &desc->mChannelMask,
+ &desc->mLatency,
+ desc->mFlags,
+ &offloadInfo);
+ if (output != 0) {
+ if (!paramStr.isEmpty()) {
+ // Here is where the out_set_parameters() for card & device gets called
+ mpClientInterface->setParameters(output, paramStr);
+ }
+
+ // Here is where we step through and resolve any "dynamic" fields
+ String8 reply;
+ char *value;
+ if (profile->mSamplingRates[0] == 0) {
+ reply = mpClientInterface->getParameters(output,
+ String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
+ ALOGV("checkOutputsForDevice() direct output sup sampling rates %s",
+ reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ loadSamplingRates(value + 1, profile);
+ }
+ }
+ if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
+ reply = mpClientInterface->getParameters(output,
+ String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
+ ALOGV("checkOutputsForDevice() direct output sup formats %s",
+ reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ loadFormats(value + 1, profile);
+ }
+ }
+ if (profile->mChannelMasks[0] == 0) {
+ reply = mpClientInterface->getParameters(output,
+ String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
+ ALOGV("checkOutputsForDevice() direct output sup channel masks %s",
+ reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ loadOutChannels(value + 1, profile);
+ }
+ }
+ if (((profile->mSamplingRates[0] == 0) &&
+ (profile->mSamplingRates.size() < 2)) ||
+ ((profile->mFormats[0] == 0) &&
+ (profile->mFormats.size() < 2)) ||
+ ((profile->mChannelMasks[0] == 0) &&
+ (profile->mChannelMasks.size() < 2))) {
+ ALOGW("checkOutputsForDevice() direct output missing param");
+ mpClientInterface->closeOutput(output);
+ output = 0;
+ } else if (profile->mSamplingRates[0] == 0) {
+ mpClientInterface->closeOutput(output);
+ desc->mSamplingRate = profile->mSamplingRates[1];
+ offloadInfo.sample_rate = desc->mSamplingRate;
+ output = mpClientInterface->openOutput(
+ profile->mModule->mHandle,
+ &desc->mDevice,
+ &desc->mSamplingRate,
+ &desc->mFormat,
+ &desc->mChannelMask,
+ &desc->mLatency,
+ desc->mFlags,
+ &offloadInfo);
+ }
+
+ if (output != 0) {
+ addOutput(output, desc);
+ if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) {
+ audio_io_handle_t duplicatedOutput = 0;
+
+ // set initial stream volume for device
+ applyStreamVolumes(output, device, 0, true);
+
+ //TODO: configure audio effect output stage here
+
+ // open a duplicating output thread for the new output and the primary output
+ duplicatedOutput = mpClientInterface->openDuplicateOutput(output,
+ mPrimaryOutput);
+ if (duplicatedOutput != 0) {
+ // add duplicated output descriptor
+ AudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor(NULL);
+ dupOutputDesc->mOutput1 = mOutputs.valueFor(mPrimaryOutput);
+ dupOutputDesc->mOutput2 = mOutputs.valueFor(output);
+ dupOutputDesc->mSamplingRate = desc->mSamplingRate;
+ dupOutputDesc->mFormat = desc->mFormat;
+ dupOutputDesc->mChannelMask = desc->mChannelMask;
+ dupOutputDesc->mLatency = desc->mLatency;
+ addOutput(duplicatedOutput, dupOutputDesc);
+ applyStreamVolumes(duplicatedOutput, device, 0, true);
+ } else {
+ ALOGW("checkOutputsForDevice() could not open dup output for %d and %d",
+ mPrimaryOutput, output);
+ mpClientInterface->closeOutput(output);
+ mOutputs.removeItem(output);
+ output = 0;
+ }
+ }
+ }
+ }
+ if (output == 0) {
+ ALOGW("checkOutputsForDevice() could not open output for device %x", device);
+ delete desc;
+ profiles.removeAt(profile_index);
+ profile_index--;
+ } else {
+ outputs.add(output);
+ ALOGV("checkOutputsForDevice(): adding output %d", output);
+ }
+ }
+
+ if (profiles.isEmpty()) {
+ ALOGW("checkOutputsForDevice(): No output available for device %04x", device);
+ return BAD_VALUE;
+ }
+ } else { // Disconnect
+ // check if one opened output is not needed any more after disconnecting one device
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ desc = mOutputs.valueAt(i);
+ if (!desc->isDuplicated() &&
+ !(desc->mProfile->mSupportedDevices & mAvailableOutputDevices)) {
+ ALOGV("checkOutputsForDevice(): disconnecting adding output %d", mOutputs.keyAt(i));
+ outputs.add(mOutputs.keyAt(i));
+ }
+ }
+ // Clear any profiles associated with the disconnected device.
+ for (size_t i = 0; i < mHwModules.size(); i++)
+ {
+ if (mHwModules[i]->mHandle == 0) {
+ continue;
+ }
+ for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
+ {
+ IOProfile *profile = mHwModules[i]->mOutputProfiles[j];
+ if (profile->mSupportedDevices & device) {
+ ALOGV("checkOutputsForDevice(): clearing direct output profile %zu on module %zu",
+ j, i);
+ if (profile->mSamplingRates[0] == 0) {
+ profile->mSamplingRates.clear();
+ profile->mSamplingRates.add(0);
+ }
+ if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
+ profile->mFormats.clear();
+ profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
+ }
+ if (profile->mChannelMasks[0] == 0) {
+ profile->mChannelMasks.clear();
+ profile->mChannelMasks.add(0);
+ }
+ }
+ }
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManagerBase::checkInputsForDevice(audio_devices_t device,
+ AudioSystem::device_connection_state state,
+ SortedVector<audio_io_handle_t>& inputs,
+ const String8 paramStr)
+{
+ AudioInputDescriptor *desc;
+ if (state == AudioSystem::DEVICE_STATE_AVAILABLE) {
+ // first list already open inputs that can be routed to this device
+ for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
+ desc = mInputs.valueAt(input_index);
+ if (desc->mProfile->mSupportedDevices & (device & ~AUDIO_DEVICE_BIT_IN)) {
+ ALOGV("checkInputsForDevice(): adding opened input %d", mInputs.keyAt(input_index));
+ inputs.add(mInputs.keyAt(input_index));
+ }
+ }
+
+ // then look for input profiles that can be routed to this device
+ SortedVector<IOProfile *> profiles;
+ for (size_t module_index = 0; module_index < mHwModules.size(); module_index++)
+ {
+ if (mHwModules[module_index]->mHandle == 0) {
+ continue;
+ }
+ for (size_t profile_index = 0;
+ profile_index < mHwModules[module_index]->mInputProfiles.size();
+ profile_index++)
+ {
+ if (mHwModules[module_index]->mInputProfiles[profile_index]->mSupportedDevices
+ & (device & ~AUDIO_DEVICE_BIT_IN)) {
+ ALOGV("checkInputsForDevice(): adding profile %d from module %d",
+ profile_index, module_index);
+ profiles.add(mHwModules[module_index]->mInputProfiles[profile_index]);
+ }
+ }
+ }
+
+ if (profiles.isEmpty() && inputs.isEmpty()) {
+ ALOGW("checkInputsForDevice(): No input available for device 0x%X", device);
+ return BAD_VALUE;
+ }
+
+ // open inputs for matching profiles if needed. Direct inputs are also opened to
+ // query for dynamic parameters and will be closed later by setDeviceConnectionState()
+ for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) {
+
+ IOProfile *profile = profiles[profile_index];
+ // nothing to do if one input is already opened for this profile
+ size_t input_index;
+ for (input_index = 0; input_index < mInputs.size(); input_index++) {
+ desc = mInputs.valueAt(input_index);
+ if (desc->mProfile == profile) {
+ break;
+ }
+ }
+ if (input_index != mInputs.size()) {
+ continue;
+ }
+
+ ALOGV("opening input for device 0x%X with params %s", device, paramStr.string());
+ desc = new AudioInputDescriptor(profile);
+ desc->mDevice = device;
+
+ audio_io_handle_t input = mpClientInterface->openInput(profile->mModule->mHandle,
+ &desc->mDevice,
+ &desc->mSamplingRate,
+ &desc->mFormat,
+ &desc->mChannelMask);
+
+ if (input != 0) {
+ if (!paramStr.isEmpty()) {
+ mpClientInterface->setParameters(input, paramStr);
+ }
+
+ // Here is where we step through and resolve any "dynamic" fields
+ String8 reply;
+ char *value;
+ if (profile->mSamplingRates[0] == 0) {
+ reply = mpClientInterface->getParameters(input,
+ String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
+ ALOGV("checkInputsForDevice() direct input sup sampling rates %s",
+ reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ loadSamplingRates(value + 1, profile);
+ }
+ }
+ if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
+ reply = mpClientInterface->getParameters(input,
+ String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
+ ALOGV("checkInputsForDevice() direct input sup formats %s", reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ loadFormats(value + 1, profile);
+ }
+ }
+ if (profile->mChannelMasks[0] == 0) {
+ reply = mpClientInterface->getParameters(input,
+ String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
+ ALOGV("checkInputsForDevice() direct input sup channel masks %s",
+ reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ loadInChannels(value + 1, profile);
+ }
+ }
+ if (((profile->mSamplingRates[0] == 0) && (profile->mSamplingRates.size() < 2)) ||
+ ((profile->mFormats[0] == 0) && (profile->mFormats.size() < 2)) ||
+ ((profile->mChannelMasks[0] == 0) && (profile->mChannelMasks.size() < 2))) {
+ ALOGW("checkInputsForDevice() direct input missing param");
+ mpClientInterface->closeInput(input);
+ input = 0;
+ }
+
+ if (input != 0) {
+ addInput(input, desc);
+ }
+ } // endif input != 0
+
+ if (input == 0) {
+ ALOGW("checkInputsForDevice() could not open input for device 0x%X", device);
+ delete desc;
+ profiles.removeAt(profile_index);
+ profile_index--;
+ } else {
+ inputs.add(input);
+ ALOGV("checkInputsForDevice(): adding input %d", input);
+ }
+ } // end scan profiles
+
+ if (profiles.isEmpty()) {
+ ALOGW("checkInputsForDevice(): No input available for device 0x%X", device);
+ return BAD_VALUE;
+ }
+ } else {
+ // Disconnect
+ // check if one opened input is not needed any more after disconnecting one device
+ for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
+ desc = mInputs.valueAt(input_index);
+ if (!(desc->mProfile->mSupportedDevices & mAvailableInputDevices)) {
+ ALOGV("checkInputsForDevice(): disconnecting adding input %d",
+ mInputs.keyAt(input_index));
+ inputs.add(mInputs.keyAt(input_index));
+ }
+ }
+ // Clear any profiles associated with the disconnected device.
+ for (size_t module_index = 0; module_index < mHwModules.size(); module_index++)
+ {
+ if (mHwModules[module_index]->mHandle == 0) {
+ continue;
+ }
+ for (size_t profile_index = 0;
+ profile_index < mHwModules[module_index]->mInputProfiles.size();
+ profile_index++)
+ {
+ IOProfile *profile = mHwModules[module_index]->mInputProfiles[profile_index];
+ if (profile->mSupportedDevices & device) {
+ ALOGV("checkInputsForDevice(): clearing direct input profile %d on module %d",
+ profile_index, module_index);
+ if (profile->mSamplingRates[0] == 0) {
+ profile->mSamplingRates.clear();
+ profile->mSamplingRates.add(0);
+ }
+ if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
+ profile->mFormats.clear();
+ profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
+ }
+ if (profile->mChannelMasks[0] == 0) {
+ profile->mChannelMasks.clear();
+ profile->mChannelMasks.add(0);
+ }
+ }
+ }
+ }
+ } // end disconnect
+
+ return NO_ERROR;
+}
+
+void AudioPolicyManagerBase::closeOutput(audio_io_handle_t output)
+{
+ ALOGV("closeOutput(%d)", output);
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+ if (outputDesc == NULL) {
+ ALOGW("closeOutput() unknown output %d", output);
+ return;
+ }
+
+ // look for duplicated outputs connected to the output being removed.
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ AudioOutputDescriptor *dupOutputDesc = mOutputs.valueAt(i);
+ if (dupOutputDesc->isDuplicated() &&
+ (dupOutputDesc->mOutput1 == outputDesc ||
+ dupOutputDesc->mOutput2 == outputDesc)) {
+ AudioOutputDescriptor *outputDesc2;
+ if (dupOutputDesc->mOutput1 == outputDesc) {
+ outputDesc2 = dupOutputDesc->mOutput2;
+ } else {
+ outputDesc2 = dupOutputDesc->mOutput1;
+ }
+ // As all active tracks on duplicated output will be deleted,
+ // and as they were also referenced on the other output, the reference
+ // count for their stream type must be adjusted accordingly on
+ // the other output.
+ for (int j = 0; j < (int)AudioSystem::NUM_STREAM_TYPES; j++) {
+ int refCount = dupOutputDesc->mRefCount[j];
+ outputDesc2->changeRefCount((AudioSystem::stream_type)j,-refCount);
+ }
+ audio_io_handle_t duplicatedOutput = mOutputs.keyAt(i);
+ ALOGV("closeOutput() closing also duplicated output %d", duplicatedOutput);
+
+ mpClientInterface->closeOutput(duplicatedOutput);
+ delete mOutputs.valueFor(duplicatedOutput);
+ mOutputs.removeItem(duplicatedOutput);
+ }
+ }
+
+ AudioParameter param;
+ param.add(String8("closing"), String8("true"));
+ mpClientInterface->setParameters(output, param.toString());
+
+ mpClientInterface->closeOutput(output);
+ delete outputDesc;
+ mOutputs.removeItem(output);
+ mPreviousOutputs = mOutputs;
+}
+
+SortedVector<audio_io_handle_t> AudioPolicyManagerBase::getOutputsForDevice(audio_devices_t device,
+ DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor *> openOutputs)
+{
+ SortedVector<audio_io_handle_t> outputs;
+
+ ALOGVV("getOutputsForDevice() device %04x", device);
+ for (size_t i = 0; i < openOutputs.size(); i++) {
+ ALOGVV("output %d isDuplicated=%d device=%04x",
+ i, openOutputs.valueAt(i)->isDuplicated(), openOutputs.valueAt(i)->supportedDevices());
+ if ((device & openOutputs.valueAt(i)->supportedDevices()) == device) {
+ ALOGVV("getOutputsForDevice() found output %d", openOutputs.keyAt(i));
+ outputs.add(openOutputs.keyAt(i));
+ }
+ }
+ return outputs;
+}
+
+bool AudioPolicyManagerBase::vectorsEqual(SortedVector<audio_io_handle_t>& outputs1,
+ SortedVector<audio_io_handle_t>& outputs2)
+{
+ if (outputs1.size() != outputs2.size()) {
+ return false;
+ }
+ for (size_t i = 0; i < outputs1.size(); i++) {
+ if (outputs1[i] != outputs2[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void AudioPolicyManagerBase::checkOutputForStrategy(routing_strategy strategy)
+{
+ audio_devices_t oldDevice = getDeviceForStrategy(strategy, true /*fromCache*/);
+ audio_devices_t newDevice = getDeviceForStrategy(strategy, false /*fromCache*/);
+ SortedVector<audio_io_handle_t> srcOutputs = getOutputsForDevice(oldDevice, mPreviousOutputs);
+ SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevice(newDevice, mOutputs);
+
+ if (!vectorsEqual(srcOutputs,dstOutputs)) {
+ ALOGV("checkOutputForStrategy() strategy %d, moving from output %d to output %d",
+ strategy, srcOutputs[0], dstOutputs[0]);
+ // mute strategy while moving tracks from one output to another
+ for (size_t i = 0; i < srcOutputs.size(); i++) {
+ AudioOutputDescriptor *desc = mOutputs.valueFor(srcOutputs[i]);
+ if (desc->isStrategyActive(strategy)) {
+ setStrategyMute(strategy, true, srcOutputs[i]);
+ setStrategyMute(strategy, false, srcOutputs[i], MUTE_TIME_MS, newDevice);
+ }
+ }
+
+ // Move effects associated to this strategy from previous output to new output
+ if (strategy == STRATEGY_MEDIA) {
+ audio_io_handle_t fxOutput = selectOutputForEffects(dstOutputs);
+ SortedVector<audio_io_handle_t> moved;
+ for (size_t i = 0; i < mEffects.size(); i++) {
+ EffectDescriptor *desc = mEffects.valueAt(i);
+ if (desc->mSession == AUDIO_SESSION_OUTPUT_MIX &&
+ desc->mIo != fxOutput) {
+ if (moved.indexOf(desc->mIo) < 0) {
+ ALOGV("checkOutputForStrategy() moving effect %d to output %d",
+ mEffects.keyAt(i), fxOutput);
+ mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, desc->mIo,
+ fxOutput);
+ moved.add(desc->mIo);
+ }
+ desc->mIo = fxOutput;
+ }
+ }
+ }
+ // Move tracks associated to this strategy from previous output to new output
+ for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
+ if (getStrategy((AudioSystem::stream_type)i) == strategy) {
+ mpClientInterface->invalidateStream((AudioSystem::stream_type)i);
+ }
+ }
+ }
+}
+
+void AudioPolicyManagerBase::checkOutputForAllStrategies()
+{
+ checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE);
+ checkOutputForStrategy(STRATEGY_PHONE);
+ checkOutputForStrategy(STRATEGY_SONIFICATION);
+ checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL);
+ checkOutputForStrategy(STRATEGY_MEDIA);
+ checkOutputForStrategy(STRATEGY_DTMF);
+}
+
+audio_io_handle_t AudioPolicyManagerBase::getA2dpOutput()
+{
+ if (!mHasA2dp) {
+ return 0;
+ }
+
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i);
+ if (!outputDesc->isDuplicated() && outputDesc->device() & AUDIO_DEVICE_OUT_ALL_A2DP) {
+ return mOutputs.keyAt(i);
+ }
+ }
+
+ return 0;
+}
+
+void AudioPolicyManagerBase::checkA2dpSuspend()
+{
+ if (!mHasA2dp) {
+ return;
+ }
+ audio_io_handle_t a2dpOutput = getA2dpOutput();
+ if (a2dpOutput == 0) {
+ return;
+ }
+
+ // suspend A2DP output if:
+ // (NOT already suspended) &&
+ // ((SCO device is connected &&
+ // (forced usage for communication || for record is SCO))) ||
+ // (phone state is ringing || in call)
+ //
+ // restore A2DP output if:
+ // (Already suspended) &&
+ // ((SCO device is NOT connected ||
+ // (forced usage NOT for communication && NOT for record is SCO))) &&
+ // (phone state is NOT ringing && NOT in call)
+ //
+ if (mA2dpSuspended) {
+ if (((mScoDeviceAddress == "") ||
+ ((mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO) &&
+ (mForceUse[AudioSystem::FOR_RECORD] != AudioSystem::FORCE_BT_SCO))) &&
+ ((mPhoneState != AudioSystem::MODE_IN_CALL) &&
+ (mPhoneState != AudioSystem::MODE_RINGTONE))) {
+
+ mpClientInterface->restoreOutput(a2dpOutput);
+ mA2dpSuspended = false;
+ }
+ } else {
+ if (((mScoDeviceAddress != "") &&
+ ((mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
+ (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO))) ||
+ ((mPhoneState == AudioSystem::MODE_IN_CALL) ||
+ (mPhoneState == AudioSystem::MODE_RINGTONE))) {
+
+ mpClientInterface->suspendOutput(a2dpOutput);
+ mA2dpSuspended = true;
+ }
+ }
+}
+
+audio_devices_t AudioPolicyManagerBase::getNewDevice(audio_io_handle_t output, bool fromCache)
+{
+ audio_devices_t device = AUDIO_DEVICE_NONE;
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+ // check the following by order of priority to request a routing change if necessary:
+ // 1: the strategy enforced audible is active on the output:
+ // use device for strategy enforced audible
+ // 2: we are in call or the strategy phone is active on the output:
+ // use device for strategy phone
+ // 3: the strategy sonification is active on the output:
+ // use device for strategy sonification
+ // 4: the strategy "respectful" sonification is active on the output:
+ // use device for strategy "respectful" sonification
+ // 5: the strategy media is active on the output:
+ // use device for strategy media
+ // 6: the strategy DTMF is active on the output:
+ // use device for strategy DTMF
+ if (outputDesc->isStrategyActive(STRATEGY_ENFORCED_AUDIBLE)) {
+ device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
+ } else if (isInCall() ||
+ outputDesc->isStrategyActive(STRATEGY_PHONE)) {
+ device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
+ } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION)) {
+ device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
+ } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION_RESPECTFUL)) {
+ device = getDeviceForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, fromCache);
+ } else if (outputDesc->isStrategyActive(STRATEGY_MEDIA)) {
+ device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache);
+ } else if (outputDesc->isStrategyActive(STRATEGY_DTMF)) {
+ device = getDeviceForStrategy(STRATEGY_DTMF, fromCache);
+ }
+
+ ALOGV("getNewDevice() selected device %x", device);
+ return device;
+}
+
+uint32_t AudioPolicyManagerBase::getStrategyForStream(AudioSystem::stream_type stream) {
+ return (uint32_t)getStrategy(stream);
+}
+
+audio_devices_t AudioPolicyManagerBase::getDevicesForStream(AudioSystem::stream_type stream) {
+ audio_devices_t devices;
+ // By checking the range of stream before calling getStrategy, we avoid
+ // getStrategy's behavior for invalid streams. getStrategy would do a ALOGE
+ // and then return STRATEGY_MEDIA, but we want to return the empty set.
+ if (stream < (AudioSystem::stream_type) 0 || stream >= AudioSystem::NUM_STREAM_TYPES) {
+ devices = AUDIO_DEVICE_NONE;
+ } else {
+ AudioPolicyManagerBase::routing_strategy strategy = getStrategy(stream);
+ devices = getDeviceForStrategy(strategy, true /*fromCache*/);
+ }
+ return devices;
+}
+
+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::ALARM:
+ return STRATEGY_SONIFICATION;
+ case AudioSystem::NOTIFICATION:
+ return STRATEGY_SONIFICATION_RESPECTFUL;
+ case AudioSystem::DTMF:
+ return STRATEGY_DTMF;
+ default:
+ ALOGE("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;
+ case AudioSystem::ENFORCED_AUDIBLE:
+ return STRATEGY_ENFORCED_AUDIBLE;
+ }
+}
+
+void AudioPolicyManagerBase::handleNotificationRoutingForStream(AudioSystem::stream_type stream) {
+ switch(stream) {
+ case AudioSystem::MUSIC:
+ checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL);
+ updateDevicesAndOutputs();
+ break;
+ default:
+ break;
+ }
+}
+
+audio_devices_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy,
+ bool fromCache)
+{
+ uint32_t device = AUDIO_DEVICE_NONE;
+
+ if (fromCache) {
+ ALOGVV("getDeviceForStrategy() from cache strategy %d, device %x",
+ strategy, mDeviceForStrategy[strategy]);
+ return mDeviceForStrategy[strategy];
+ }
+
+ switch (strategy) {
+
+ case STRATEGY_SONIFICATION_RESPECTFUL:
+ if (isInCall()) {
+ device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+ } else if (isStreamActiveRemotely(AudioSystem::MUSIC,
+ SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
+ // while media is playing on a remote device, use the the sonification behavior.
+ // Note that we test this usecase before testing if media is playing because
+ // the isStreamActive() method only informs about the activity of a stream, not
+ // if it's for local playback. Note also that we use the same delay between both tests
+ device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+ } else if (isStreamActive(AudioSystem::MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
+ // while media is playing (or has recently played), use the same device
+ device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
+ } else {
+ // when media is not playing anymore, fall back on the sonification behavior
+ device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+ }
+
+ break;
+
+ case STRATEGY_DTMF:
+ if (!isInCall()) {
+ // when off call, DTMF strategy follows the same rules as MEDIA strategy
+ device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
+ 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 (!isInCall() || strategy != STRATEGY_DTMF) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+ if (device) break;
+ }
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_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
+ // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
+ if (mHasA2dp && !isInCall() &&
+ (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+ (getA2dpOutput() != 0) && !mA2dpSuspended) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ if (device) break;
+ }
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ if (device) break;
+ if (mPhoneState != AudioSystem::MODE_IN_CALL) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ if (device) break;
+ }
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_EARPIECE;
+ if (device) break;
+ device = mDefaultOutputDevice;
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE");
+ }
+ break;
+
+ case AudioSystem::FORCE_SPEAKER:
+ // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to
+ // A2DP speaker when forcing to speaker output
+ if (mHasA2dp && !isInCall() &&
+ (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+ (getA2dpOutput() != 0) && !mA2dpSuspended) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ if (device) break;
+ }
+ if (mPhoneState != AudioSystem::MODE_IN_CALL) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ if (device) break;
+ }
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+ if (device) break;
+ device = mDefaultOutputDevice;
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER");
+ }
+ break;
+ }
+ break;
+
+ case STRATEGY_SONIFICATION:
+
+ // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by
+ // handleIncallSonification().
+ if (isInCall()) {
+ device = getDeviceForStrategy(STRATEGY_PHONE, false /*fromCache*/);
+ break;
+ }
+ // FALL THROUGH
+
+ case STRATEGY_ENFORCED_AUDIBLE:
+ // strategy STRATEGY_ENFORCED_AUDIBLE uses same routing policy as STRATEGY_SONIFICATION
+ // except:
+ // - when in call where it doesn't default to STRATEGY_PHONE behavior
+ // - in countries where not enforced in which case it follows STRATEGY_MEDIA
+
+ if ((strategy == STRATEGY_SONIFICATION) ||
+ (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_SYSTEM_ENFORCED)) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGE("getDeviceForStrategy() speaker device not found for STRATEGY_SONIFICATION");
+ }
+ }
+ // The second device used for sonification is the same as the device used by media strategy
+ // FALL THROUGH
+
+ case STRATEGY_MEDIA: {
+ uint32_t device2 = AUDIO_DEVICE_NONE;
+ if (strategy != STRATEGY_SONIFICATION) {
+ // no sonification on remote submix (e.g. WFD)
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ }
+ if ((device2 == AUDIO_DEVICE_NONE) &&
+ mHasA2dp && (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+ (getA2dpOutput() != 0) && !mA2dpSuspended) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ }
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ }
+ if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) {
+ // no sonification on aux digital (e.g. HDMI)
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ }
+ if ((device2 == AUDIO_DEVICE_NONE) /*&&
+ (mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_ANALOG_DOCK)*/) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+ }
+
+ // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or
+ // STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise
+ device |= device2;
+ if (device) break;
+ device = mDefaultOutputDevice;
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA");
+ }
+ } break;
+
+ default:
+ ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy);
+ break;
+ }
+
+ uint32_t deviceBluetooth = (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
+
+ uint32_t devicePrimary = (AUDIO_DEVICE_OUT_WIRED_HEADSET |
+ AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+ AUDIO_DEVICE_OUT_SPEAKER);
+
+ if ((((device & deviceBluetooth) == AUDIO_DEVICE_NONE) || (device & (~deviceBluetooth))) &&
+ (mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
+ device &= ~devicePrimary;
+ device |= AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ }
+
+ ALOGVV("getDeviceForStrategy() strategy %d, device %x", strategy, device);
+ return device;
+}
+
+void AudioPolicyManagerBase::updateDevicesAndOutputs()
+{
+ for (int i = 0; i < NUM_STRATEGIES; i++) {
+ mDeviceForStrategy[i] = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/);
+ }
+ mPreviousOutputs = mOutputs;
+}
+
+uint32_t AudioPolicyManagerBase::checkDeviceMuteStrategies(AudioOutputDescriptor *outputDesc,
+ audio_devices_t prevDevice,
+ uint32_t delayMs)
+{
+ // mute/unmute strategies using an incompatible device combination
+ // if muting, wait for the audio in pcm buffer to be drained before proceeding
+ // if unmuting, unmute only after the specified delay
+ if (outputDesc->isDuplicated()) {
+ return 0;
+ }
+
+ uint32_t muteWaitMs = 0;
+ audio_devices_t device = outputDesc->device();
+ bool shouldMute = outputDesc->isActive() && (AudioSystem::popCount(device) >= 2);
+ // temporary mute output if device selection changes to avoid volume bursts due to
+ // different per device volumes
+ bool tempMute = outputDesc->isActive() && (device != prevDevice);
+
+ for (size_t i = 0; i < NUM_STRATEGIES; i++) {
+ audio_devices_t curDevice = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/);
+ bool mute = shouldMute && (curDevice & device) && (curDevice != device);
+ bool doMute = false;
+
+ if (mute && !outputDesc->mStrategyMutedByDevice[i]) {
+ doMute = true;
+ outputDesc->mStrategyMutedByDevice[i] = true;
+ } else if (!mute && outputDesc->mStrategyMutedByDevice[i]){
+ doMute = true;
+ outputDesc->mStrategyMutedByDevice[i] = false;
+ }
+ if (doMute || tempMute) {
+ for (size_t j = 0; j < mOutputs.size(); j++) {
+ AudioOutputDescriptor *desc = mOutputs.valueAt(j);
+ // skip output if it does not share any device with current output
+ if ((desc->supportedDevices() & outputDesc->supportedDevices())
+ == AUDIO_DEVICE_NONE) {
+ continue;
+ }
+ audio_io_handle_t curOutput = mOutputs.keyAt(j);
+ ALOGVV("checkDeviceMuteStrategies() %s strategy %d (curDevice %04x) on output %d",
+ mute ? "muting" : "unmuting", i, curDevice, curOutput);
+ setStrategyMute((routing_strategy)i, mute, curOutput, mute ? 0 : delayMs);
+ if (desc->isStrategyActive((routing_strategy)i)) {
+ // do tempMute only for current output
+ if (tempMute && (desc == outputDesc)) {
+ setStrategyMute((routing_strategy)i, true, curOutput);
+ setStrategyMute((routing_strategy)i, false, curOutput,
+ desc->latency() * 2, device);
+ }
+ if ((tempMute && (desc == outputDesc)) || mute) {
+ if (muteWaitMs < desc->latency()) {
+ muteWaitMs = desc->latency();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // FIXME: should not need to double latency if volume could be applied immediately by the
+ // audioflinger mixer. We must account for the delay between now and the next time
+ // the audioflinger thread for this output will process a buffer (which corresponds to
+ // one buffer size, usually 1/2 or 1/4 of the latency).
+ muteWaitMs *= 2;
+ // wait for the PCM output buffers to empty before proceeding with the rest of the command
+ if (muteWaitMs > delayMs) {
+ muteWaitMs -= delayMs;
+ usleep(muteWaitMs * 1000);
+ return muteWaitMs;
+ }
+ return 0;
+}
+
+uint32_t AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output,
+ audio_devices_t device,
+ bool force,
+ int delayMs)
+{
+ ALOGV("setOutputDevice() output %d device %04x delayMs %d", output, device, delayMs);
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+ AudioParameter param;
+ uint32_t muteWaitMs;
+
+ if (outputDesc->isDuplicated()) {
+ muteWaitMs = setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs);
+ muteWaitMs += setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs);
+ return muteWaitMs;
+ }
+ // no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
+ // output profile
+ if ((device != AUDIO_DEVICE_NONE) &&
+ ((device & outputDesc->mProfile->mSupportedDevices) == 0)) {
+ return 0;
+ }
+
+ // filter devices according to output selected
+ device = (audio_devices_t)(device & outputDesc->mProfile->mSupportedDevices);
+
+ audio_devices_t prevDevice = outputDesc->mDevice;
+
+ ALOGV("setOutputDevice() prevDevice %04x", prevDevice);
+
+ if (device != AUDIO_DEVICE_NONE) {
+ outputDesc->mDevice = device;
+ }
+ muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+
+ // Do not change the routing if:
+ // - the requested device is AUDIO_DEVICE_NONE
+ // - 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 == AUDIO_DEVICE_NONE || device == prevDevice) && !force) {
+ ALOGV("setOutputDevice() setting same device %04x or null device for output %d", device, output);
+ return muteWaitMs;
+ }
+
+ ALOGV("setOutputDevice() changing device");
+ // do the routing
+ param.addInt(String8(AudioParameter::keyRouting), (int)device);
+ mpClientInterface->setParameters(output, param.toString(), delayMs);
+ if (device != AUDIO_DEVICE_NONE) {
+ //If is incall state, it need update incall voice volume.
+ if (mPhoneState == AudioSystem::MODE_IN_CALL)
+ mLastVoiceVolume = -1.0f;
+
+ // update stream volumes according to new device
+ applyStreamVolumes(output, device, delayMs);
+ }
+
+ return muteWaitMs;
+}
+
+AudioPolicyManagerBase::IOProfile *AudioPolicyManagerBase::getInputProfile(audio_devices_t device,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask)
+{
+ // Choose an input profile based on the requested capture parameters: select the first available
+ // profile supporting all requested parameters.
+ for (size_t i = 0; i < mHwModules.size(); i++)
+ {
+ if (mHwModules[i]->mHandle == 0) {
+ continue;
+ }
+ for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++)
+ {
+ IOProfile *profile = mHwModules[i]->mInputProfiles[j];
+ // profile->log();
+ if (profile->isCompatibleProfile(device, samplingRate, format,
+ channelMask, AUDIO_OUTPUT_FLAG_NONE)) {
+ return profile;
+ }
+ }
+ }
+ return NULL;
+}
+
+audio_devices_t AudioPolicyManagerBase::getDeviceForInputSource(int inputSource)
+{
+ uint32_t device = AUDIO_DEVICE_NONE;
+
+ switch (inputSource) {
+ case AUDIO_SOURCE_VOICE_UPLINK:
+ if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) {
+ device = AUDIO_DEVICE_IN_VOICE_CALL;
+ break;
+ }
+ // FALL THROUGH
+
+ case AUDIO_SOURCE_DEFAULT:
+ case AUDIO_SOURCE_MIC:
+ if (mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
+ device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+ break;
+ }
+ // FALL THROUGH
+
+ case AUDIO_SOURCE_VOICE_RECOGNITION:
+ case AUDIO_SOURCE_HOTWORD:
+ case AUDIO_SOURCE_VOICE_COMMUNICATION:
+ if (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO &&
+ mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+ device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+ } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_USB_DEVICE) {
+ device = AUDIO_DEVICE_IN_USB_DEVICE;
+ } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ }
+ break;
+ case AUDIO_SOURCE_CAMCORDER:
+ if (mAvailableInputDevices & AUDIO_DEVICE_IN_BACK_MIC) {
+ device = AUDIO_DEVICE_IN_BACK_MIC;
+ } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ }
+ break;
+ case AUDIO_SOURCE_VOICE_DOWNLINK:
+ case AUDIO_SOURCE_VOICE_CALL:
+ if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) {
+ device = AUDIO_DEVICE_IN_VOICE_CALL;
+ }
+ break;
+ case AUDIO_SOURCE_REMOTE_SUBMIX:
+ if (mAvailableInputDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
+ device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+ }
+ break;
+ default:
+ ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);
+ break;
+ }
+ ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device);
+ return device;
+}
+
+bool AudioPolicyManagerBase::isVirtualInputDevice(audio_devices_t device)
+{
+ if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+ device &= ~AUDIO_DEVICE_BIT_IN;
+ if ((popcount(device) == 1) && ((device & ~APM_AUDIO_IN_DEVICE_VIRTUAL_ALL) == 0))
+ return true;
+ }
+ return false;
+}
+
+audio_io_handle_t AudioPolicyManagerBase::getActiveInput(bool ignoreVirtualInputs)
+{
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ const AudioInputDescriptor * input_descriptor = mInputs.valueAt(i);
+ if ((input_descriptor->mRefCount > 0)
+ && (!ignoreVirtualInputs || !isVirtualInputDevice(input_descriptor->mDevice))) {
+ return mInputs.keyAt(i);
+ }
+ }
+ return 0;
+}
+
+
+audio_devices_t AudioPolicyManagerBase::getDeviceForVolume(audio_devices_t device)
+{
+ if (device == AUDIO_DEVICE_NONE) {
+ // this happens when forcing a route update and no track is active on an output.
+ // In this case the returned category is not important.
+ device = AUDIO_DEVICE_OUT_SPEAKER;
+ } else if (AudioSystem::popCount(device) > 1) {
+ // Multiple device selection is either:
+ // - speaker + one other device: give priority to speaker in this case.
+ // - one A2DP device + another device: happens with duplicated output. In this case
+ // retain the device on the A2DP output as the other must not correspond to an active
+ // selection if not the speaker.
+ if (device & AUDIO_DEVICE_OUT_SPEAKER) {
+ device = AUDIO_DEVICE_OUT_SPEAKER;
+ } else {
+ device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP);
+ }
+ }
+
+ ALOGW_IF(AudioSystem::popCount(device) != 1,
+ "getDeviceForVolume() invalid device combination: %08x",
+ device);
+
+ return device;
+}
+
+AudioPolicyManagerBase::device_category AudioPolicyManagerBase::getDeviceCategory(audio_devices_t device)
+{
+ switch(getDeviceForVolume(device)) {
+ case AUDIO_DEVICE_OUT_EARPIECE:
+ return DEVICE_CATEGORY_EARPIECE;
+ case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+ case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+ return DEVICE_CATEGORY_HEADSET;
+ case AUDIO_DEVICE_OUT_SPEAKER:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
+ case AUDIO_DEVICE_OUT_AUX_DIGITAL:
+ case AUDIO_DEVICE_OUT_USB_ACCESSORY:
+ case AUDIO_DEVICE_OUT_USB_DEVICE:
+ case AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
+ default:
+ return DEVICE_CATEGORY_SPEAKER;
+ }
+}
+
+float AudioPolicyManagerBase::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
+ int indexInUi)
+{
+ device_category deviceCategory = getDeviceCategory(device);
+ const VolumeCurvePoint *curve = streamDesc.mVolumeCurve[deviceCategory];
+
+ // the volume index in the UI is relative to the min and max volume indices for this stream type
+ int nbSteps = 1 + curve[VOLMAX].mIndex -
+ curve[VOLMIN].mIndex;
+ int volIdx = (nbSteps * (indexInUi - streamDesc.mIndexMin)) /
+ (streamDesc.mIndexMax - streamDesc.mIndexMin);
+
+ // find what part of the curve this index volume belongs to, or if it's out of bounds
+ int segment = 0;
+ if (volIdx < curve[VOLMIN].mIndex) { // out of bounds
+ return 0.0f;
+ } else if (volIdx < curve[VOLKNEE1].mIndex) {
+ segment = 0;
+ } else if (volIdx < curve[VOLKNEE2].mIndex) {
+ segment = 1;
+ } else if (volIdx <= curve[VOLMAX].mIndex) {
+ segment = 2;
+ } else { // out of bounds
+ return 1.0f;
+ }
+
+ // linear interpolation in the attenuation table in dB
+ float decibels = curve[segment].mDBAttenuation +
+ ((float)(volIdx - curve[segment].mIndex)) *
+ ( (curve[segment+1].mDBAttenuation -
+ curve[segment].mDBAttenuation) /
+ ((float)(curve[segment+1].mIndex -
+ curve[segment].mIndex)) );
+
+ float amplification = exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 )
+
+ ALOGVV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f] ampl=%.5f",
+ curve[segment].mIndex, volIdx,
+ curve[segment+1].mIndex,
+ curve[segment].mDBAttenuation,
+ decibels,
+ curve[segment+1].mDBAttenuation,
+ amplification);
+
+ return amplification;
+}
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sDefaultVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+ {1, -49.5f}, {33, -33.5f}, {66, -17.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sDefaultMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+ {1, -58.0f}, {20, -40.0f}, {60, -17.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sSpeakerMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+ {1, -56.0f}, {20, -34.0f}, {60, -11.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sSpeakerSonificationVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+ {1, -29.7f}, {33, -20.1f}, {66, -10.2f}, {100, 0.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sSpeakerSonificationVolumeCurveDrc[AudioPolicyManagerBase::VOLCNT] = {
+ {1, -35.7f}, {33, -26.1f}, {66, -13.2f}, {100, 0.0f}
+};
+
+// AUDIO_STREAM_SYSTEM, AUDIO_STREAM_ENFORCED_AUDIBLE and AUDIO_STREAM_DTMF volume tracks
+// AUDIO_STREAM_RING on phones and AUDIO_STREAM_MUSIC on tablets.
+// AUDIO_STREAM_DTMF tracks AUDIO_STREAM_VOICE_CALL while in call (See AudioService.java).
+// The range is constrained between -24dB and -6dB over speaker and -30dB and -18dB over headset.
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sDefaultSystemVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+ {1, -24.0f}, {33, -18.0f}, {66, -12.0f}, {100, -6.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sDefaultSystemVolumeCurveDrc[AudioPolicyManagerBase::VOLCNT] = {
+ {1, -34.0f}, {33, -24.0f}, {66, -15.0f}, {100, -6.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sHeadsetSystemVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+ {1, -30.0f}, {33, -26.0f}, {66, -22.0f}, {100, -18.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sDefaultVoiceVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+ {0, -42.0f}, {33, -28.0f}, {66, -14.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sSpeakerVoiceVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+ {0, -24.0f}, {33, -16.0f}, {66, -8.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+ *AudioPolicyManagerBase::sVolumeProfiles[AUDIO_STREAM_CNT]
+ [AudioPolicyManagerBase::DEVICE_CATEGORY_CNT] = {
+ { // AUDIO_STREAM_VOICE_CALL
+ sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultVoiceVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ },
+ { // AUDIO_STREAM_SYSTEM
+ sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultSystemVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ },
+ { // AUDIO_STREAM_RING
+ sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ },
+ { // AUDIO_STREAM_MUSIC
+ sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ },
+ { // AUDIO_STREAM_ALARM
+ sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ },
+ { // AUDIO_STREAM_NOTIFICATION
+ sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ },
+ { // AUDIO_STREAM_BLUETOOTH_SCO
+ sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultVoiceVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ },
+ { // AUDIO_STREAM_ENFORCED_AUDIBLE
+ sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultSystemVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ },
+ { // AUDIO_STREAM_DTMF
+ sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultSystemVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ },
+ { // AUDIO_STREAM_TTS
+ sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ },
+};
+
+void AudioPolicyManagerBase::initializeVolumeCurves()
+{
+ for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
+ for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
+ mStreams[i].mVolumeCurve[j] =
+ sVolumeProfiles[i][j];
+ }
+ }
+
+ // Check availability of DRC on speaker path: if available, override some of the speaker curves
+ if (mSpeakerDrcEnabled) {
+ mStreams[AUDIO_STREAM_SYSTEM].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+ sDefaultSystemVolumeCurveDrc;
+ mStreams[AUDIO_STREAM_RING].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+ sSpeakerSonificationVolumeCurveDrc;
+ mStreams[AUDIO_STREAM_ALARM].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+ sSpeakerSonificationVolumeCurveDrc;
+ mStreams[AUDIO_STREAM_NOTIFICATION].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+ sSpeakerSonificationVolumeCurveDrc;
+ }
+}
+
+float AudioPolicyManagerBase::computeVolume(int stream,
+ int index,
+ audio_io_handle_t output,
+ audio_devices_t device)
+{
+ float volume = 1.0;
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+ StreamDescriptor &streamDesc = mStreams[stream];
+
+ if (device == AUDIO_DEVICE_NONE) {
+ device = outputDesc->device();
+ }
+
+ // if volume is not 0 (not muted), force media volume to max on digital output
+ if (stream == AudioSystem::MUSIC &&
+ index != mStreams[stream].mIndexMin &&
+ (//device == AUDIO_DEVICE_OUT_AUX_DIGITAL ||
+ //device == AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET
+ true)) {
+ return 1.0;
+ }
+
+ volume = volIndexToAmpl(device, streamDesc, index);
+
+ // 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.
+ const routing_strategy stream_strategy = getStrategy((AudioSystem::stream_type)stream);
+ if ((device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+ AUDIO_DEVICE_OUT_WIRED_HEADSET |
+ AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) &&
+ ((stream_strategy == STRATEGY_SONIFICATION)
+ || (stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL)
+ || (stream == AudioSystem::SYSTEM)
+ || ((stream_strategy == STRATEGY_ENFORCED_AUDIBLE) &&
+ (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_NONE))) &&
+ 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 (isStreamActive(AudioSystem::MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY) ||
+ mLimitRingtoneVolume) {
+ audio_devices_t musicDevice = getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/);
+ float musicVol = computeVolume(AudioSystem::MUSIC,
+ mStreams[AudioSystem::MUSIC].getVolumeIndex(musicDevice),
+ output,
+ musicDevice);
+ float minVol = (musicVol > SONIFICATION_HEADSET_VOLUME_MIN) ?
+ musicVol : SONIFICATION_HEADSET_VOLUME_MIN;
+ if (volume > minVol) {
+ volume = minVol;
+ ALOGV("computeVolume limiting volume to %f musicVol %f", minVol, musicVol);
+ }
+ }
+ }
+
+ return volume;
+}
+
+status_t AudioPolicyManagerBase::checkAndSetVolume(int stream,
+ int index,
+ audio_io_handle_t output,
+ audio_devices_t device,
+ int delayMs,
+ bool force)
+{
+
+ // do not change actual stream volume if the stream is muted
+ if (mOutputs.valueFor(output)->mMuteCount[stream] != 0) {
+ ALOGVV("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)) {
+ ALOGV("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);
+ // We actually change the volume if:
+ // - the float value returned by computeVolume() changed
+ // - the force flag is set
+ if (volume != mOutputs.valueFor(output)->mCurVolume[stream] ||
+ force) {
+ mOutputs.valueFor(output)->mCurVolume[stream] = volume;
+ ALOGVV("checkAndSetVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs);
+ // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is
+ // enabled
+ if (stream == AudioSystem::BLUETOOTH_SCO) {
+ mpClientInterface->setStreamVolume(AudioSystem::VOICE_CALL, volume, output, delayMs);
+ }
+ mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
+ }
+
+ if (stream == AudioSystem::VOICE_CALL ||
+ stream == AudioSystem::BLUETOOTH_SCO) {
+ float voiceVolume;
+ // Force voice volume to max for bluetooth SCO as volume is managed by the headset
+ if (stream == AudioSystem::VOICE_CALL) {
+ voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
+ } else {
+ voiceVolume = 1.0;
+ }
+
+ if (voiceVolume != mLastVoiceVolume && output == mPrimaryOutput) {
+ mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
+ mLastVoiceVolume = voiceVolume;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+void AudioPolicyManagerBase::applyStreamVolumes(audio_io_handle_t output,
+ audio_devices_t device,
+ int delayMs,
+ bool force)
+{
+ ALOGVV("applyStreamVolumes() for output %d and device %x", output, device);
+
+ for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+ checkAndSetVolume(stream,
+ mStreams[stream].getVolumeIndex(device),
+ output,
+ device,
+ delayMs,
+ force);
+ }
+}
+
+void AudioPolicyManagerBase::setStrategyMute(routing_strategy strategy,
+ bool on,
+ audio_io_handle_t output,
+ int delayMs,
+ audio_devices_t device)
+{
+ ALOGVV("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, device);
+ }
+ }
+}
+
+void AudioPolicyManagerBase::setStreamMute(int stream,
+ bool on,
+ audio_io_handle_t output,
+ int delayMs,
+ audio_devices_t device)
+{
+ StreamDescriptor &streamDesc = mStreams[stream];
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+ if (device == AUDIO_DEVICE_NONE) {
+ device = outputDesc->device();
+ }
+
+ ALOGVV("setStreamMute() stream %d, mute %d, output %d, mMuteCount %d device %04x",
+ stream, on, output, outputDesc->mMuteCount[stream], device);
+
+ if (on) {
+ if (outputDesc->mMuteCount[stream] == 0) {
+ if (streamDesc.mCanBeMuted &&
+ ((stream != AudioSystem::ENFORCED_AUDIBLE) ||
+ (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_NONE))) {
+ checkAndSetVolume(stream, 0, output, device, delayMs);
+ }
+ }
+ // increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored
+ outputDesc->mMuteCount[stream]++;
+ } else {
+ if (outputDesc->mMuteCount[stream] == 0) {
+ ALOGV("setStreamMute() unmuting non muted stream!");
+ return;
+ }
+ if (--outputDesc->mMuteCount[stream] == 0) {
+ checkAndSetVolume(stream,
+ streamDesc.getVolumeIndex(device),
+ output,
+ 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
+ const routing_strategy stream_strategy = getStrategy((AudioSystem::stream_type)stream);
+ if ((stream_strategy == STRATEGY_SONIFICATION) ||
+ ((stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL))) {
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mPrimaryOutput);
+ ALOGV("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)) {
+ ALOGV("handleIncallSonification() low visibility, muteCount %d", muteCount);
+ for (int i = 0; i < muteCount; i++) {
+ setStreamMute(stream, starting, mPrimaryOutput);
+ }
+ } else {
+ ALOGV("handleIncallSonification() high visibility");
+ if (outputDesc->device() &
+ getDeviceForStrategy(STRATEGY_PHONE, true /*fromCache*/)) {
+ ALOGV("handleIncallSonification() high visibility muted, muteCount %d", muteCount);
+ for (int i = 0; i < muteCount; i++) {
+ setStreamMute(stream, starting, mPrimaryOutput);
+ }
+ }
+ if (starting) {
+ mpClientInterface->startTone(ToneGenerator::TONE_SUP_CALL_WAITING, AudioSystem::VOICE_CALL);
+ } else {
+ mpClientInterface->stopTone();
+ }
+ }
+ }
+ }
+}
+
+bool AudioPolicyManagerBase::isInCall()
+{
+ return isStateInCall(mPhoneState);
+}
+
+bool AudioPolicyManagerBase::isStateInCall(int state) {
+ return ((state == AudioSystem::MODE_IN_CALL) ||
+ (state == AudioSystem::MODE_IN_COMMUNICATION));
+}
+
+uint32_t AudioPolicyManagerBase::getMaxEffectsCpuLoad()
+{
+ return MAX_EFFECTS_CPU_LOAD;
+}
+
+uint32_t AudioPolicyManagerBase::getMaxEffectsMemory()
+{
+ return MAX_EFFECTS_MEMORY;
+}
+
+// --- AudioOutputDescriptor class implementation
+
+AudioPolicyManagerBase::AudioOutputDescriptor::AudioOutputDescriptor(
+ const IOProfile *profile)
+ : mId(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT),
+ mChannelMask(0), mLatency(0),
+ mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE),
+ mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(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;
+ mStopTime[i] = 0;
+ }
+ for (int i = 0; i < NUM_STRATEGIES; i++) {
+ mStrategyMutedByDevice[i] = false;
+ }
+ if (profile != NULL) {
+ mSamplingRate = profile->mSamplingRates[0];
+ mFormat = profile->mFormats[0];
+ mChannelMask = profile->mChannelMasks[0];
+ mFlags = profile->mFlags;
+ }
+}
+
+audio_devices_t AudioPolicyManagerBase::AudioOutputDescriptor::device() const
+{
+ if (isDuplicated()) {
+ return (audio_devices_t)(mOutput1->mDevice | mOutput2->mDevice);
+ } else {
+ return mDevice;
+ }
+}
+
+uint32_t AudioPolicyManagerBase::AudioOutputDescriptor::latency()
+{
+ if (isDuplicated()) {
+ return (mOutput1->mLatency > mOutput2->mLatency) ? mOutput1->mLatency : mOutput2->mLatency;
+ } else {
+ return mLatency;
+ }
+}
+
+bool AudioPolicyManagerBase::AudioOutputDescriptor::sharesHwModuleWith(
+ const AudioOutputDescriptor *outputDesc)
+{
+ if (isDuplicated()) {
+ return mOutput1->sharesHwModuleWith(outputDesc) || mOutput2->sharesHwModuleWith(outputDesc);
+ } else if (outputDesc->isDuplicated()){
+ return sharesHwModuleWith(outputDesc->mOutput1) || sharesHwModuleWith(outputDesc->mOutput2);
+ } else {
+ return (mProfile->mModule == outputDesc->mProfile->mModule);
+ }
+}
+
+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) {
+ ALOGW("changeRefCount() invalid delta %d for stream %d, refCount %d", delta, stream, mRefCount[stream]);
+ mRefCount[stream] = 0;
+ return;
+ }
+ mRefCount[stream] += delta;
+ ALOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]);
+}
+
+audio_devices_t AudioPolicyManagerBase::AudioOutputDescriptor::supportedDevices()
+{
+ if (isDuplicated()) {
+ return (audio_devices_t)(mOutput1->supportedDevices() | mOutput2->supportedDevices());
+ } else {
+ return mProfile->mSupportedDevices ;
+ }
+}
+
+bool AudioPolicyManagerBase::AudioOutputDescriptor::isActive(uint32_t inPastMs) const
+{
+ return isStrategyActive(NUM_STRATEGIES, inPastMs);
+}
+
+bool AudioPolicyManagerBase::AudioOutputDescriptor::isStrategyActive(routing_strategy strategy,
+ uint32_t inPastMs,
+ nsecs_t sysTime) const
+{
+ if ((sysTime == 0) && (inPastMs != 0)) {
+ sysTime = systemTime();
+ }
+ for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
+ if (((getStrategy((AudioSystem::stream_type)i) == strategy) ||
+ (NUM_STRATEGIES == strategy)) &&
+ isStreamActive((AudioSystem::stream_type)i, inPastMs, sysTime)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AudioPolicyManagerBase::AudioOutputDescriptor::isStreamActive(AudioSystem::stream_type stream,
+ uint32_t inPastMs,
+ nsecs_t sysTime) const
+{
+ if (mRefCount[stream] != 0) {
+ return true;
+ }
+ if (inPastMs == 0) {
+ return false;
+ }
+ if (sysTime == 0) {
+ sysTime = systemTime();
+ }
+ if (ns2ms(sysTime - mStopTime[stream]) < inPastMs) {
+ return true;
+ }
+ return false;
+}
+
+
+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: %08x\n", mFormat);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask);
+ 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(const IOProfile *profile)
+ : mId(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0),
+ mDevice(AUDIO_DEVICE_NONE), mRefCount(0),
+ mInputSource(0), mProfile(profile)
+{
+ if (profile != NULL) {
+ mSamplingRate = profile->mSamplingRates[0];
+ mFormat = profile->mFormats[0];
+ mChannelMask = profile->mChannelMasks[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", mChannelMask);
+ 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
+
+AudioPolicyManagerBase::StreamDescriptor::StreamDescriptor()
+ : mIndexMin(0), mIndexMax(1), mCanBeMuted(true)
+{
+ mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT, 0);
+}
+
+int AudioPolicyManagerBase::StreamDescriptor::getVolumeIndex(audio_devices_t device)
+{
+ device = AudioPolicyManagerBase::getDeviceForVolume(device);
+ // there is always a valid entry for AUDIO_DEVICE_OUT_DEFAULT
+ if (mIndexCur.indexOfKey(device) < 0) {
+ device = AUDIO_DEVICE_OUT_DEFAULT;
+ }
+ return mIndexCur.valueFor(device);
+}
+
+void AudioPolicyManagerBase::StreamDescriptor::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "%s %02d %02d ",
+ mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax);
+ result.append(buffer);
+ for (size_t i = 0; i < mIndexCur.size(); i++) {
+ snprintf(buffer, SIZE, "%04x : %02d, ",
+ mIndexCur.keyAt(i),
+ mIndexCur.valueAt(i));
+ result.append(buffer);
+ }
+ result.append("\n");
+
+ write(fd, result.string(), result.size());
+}
+
+// --- EffectDescriptor class implementation
+
+status_t AudioPolicyManagerBase::EffectDescriptor::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, " I/O: %d\n", mIo);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Strategy: %d\n", mStrategy);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Session: %d\n", mSession);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Name: %s\n", mDesc.name);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " %s\n", mEnabled ? "Enabled" : "Disabled");
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+
+ return NO_ERROR;
+}
+
+// --- IOProfile class implementation
+
+AudioPolicyManagerBase::HwModule::HwModule(const char *name)
+ : mName(strndup(name, AUDIO_HARDWARE_MODULE_ID_MAX_LEN)), mHandle(0)
+{
+}
+
+AudioPolicyManagerBase::HwModule::~HwModule()
+{
+ for (size_t i = 0; i < mOutputProfiles.size(); i++) {
+ delete mOutputProfiles[i];
+ }
+ for (size_t i = 0; i < mInputProfiles.size(); i++) {
+ delete mInputProfiles[i];
+ }
+ free((void *)mName);
+}
+
+void AudioPolicyManagerBase::HwModule::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, " - name: %s\n", mName);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " - handle: %d\n", mHandle);
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ if (mOutputProfiles.size()) {
+ write(fd, " - outputs:\n", strlen(" - outputs:\n"));
+ for (size_t i = 0; i < mOutputProfiles.size(); i++) {
+ snprintf(buffer, SIZE, " output %zu:\n", i);
+ write(fd, buffer, strlen(buffer));
+ mOutputProfiles[i]->dump(fd);
+ }
+ }
+ if (mInputProfiles.size()) {
+ write(fd, " - inputs:\n", strlen(" - inputs:\n"));
+ for (size_t i = 0; i < mInputProfiles.size(); i++) {
+ snprintf(buffer, SIZE, " input %zu:\n", i);
+ write(fd, buffer, strlen(buffer));
+ mInputProfiles[i]->dump(fd);
+ }
+ }
+}
+
+AudioPolicyManagerBase::IOProfile::IOProfile(HwModule *module)
+ : mFlags((audio_output_flags_t)0), mModule(module)
+{
+}
+
+AudioPolicyManagerBase::IOProfile::~IOProfile()
+{
+}
+
+// checks if the IO profile is compatible with specified parameters.
+// Sampling rate, format and channel mask must be specified in order to
+// get a valid a match
+bool AudioPolicyManagerBase::IOProfile::isCompatibleProfile(audio_devices_t device,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_output_flags_t flags) const
+{
+ if (samplingRate == 0 || !audio_is_valid_format(format) || channelMask == 0) {
+ return false;
+ }
+
+ if ((mSupportedDevices & device) != device) {
+ return false;
+ }
+ if ((mFlags & flags) != flags) {
+ return false;
+ }
+ size_t i;
+ for (i = 0; i < mSamplingRates.size(); i++)
+ {
+ if (mSamplingRates[i] == samplingRate) {
+ break;
+ }
+ }
+ if (i == mSamplingRates.size()) {
+ return false;
+ }
+ for (i = 0; i < mFormats.size(); i++)
+ {
+ if (mFormats[i] == format) {
+ break;
+ }
+ }
+ if (i == mFormats.size()) {
+ return false;
+ }
+ for (i = 0; i < mChannelMasks.size(); i++)
+ {
+ if (mChannelMasks[i] == channelMask) {
+ break;
+ }
+ }
+ if (i == mChannelMasks.size()) {
+ return false;
+ }
+ return true;
+}
+
+void AudioPolicyManagerBase::IOProfile::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, " - sampling rates: ");
+ result.append(buffer);
+ for (size_t i = 0; i < mSamplingRates.size(); i++) {
+ snprintf(buffer, SIZE, "%d", mSamplingRates[i]);
+ result.append(buffer);
+ result.append(i == (mSamplingRates.size() - 1) ? "\n" : ", ");
+ }
+
+ snprintf(buffer, SIZE, " - channel masks: ");
+ result.append(buffer);
+ for (size_t i = 0; i < mChannelMasks.size(); i++) {
+ snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]);
+ result.append(buffer);
+ result.append(i == (mChannelMasks.size() - 1) ? "\n" : ", ");
+ }
+
+ snprintf(buffer, SIZE, " - formats: ");
+ result.append(buffer);
+ for (size_t i = 0; i < mFormats.size(); i++) {
+ snprintf(buffer, SIZE, "0x%08x", mFormats[i]);
+ result.append(buffer);
+ result.append(i == (mFormats.size() - 1) ? "\n" : ", ");
+ }
+
+ snprintf(buffer, SIZE, " - devices: 0x%04x\n", mSupportedDevices);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " - flags: 0x%04x\n", mFlags);
+ result.append(buffer);
+
+ write(fd, result.string(), result.size());
+}
+
+void AudioPolicyManagerBase::IOProfile::log()
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ ALOGV(" - sampling rates: ");
+ for (size_t i = 0; i < mSamplingRates.size(); i++) {
+ ALOGV(" %d", mSamplingRates[i]);
+ }
+
+ ALOGV(" - channel masks: ");
+ for (size_t i = 0; i < mChannelMasks.size(); i++) {
+ ALOGV(" 0x%04x", mChannelMasks[i]);
+ }
+
+ ALOGV(" - formats: ");
+ for (size_t i = 0; i < mFormats.size(); i++) {
+ ALOGV(" 0x%08x", mFormats[i]);
+ }
+
+ ALOGV(" - devices: 0x%04x\n", mSupportedDevices);
+ ALOGV(" - flags: 0x%04x\n", mFlags);
+}
+
+// --- audio_policy.conf file parsing
+
+struct StringToEnum {
+ const char *name;
+ uint32_t value;
+};
+
+#define STRING_TO_ENUM(string) { #string, string }
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+const struct StringToEnum sDeviceNameToEnumTable[] = {
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_EARPIECE),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPEAKER),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADSET),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADPHONE),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_SCO),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_A2DP),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_AUX_DIGITAL),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_DEVICE),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_ACCESSORY),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_USB),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_REMOTE_SUBMIX),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_WIRED_HEADSET),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_AUX_DIGITAL),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_VOICE_CALL),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_BACK_MIC),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_REMOTE_SUBMIX),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_ACCESSORY),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_DEVICE),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
+};
+
+const struct StringToEnum sFlagNameToEnumTable[] = {
+ STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT),
+ STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY),
+ STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_FAST),
+ STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
+ STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
+ STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING),
+};
+
+const struct StringToEnum sFormatNameToEnumTable[] = {
+ STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT),
+ STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT),
+ STRING_TO_ENUM(AUDIO_FORMAT_PCM_32_BIT),
+ STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_24_BIT),
+ STRING_TO_ENUM(AUDIO_FORMAT_PCM_FLOAT),
+ STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED),
+ STRING_TO_ENUM(AUDIO_FORMAT_MP3),
+ STRING_TO_ENUM(AUDIO_FORMAT_AAC),
+ STRING_TO_ENUM(AUDIO_FORMAT_VORBIS),
+ STRING_TO_ENUM(AUDIO_FORMAT_HE_AAC_V1),
+ STRING_TO_ENUM(AUDIO_FORMAT_HE_AAC_V2),
+ STRING_TO_ENUM(AUDIO_FORMAT_OPUS),
+ STRING_TO_ENUM(AUDIO_FORMAT_AC3),
+ STRING_TO_ENUM(AUDIO_FORMAT_E_AC3),
+};
+
+const struct StringToEnum sOutChannelsNameToEnumTable[] = {
+ STRING_TO_ENUM(AUDIO_CHANNEL_OUT_MONO),
+ STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO),
+ STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
+ STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
+};
+
+const struct StringToEnum sInChannelsNameToEnumTable[] = {
+ STRING_TO_ENUM(AUDIO_CHANNEL_IN_MONO),
+ STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO),
+ STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
+};
+
+
+uint32_t AudioPolicyManagerBase::stringToEnum(const struct StringToEnum *table,
+ size_t size,
+ const char *name)
+{
+ for (size_t i = 0; i < size; i++) {
+ if (strcmp(table[i].name, name) == 0) {
+ ALOGV("stringToEnum() found %s", table[i].name);
+ return table[i].value;
+ }
+ }
+ return 0;
+}
+
+bool AudioPolicyManagerBase::stringToBool(const char *value)
+{
+ return ((strcasecmp("true", value) == 0) || (strcmp("1", value) == 0));
+}
+
+audio_output_flags_t AudioPolicyManagerBase::parseFlagNames(char *name)
+{
+ uint32_t flag = 0;
+
+ // it is OK to cast name to non const here as we are not going to use it after
+ // strtok() modifies it
+ char *flagName = strtok(name, "|");
+ while (flagName != NULL) {
+ if (strlen(flagName) != 0) {
+ flag |= stringToEnum(sFlagNameToEnumTable,
+ ARRAY_SIZE(sFlagNameToEnumTable),
+ flagName);
+ }
+ flagName = strtok(NULL, "|");
+ }
+ //force direct flag if offload flag is set: offloading implies a direct output stream
+ // and all common behaviors are driven by checking only the direct flag
+ // this should normally be set appropriately in the policy configuration file
+ if ((flag & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+ flag |= AUDIO_OUTPUT_FLAG_DIRECT;
+ }
+
+ return (audio_output_flags_t)flag;
+}
+
+audio_devices_t AudioPolicyManagerBase::parseDeviceNames(char *name)
+{
+ uint32_t device = 0;
+
+ char *devName = strtok(name, "|");
+ while (devName != NULL) {
+ if (strlen(devName) != 0) {
+ device |= stringToEnum(sDeviceNameToEnumTable,
+ ARRAY_SIZE(sDeviceNameToEnumTable),
+ devName);
+ }
+ devName = strtok(NULL, "|");
+ }
+ return device;
+}
+
+void AudioPolicyManagerBase::loadSamplingRates(char *name, IOProfile *profile)
+{
+ char *str = strtok(name, "|");
+
+ // by convention, "0' in the first entry in mSamplingRates indicates the supported sampling
+ // rates should be read from the output stream after it is opened for the first time
+ if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+ profile->mSamplingRates.add(0);
+ return;
+ }
+
+ while (str != NULL) {
+ uint32_t rate = atoi(str);
+ if (rate != 0) {
+ ALOGV("loadSamplingRates() adding rate %d", rate);
+ profile->mSamplingRates.add(rate);
+ }
+ str = strtok(NULL, "|");
+ }
+ return;
+}
+
+void AudioPolicyManagerBase::loadFormats(char *name, IOProfile *profile)
+{
+ char *str = strtok(name, "|");
+
+ // by convention, "0' in the first entry in mFormats indicates the supported formats
+ // should be read from the output stream after it is opened for the first time
+ if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+ profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
+ return;
+ }
+
+ while (str != NULL) {
+ audio_format_t format = (audio_format_t)stringToEnum(sFormatNameToEnumTable,
+ ARRAY_SIZE(sFormatNameToEnumTable),
+ str);
+ if (format != AUDIO_FORMAT_DEFAULT) {
+ profile->mFormats.add(format);
+ }
+ str = strtok(NULL, "|");
+ }
+ return;
+}
+
+void AudioPolicyManagerBase::loadInChannels(char *name, IOProfile *profile)
+{
+ const char *str = strtok(name, "|");
+
+ ALOGV("loadInChannels() %s", name);
+
+ if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+ profile->mChannelMasks.add(0);
+ return;
+ }
+
+ while (str != NULL) {
+ audio_channel_mask_t channelMask =
+ (audio_channel_mask_t)stringToEnum(sInChannelsNameToEnumTable,
+ ARRAY_SIZE(sInChannelsNameToEnumTable),
+ str);
+ if (channelMask != 0) {
+ ALOGV("loadInChannels() adding channelMask %04x", channelMask);
+ profile->mChannelMasks.add(channelMask);
+ }
+ str = strtok(NULL, "|");
+ }
+ return;
+}
+
+void AudioPolicyManagerBase::loadOutChannels(char *name, IOProfile *profile)
+{
+ const char *str = strtok(name, "|");
+
+ ALOGV("loadOutChannels() %s", name);
+
+ // by convention, "0' in the first entry in mChannelMasks indicates the supported channel
+ // masks should be read from the output stream after it is opened for the first time
+ if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+ profile->mChannelMasks.add(0);
+ return;
+ }
+
+ while (str != NULL) {
+ audio_channel_mask_t channelMask =
+ (audio_channel_mask_t)stringToEnum(sOutChannelsNameToEnumTable,
+ ARRAY_SIZE(sOutChannelsNameToEnumTable),
+ str);
+ if (channelMask != 0) {
+ profile->mChannelMasks.add(channelMask);
+ }
+ str = strtok(NULL, "|");
+ }
+ return;
+}
+
+status_t AudioPolicyManagerBase::loadInput(cnode *root, HwModule *module)
+{
+ cnode *node = root->first_child;
+
+ IOProfile *profile = new IOProfile(module);
+
+ while (node) {
+ if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
+ loadSamplingRates((char *)node->value, profile);
+ } else if (strcmp(node->name, FORMATS_TAG) == 0) {
+ loadFormats((char *)node->value, profile);
+ } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
+ loadInChannels((char *)node->value, profile);
+ } else if (strcmp(node->name, DEVICES_TAG) == 0) {
+ profile->mSupportedDevices = parseDeviceNames((char *)node->value);
+ }
+ node = node->next;
+ }
+ ALOGW_IF(profile->mSupportedDevices == AUDIO_DEVICE_NONE,
+ "loadInput() invalid supported devices");
+ ALOGW_IF(profile->mChannelMasks.size() == 0,
+ "loadInput() invalid supported channel masks");
+ ALOGW_IF(profile->mSamplingRates.size() == 0,
+ "loadInput() invalid supported sampling rates");
+ ALOGW_IF(profile->mFormats.size() == 0,
+ "loadInput() invalid supported formats");
+ if ((profile->mSupportedDevices != AUDIO_DEVICE_NONE) &&
+ (profile->mChannelMasks.size() != 0) &&
+ (profile->mSamplingRates.size() != 0) &&
+ (profile->mFormats.size() != 0)) {
+
+ ALOGV("loadInput() adding input mSupportedDevices 0x%X", profile->mSupportedDevices);
+
+ module->mInputProfiles.add(profile);
+ return NO_ERROR;
+ } else {
+ delete profile;
+ return BAD_VALUE;
+ }
+}
+
+status_t AudioPolicyManagerBase::loadOutput(cnode *root, HwModule *module)
+{
+ cnode *node = root->first_child;
+
+ IOProfile *profile = new IOProfile(module);
+
+ while (node) {
+ if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
+ loadSamplingRates((char *)node->value, profile);
+ } else if (strcmp(node->name, FORMATS_TAG) == 0) {
+ loadFormats((char *)node->value, profile);
+ } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
+ loadOutChannels((char *)node->value, profile);
+ } else if (strcmp(node->name, DEVICES_TAG) == 0) {
+ profile->mSupportedDevices = parseDeviceNames((char *)node->value);
+ } else if (strcmp(node->name, FLAGS_TAG) == 0) {
+ profile->mFlags = parseFlagNames((char *)node->value);
+ }
+ node = node->next;
+ }
+ ALOGW_IF(profile->mSupportedDevices == AUDIO_DEVICE_NONE,
+ "loadOutput() invalid supported devices");
+ ALOGW_IF(profile->mChannelMasks.size() == 0,
+ "loadOutput() invalid supported channel masks");
+ ALOGW_IF(profile->mSamplingRates.size() == 0,
+ "loadOutput() invalid supported sampling rates");
+ ALOGW_IF(profile->mFormats.size() == 0,
+ "loadOutput() invalid supported formats");
+ if ((profile->mSupportedDevices != AUDIO_DEVICE_NONE) &&
+ (profile->mChannelMasks.size() != 0) &&
+ (profile->mSamplingRates.size() != 0) &&
+ (profile->mFormats.size() != 0)) {
+
+ ALOGV("loadOutput() adding output mSupportedDevices %04x, mFlags %04x",
+ profile->mSupportedDevices, profile->mFlags);
+
+ module->mOutputProfiles.add(profile);
+ return NO_ERROR;
+ } else {
+ delete profile;
+ return BAD_VALUE;
+ }
+}
+
+void AudioPolicyManagerBase::loadHwModule(cnode *root)
+{
+ cnode *node = config_find(root, OUTPUTS_TAG);
+ status_t status = NAME_NOT_FOUND;
+
+ HwModule *module = new HwModule(root->name);
+
+ if (node != NULL) {
+ if (strcmp(root->name, AUDIO_HARDWARE_MODULE_ID_A2DP) == 0) {
+ mHasA2dp = true;
+ } else if (strcmp(root->name, AUDIO_HARDWARE_MODULE_ID_USB) == 0) {
+ mHasUsb = true;
+ } else if (strcmp(root->name, AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX) == 0) {
+ mHasRemoteSubmix = true;
+ }
+
+ node = node->first_child;
+ while (node) {
+ ALOGV("loadHwModule() loading output %s", node->name);
+ status_t tmpStatus = loadOutput(node, module);
+ if (status == NAME_NOT_FOUND || status == NO_ERROR) {
+ status = tmpStatus;
+ }
+ node = node->next;
+ }
+ }
+ node = config_find(root, INPUTS_TAG);
+ if (node != NULL) {
+ node = node->first_child;
+ while (node) {
+ ALOGV("loadHwModule() loading input %s", node->name);
+ status_t tmpStatus = loadInput(node, module);
+ if (status == NAME_NOT_FOUND || status == NO_ERROR) {
+ status = tmpStatus;
+ }
+ node = node->next;
+ }
+ }
+ if (status == NO_ERROR) {
+ mHwModules.add(module);
+ } else {
+ delete module;
+ }
+}
+
+void AudioPolicyManagerBase::loadHwModules(cnode *root)
+{
+ cnode *node = config_find(root, AUDIO_HW_MODULE_TAG);
+ if (node == NULL) {
+ return;
+ }
+
+ node = node->first_child;
+ while (node) {
+ ALOGV("loadHwModules() loading module %s", node->name);
+ loadHwModule(node);
+ node = node->next;
+ }
+}
+
+void AudioPolicyManagerBase::loadGlobalConfig(cnode *root)
+{
+ cnode *node = config_find(root, GLOBAL_CONFIG_TAG);
+ if (node == NULL) {
+ return;
+ }
+ node = node->first_child;
+ while (node) {
+ if (strcmp(ATTACHED_OUTPUT_DEVICES_TAG, node->name) == 0) {
+ mAttachedOutputDevices = parseDeviceNames((char *)node->value);
+ ALOGW_IF(mAttachedOutputDevices == AUDIO_DEVICE_NONE,
+ "loadGlobalConfig() no attached output devices");
+ ALOGV("loadGlobalConfig() mAttachedOutputDevices %04x", mAttachedOutputDevices);
+ } else if (strcmp(DEFAULT_OUTPUT_DEVICE_TAG, node->name) == 0) {
+ mDefaultOutputDevice = (audio_devices_t)stringToEnum(sDeviceNameToEnumTable,
+ ARRAY_SIZE(sDeviceNameToEnumTable),
+ (char *)node->value);
+ ALOGW_IF(mDefaultOutputDevice == AUDIO_DEVICE_NONE,
+ "loadGlobalConfig() default device not specified");
+ ALOGV("loadGlobalConfig() mDefaultOutputDevice %04x", mDefaultOutputDevice);
+ } else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) {
+ mAvailableInputDevices = parseDeviceNames((char *)node->value) & ~AUDIO_DEVICE_BIT_IN;
+ ALOGV("loadGlobalConfig() mAvailableInputDevices %04x", mAvailableInputDevices);
+ } else if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) {
+ mSpeakerDrcEnabled = stringToBool((char *)node->value);
+ ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", mSpeakerDrcEnabled);
+ }
+ node = node->next;
+ }
+}
+
+status_t AudioPolicyManagerBase::loadAudioPolicyConfig(const char *path)
+{
+ cnode *root;
+ char *data;
+
+ data = (char *)load_file(path, NULL);
+ if (data == NULL) {
+ return -ENODEV;
+ }
+ root = config_node("", "");
+ config_load(root, data);
+
+ loadGlobalConfig(root);
+ loadHwModules(root);
+
+ config_free(root);
+ free(root);
+ free(data);
+
+ ALOGI("loadAudioPolicyConfig() loaded %s\n", path);
+
+ return NO_ERROR;
+}
+
+void AudioPolicyManagerBase::defaultAudioPolicyConfig(void)
+{
+ HwModule *module;
+ IOProfile *profile;
+
+ mDefaultOutputDevice = AUDIO_DEVICE_OUT_SPEAKER;
+ mAttachedOutputDevices = AUDIO_DEVICE_OUT_SPEAKER;
+ mAvailableInputDevices = AUDIO_DEVICE_IN_BUILTIN_MIC & ~AUDIO_DEVICE_BIT_IN;
+
+ module = new HwModule("primary");
+
+ profile = new IOProfile(module);
+ profile->mSamplingRates.add(44100);
+ profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
+ profile->mChannelMasks.add(AUDIO_CHANNEL_OUT_STEREO);
+ profile->mSupportedDevices = AUDIO_DEVICE_OUT_SPEAKER;
+ profile->mFlags = AUDIO_OUTPUT_FLAG_PRIMARY;
+ module->mOutputProfiles.add(profile);
+
+ profile = new IOProfile(module);
+ profile->mSamplingRates.add(8000);
+ profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
+ profile->mChannelMasks.add(AUDIO_CHANNEL_IN_MONO);
+ profile->mSupportedDevices = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ module->mInputProfiles.add(profile);
+
+ mHwModules.add(module);
+}
+
+}; // namespace android
diff --git a/legacy_hal/AudioPolicyManagerDefault.cpp b/legacy_hal/AudioPolicyManagerDefault.cpp
new file mode 100755
index 0000000..9083638
--- /dev/null
+++ b/legacy_hal/AudioPolicyManagerDefault.cpp
@@ -0,0 +1,34 @@
+/*
+ * 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 "AudioPolicyManagerDefault"
+//#define LOG_NDEBUG 0
+
+#include "AudioPolicyManagerDefault.h"
+
+namespace android_audio_legacy {
+
+extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
+{
+ return new AudioPolicyManagerDefault(clientInterface);
+}
+
+extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface)
+{
+ delete interface;
+}
+
+}; // namespace android
diff --git a/legacy_hal/AudioPolicyManagerDefault.h b/legacy_hal/AudioPolicyManagerDefault.h
new file mode 100755
index 0000000..0307976
--- /dev/null
+++ b/legacy_hal/AudioPolicyManagerDefault.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <hardware_legacy/AudioPolicyManagerBase.h>
+
+namespace android_audio_legacy {
+
+class AudioPolicyManagerDefault: public AudioPolicyManagerBase
+{
+
+public:
+ AudioPolicyManagerDefault(AudioPolicyClientInterface *clientInterface)
+ : AudioPolicyManagerBase(clientInterface) {}
+
+ virtual ~AudioPolicyManagerDefault() {}
+
+};
+};
diff --git a/legacy_hal/AudioUsbAudioHardware.h b/legacy_hal/AudioUsbAudioHardware.h
new file mode 100755
index 0000000..eadf0cf
--- /dev/null
+++ b/legacy_hal/AudioUsbAudioHardware.h
@@ -0,0 +1,172 @@
+#ifndef ANDROID_AUDIO_USBAUDIO_HARDWARE_H
+#define ANDROID_AUDIO_USBAUDIO_HARDWARE_H
+
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#define UA_Path "/proc/asound/card2/stream0"
+#define UA_Record_SampleRate 48000
+#define UA_Playback_SampleRate 48000
+#define RETRY_TIMES 10
+#define RETRY_SLEEPTIME 300*1000
+#define UA_Record_type "Capture"
+#define UA_Playback_type "Playback"
+#define UA_Format "Format"
+#define UA_Channels "Channels"
+#define UA_SampleRates "Rates"
+
+bool has_USBAudio_Speaker_MIC(const char *type)
+{
+ int fd;
+ char buf[2048] = {0};
+ char *str,tmp[6] = {0};
+
+ for(int i = 0; i < RETRY_TIMES; i++) {
+ fd = open(UA_Path,O_RDONLY);
+ if(fd < 0) {
+ ALOGV("Can not open /proc/asound/card2/stream0, try time = %d", i + 1);
+ usleep(RETRY_SLEEPTIME);
+ continue;
+ }
+ break;
+ }
+
+ if (fd < 0) {
+ ALOGE("Can't open /proc/asound/card2/stream0, giveup");
+ return false;
+ }
+
+ read(fd, buf, sizeof(buf));
+ str = strstr(buf, type);
+ close(fd);
+
+ if (str != NULL) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+uint32_t get_USBAudio_sampleRate(const char *type, uint32_t req_rate)
+{//support like this: Rates: 8000, 16000, 24000, 32000, 44100, 48000 or Rates: 48000
+ int fd;
+ uint32_t sampleRate = 0, lastSampleRate = 0;
+ char buf[2048]={0};
+ char *str;
+ ssize_t nbytes;
+
+ ALOGD("get_USBAudio_sampleRate() %s : req_rate %d", type, req_rate);
+
+ for(int i = 0; i < RETRY_TIMES; i++) {
+ fd = open(UA_Path,O_RDONLY);
+ if(fd < 0) {
+ ALOGV("Can not open /proc/asound/card2/stream0, try time = %d", i + 1);
+ usleep(RETRY_SLEEPTIME);
+ continue;
+ }
+ break;
+ }
+
+ if (fd < 0) {
+ ALOGE("Can't open /proc/asound/card2/stream0, giveup");
+ return 0;
+ }
+
+ read(fd, buf, sizeof(buf) - 1);
+ close(fd);
+
+ str = strstr(buf, type);
+ if(!str) return 0;
+
+ str = strstr(str, UA_SampleRates);//point to the param line
+ if(!str) return 0;
+
+ str += sizeof(UA_SampleRates);
+
+ nbytes = strlen(str);
+
+ //ALOGD("get_USBAudio_sampleRate() nbytes = %d, str = %s", nbytes, str);
+
+ while (nbytes > 0 && *str != '\n') {
+
+ while (nbytes > 0 && (*str > '9' || *str < '0') && *str != '\n') {
+ str++;
+ nbytes--;
+ }
+
+ if (*str == '\n') break;
+
+ sampleRate = atoi(str);
+
+ if (sampleRate == 0) {
+ sampleRate = lastSampleRate;
+ break;
+ }
+
+ ALOGV("get_USBAudio_sampleRate() Get rate : %d", sampleRate);
+
+ if (sampleRate >= req_rate)
+ break;
+
+ lastSampleRate = sampleRate;
+
+ while (nbytes > 0 && *str <= '9' && *str >= '0') {
+ str++;
+ nbytes--;
+ }
+ }
+
+ ALOGD("get_USBAudio_sampleRate() Get rate %d for %s", sampleRate, type);
+
+ return sampleRate;
+}
+
+uint32_t get_USBAudio_Channels(const char *type, uint32_t req_channel)
+{
+ int fd;
+ uint32_t channels = 0;
+ char *str;
+ char buf[2048]={0};
+
+ ALOGV("get_USBAudio_Channels() %s : req_rate %d", type, req_channel);
+
+ for (int i = 0; i < RETRY_TIMES; i++) {
+ fd = open(UA_Path, O_RDONLY);
+ if (fd < 0) {
+ ALOGD("Can not open /proc/asound/card2/stream0,try time =%d", i + 1);
+ usleep(RETRY_SLEEPTIME);
+ continue;
+ }
+ break;
+ }
+
+ if (fd < 0) {
+ ALOGE("Can't open /proc/asound/card2/stream0,giveup");
+ return 0;
+ }
+
+ read(fd, buf, sizeof(buf)-1);
+ close(fd);
+
+ str = strstr(buf, type);
+ if (!str) return 0;
+
+ str = strstr(str, UA_Channels);//point to the param line
+ str += sizeof(UA_Channels);
+ channels = atoi(str);
+
+ ALOGD("get_USBAudio_Channels() Get channels %d for %s",
+ channels, type);
+
+ return channels;
+}
+
+#endif
diff --git a/legacy_hal/alsa_audio.h b/legacy_hal/alsa_audio.h
new file mode 100755
index 0000000..101fa2a
--- /dev/null
+++ b/legacy_hal/alsa_audio.h
@@ -0,0 +1,167 @@
+/*
+** Copyright 2010, The Android Open-Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef _AUDIO_H_
+#define _AUDIO_H_
+
+#define PCM_OUT 0x00000000
+#define PCM_IN 0x10000000
+
+#define PCM_STEREO 0x00000000
+#define PCM_MONO 0x01000000
+
+#define PCM_44100HZ 0x00000000
+#define PCM_48000HZ 0x00100000
+#define PCM_8000HZ 0x00200000
+#define PCM_RATE_MASK 0x00F00000
+
+#define PCM_DEVICE0 0x00000000
+#define PCM_DEVICE1 0x00000010
+#define PCM_DEVICE2 0x00000020
+#define PCM_DEVICE_MASK 0x000000F0
+#define PCM_DEVICE_SHIFT 4
+
+#define PCM_CARD0 0x00000000
+#define PCM_CARD1 0x00000001
+#define PCM_CARD2 0x00000002
+#define PCM_CARD_MASK 0x0000000F
+#define PCM_CARD_SHIFT 0
+
+#define PCM_PERIOD_CNT_MIN 3
+#define PCM_PERIOD_CNT_SHIFT 16
+#define PCM_PERIOD_CNT_MASK (0xF << PCM_PERIOD_CNT_SHIFT)
+#define PCM_PERIOD_SZ_MIN 64
+#define PCM_PERIOD_SZ_SHIFT 12
+#define PCM_PERIOD_SZ_MASK (0xF << PCM_PERIOD_SZ_SHIFT)
+
+typedef enum _AudioRoute {
+ SPEAKER_NORMAL_ROUTE = 0,
+ SPEAKER_INCALL_ROUTE, // 1
+ SPEAKER_RINGTONE_ROUTE,
+ SPEAKER_VOIP_ROUTE,
+
+ EARPIECE_NORMAL_ROUTE, // 4
+ EARPIECE_INCALL_ROUTE,
+ EARPIECE_RINGTONE_ROUTE,
+ EARPIECE_VOIP_ROUTE,
+
+ HEADPHONE_NORMAL_ROUTE, // 8
+ HEADPHONE_INCALL_ROUTE,
+ HEADPHONE_RINGTONE_ROUTE,
+ SPEAKER_HEADPHONE_NORMAL_ROUTE,
+ SPEAKER_HEADPHONE_RINGTONE_ROUTE,
+ HEADPHONE_VOIP_ROUTE,
+
+ HEADSET_NORMAL_ROUTE, // 14
+ HEADSET_INCALL_ROUTE,
+ HEADSET_RINGTONE_ROUTE,
+ HEADSET_VOIP_ROUTE,
+
+ BLUETOOTH_NORMAL_ROUTE, // 18
+ BLUETOOTH_INCALL_ROUTE,
+ BLUETOOTH_VOIP_ROUTE,
+
+ MAIN_MIC_CAPTURE_ROUTE, // 21
+ HANDS_FREE_MIC_CAPTURE_ROUTE,
+ BLUETOOTH_SOC_MIC_CAPTURE_ROUTE,
+
+ PLAYBACK_OFF_ROUTE, // 24
+ CAPTURE_OFF_ROUTE,
+ INCALL_OFF_ROUTE,
+ VOIP_OFF_ROUTE,
+
+ HDMI_NORMAL_ROUTE, // 28
+
+ USB_NORMAL_ROUTE, // 29
+ USB_CAPTURE_ROUTE,
+
+ MAX_ROUTE, // 31
+} AudioRoute;
+
+#define PCM_ERROR_MAX 128
+
+struct pcm {
+ int fd;
+ unsigned flags;
+ int running:1;
+ int underruns;
+ unsigned buffer_size;
+ char error[PCM_ERROR_MAX];
+};
+
+/* Acquire/release a pcm channel.
+ * Returns non-zero on error
+ */
+struct pcm *pcm_open(unsigned flags);
+int pcm_close(struct pcm *pcm);
+int pcm_ready(struct pcm *pcm);
+
+/* Returns a human readable reason for the last error. */
+const char *pcm_error(struct pcm *pcm);
+
+/* Returns the buffer size (int bytes) that should be used for pcm_write.
+ * This will be 1/2 of the actual fifo size.
+ */
+unsigned pcm_buffer_size(struct pcm *pcm);
+
+/* Write data to the fifo.
+ * Will start playback on the first write or on a write that
+ * occurs after a fifo underrun.
+ */
+int pcm_write(struct pcm *pcm, void *data, unsigned count);
+int pcm_read(struct pcm *pcm, void *data, unsigned count);
+
+struct mixer_ctl {
+ struct mixer *mixer;
+ struct snd_ctl_elem_info *info;
+ struct snd_ctl_tlv *tlv;
+ char **ename;
+};
+
+struct mixer {
+ int fd;
+ struct snd_ctl_elem_info *info;
+ struct mixer_ctl *ctl;
+ unsigned count;
+};
+
+struct mixer *mixer_open(unsigned card);
+void mixer_close(struct mixer *mixer);
+void mixer_dump(struct mixer *mixer);
+
+struct mixer_ctl *mixer_get_control(struct mixer *mixer,
+ const char *name, unsigned index);
+struct mixer_ctl *mixer_get_nth_control(struct mixer *mixer, unsigned n);
+
+int mixer_ctl_set(struct mixer_ctl *ctl, unsigned percent);
+int mixer_ctl_select(struct mixer_ctl *ctl, const char *value);
+void mixer_ctl_print(struct mixer_ctl *ctl);
+int mixer_ctl_set_int_double(struct mixer_ctl *ctl, long long left, long long right);
+int mixer_ctl_set_int(struct mixer_ctl *ctl, long long value);
+int mixer_tlv_get_dB_range(unsigned int *tlv, long rangemin, long rangemax,
+ long *min, long *max);
+int mixer_get_ctl_minmax(struct mixer_ctl *ctl, long long *min, long long *max);
+int mixer_get_dB_range(struct mixer_ctl *ctl, long rangemin, long rangemax,
+ float *dB_min, float *dB_max, float *dB_step);
+
+int route_init(void);
+void route_uninit(void);
+int route_set_input_source(const char *source);
+int route_set_voice_volume(const char *ctlName, float volume);
+int route_set_controls(unsigned route);
+struct pcm *route_pcm_open(unsigned route, unsigned int flags);
+int route_pcm_close(unsigned route);
+#endif
diff --git a/legacy_hal/alsa_mixer.c b/legacy_hal/alsa_mixer.c
new file mode 100755
index 0000000..26bd353
--- /dev/null
+++ b/legacy_hal/alsa_mixer.c
@@ -0,0 +1,609 @@
+/*
+** Copyright 2010, The Android Open-Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <linux/ioctl.h>
+#define __force
+#define __bitwise
+#define __user
+#include "asound.h"
+#define LOG_TAG "alsa_mixer"
+
+//#define LOG_NDEBUG 0
+
+#include "alsa_audio.h"
+#include <cutils/log.h>
+
+#define MAX_SOUND_CARDS 10
+#define VOLUME_PERCENTS 90
+#define SOUND_CTL_PREFIX "/dev/snd/controlC%d"
+
+/* convert to index of integer array */
+#define int_index(size) (((size) + sizeof(int) - 1) / sizeof(int))
+/* max size of a TLV entry for dB information (including compound one) */
+#define MAX_TLV_RANGE_SIZE 256
+
+char *volume_controls_name_table[] = {
+ "Earpiece Playback Volume",
+ "Speaker Playback Volume",
+ "Headphone Playback Volume",
+ "PCM Playback Volume",
+ "Mic Capture Volume",
+};
+
+static const char *elem_iface_name(snd_ctl_elem_iface_t n)
+{
+ switch (n) {
+ case SNDRV_CTL_ELEM_IFACE_CARD: return "CARD";
+ case SNDRV_CTL_ELEM_IFACE_HWDEP: return "HWDEP";
+ case SNDRV_CTL_ELEM_IFACE_MIXER: return "MIXER";
+ case SNDRV_CTL_ELEM_IFACE_PCM: return "PCM";
+ case SNDRV_CTL_ELEM_IFACE_RAWMIDI: return "MIDI";
+ case SNDRV_CTL_ELEM_IFACE_TIMER: return "TIMER";
+ case SNDRV_CTL_ELEM_IFACE_SEQUENCER: return "SEQ";
+ default: return "???";
+ }
+}
+
+static const char *elem_type_name(snd_ctl_elem_type_t n)
+{
+ switch (n) {
+ case SNDRV_CTL_ELEM_TYPE_NONE: return "NONE";
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return "BOOL";
+ case SNDRV_CTL_ELEM_TYPE_INTEGER: return "INT32";
+ case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return "ENUM";
+ case SNDRV_CTL_ELEM_TYPE_BYTES: return "BYTES";
+ case SNDRV_CTL_ELEM_TYPE_IEC958: return "IEC958";
+ case SNDRV_CTL_ELEM_TYPE_INTEGER64: return "INT64";
+ default: return "???";
+ }
+}
+
+void mixer_close(struct mixer *mixer)
+{
+ unsigned n,m;
+
+ if (mixer->fd >= 0)
+ close(mixer->fd);
+
+ if (mixer->ctl) {
+ for (n = 0; n < mixer->count; n++) {
+ if (mixer->ctl[n].tlv)
+ free(mixer->ctl[n].tlv);
+ if (mixer->ctl[n].ename) {
+ unsigned max = mixer->ctl[n].info->value.enumerated.items;
+ for (m = 0; m < max; m++)
+ if(mixer->ctl[n].ename[m])
+ free(mixer->ctl[n].ename[m]);
+ if(mixer->ctl[n].ename[m])
+ free(mixer->ctl[n].ename);
+ }
+ }
+ free(mixer->ctl);
+ }
+
+ if (mixer->info)
+ free(mixer->info);
+
+ free(mixer);
+}
+
+struct mixer *mixer_open(unsigned card)
+{
+ char dname[sizeof(SOUND_CTL_PREFIX) + 20];
+ struct snd_ctl_elem_list elist;
+ struct snd_ctl_elem_info tmp;
+ struct snd_ctl_elem_id *eid = NULL;
+ struct mixer *mixer = NULL;
+ unsigned n, m, i, max = sizeof(volume_controls_name_table) / sizeof(char *);
+ int fd;
+
+ sprintf(dname, SOUND_CTL_PREFIX, card);
+
+ fd = open(dname, O_RDWR);
+
+ if (fd < 0) {
+ ALOGE("mixer_open() Can not open %s for card %d", dname, card);
+ return 0;
+ }
+
+ memset(&elist, 0, sizeof(elist));
+ if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
+ goto fail;
+
+ mixer = calloc(1, sizeof(*mixer));
+ if (!mixer)
+ goto fail;
+
+ mixer->ctl = calloc(elist.count, sizeof(struct mixer_ctl));
+ mixer->info = calloc(elist.count, sizeof(struct snd_ctl_elem_info));
+ if (!mixer->ctl || !mixer->info)
+ goto fail;
+
+ eid = calloc(elist.count, sizeof(struct snd_ctl_elem_id));
+ if (!eid)
+ goto fail;
+
+ mixer->count = elist.count;
+ mixer->fd = fd;
+ elist.space = mixer->count;
+ elist.pids = eid;
+ if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
+ goto fail;
+
+ for (n = 0; n < mixer->count; n++) {
+ struct snd_ctl_elem_info *ei = mixer->info + n;
+ ei->id.numid = eid[n].numid;
+ if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, ei) < 0)
+ goto fail;
+ mixer->ctl[n].info = ei;
+ mixer->ctl[n].mixer = mixer;
+ if (ei->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
+ char **enames = calloc(ei->value.enumerated.items, sizeof(char*));
+ if (!enames)
+ goto fail;
+ mixer->ctl[n].ename = enames;
+ for (m = 0; m < ei->value.enumerated.items; m++) {
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.id.numid = ei->id.numid;
+ tmp.value.enumerated.item = m;
+ if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, &tmp) < 0)
+ goto fail;
+ enames[m] = strdup(tmp.value.enumerated.name);
+ if (!enames[m])
+ goto fail;
+ }
+ }
+
+ //add for incall volume by Jear.Chen. get tlv.
+ for (i = 0; i < max; i++) {
+ if (!strcmp((char*) mixer->ctl[n].info->id.name, volume_controls_name_table[i]))
+ break;
+ }
+
+ if (i >= max) {
+ mixer->ctl[n].tlv = NULL;
+ continue;
+ }
+
+ if ((mixer->ctl[n].info->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) == 0) {
+ ALOGV("mixer_open() type of control %s is not TLVT_DB", mixer->ctl[n].info->id.name);
+ mixer->ctl[n].tlv = NULL;
+ continue;
+ }
+
+ unsigned int tlv_size = 2 * sizeof(unsigned int) + 2 * sizeof(unsigned int);
+ struct snd_ctl_tlv *tlv = malloc(sizeof(struct sndrv_ctl_tlv) + tlv_size);
+
+ //tlv->numid < (info->id.numid + info->count) and
+ //tlv->numid >= info->id.numid
+ tlv->numid = mixer->ctl[n].info->id.numid;
+ //length >= tlv.p[1] + 2 * sizeof(unsigned int);
+ //tlv.p is DECLARE_TLV_DB_SCALE defined in kernel
+ tlv->length = tlv_size;
+
+ if (ioctl(fd, SNDRV_CTL_IOCTL_TLV_READ, tlv) < 0) {
+ ALOGE("mixer_open() get tlv for control %s fail", mixer->ctl[n].info->id.name);
+ free(tlv);
+ mixer->ctl[n].tlv = tlv = NULL;
+ continue;
+ }
+
+ ALOGV("mixer_open() get tlv for control %s", mixer->ctl[n].info->id.name);
+ mixer->ctl[n].tlv = tlv;
+ //add for incall volume end
+ }
+
+ free(eid);
+ return mixer;
+
+fail:
+ if (eid)
+ free(eid);
+ if (mixer)
+ mixer_close(mixer);
+ else if (fd >= 0)
+ close(fd);
+ return 0;
+}
+
+void mixer_ctl_print(struct mixer_ctl *ctl)
+{
+ struct snd_ctl_elem_value ev;
+ struct snd_ctl_elem_info *ei = ctl->info;
+ unsigned m;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.id.numid = ctl->info->id.numid;
+ if (ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev))
+ return;
+ printf("%s:", ctl->info->id.name);
+
+ switch (ei->type) {
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+ for (m = 0; m < ei->count; m++)
+ printf(" %s", ev.value.integer.value[m] ? "ON" : "OFF");
+
+ printf(" { OFF=0, ON=1 }");
+ break;
+ case SNDRV_CTL_ELEM_TYPE_INTEGER:
+ for (m = 0; m < ei->count; m++)
+ printf(" %ld", ev.value.integer.value[m]);
+
+ printf(ei->value.integer.step ?
+ " { %ld-%ld, %ld }\n" : " { %ld-%ld }",
+ ei->value.integer.min,
+ ei->value.integer.max,
+ ei->value.integer.step);
+ break;
+ case SNDRV_CTL_ELEM_TYPE_INTEGER64:
+ for (m = 0; m < ei->count; m++)
+ printf(" %lld", ev.value.integer64.value[m]);
+
+ printf(ei->value.integer64.step ?
+ " { %lld-%lld, %lld }\n" : " { %lld-%lld }",
+ ei->value.integer64.min,
+ ei->value.integer64.max,
+ ei->value.integer64.step);
+ break;
+ case SNDRV_CTL_ELEM_TYPE_ENUMERATED: {
+ for (m = 0; m < ei->count; m++) {
+ unsigned v = ev.value.enumerated.item[m];
+ printf(" (%d %s)", v,
+ (v < ei->value.enumerated.items) ? ctl->ename[v] : "???");
+ }
+
+ printf(" { %s=0", ctl->ename[0]);
+ for (m = 1; m < ei->value.enumerated.items; m++)
+ printf(", %s=%d", ctl->ename[m],m);
+ printf(" }");
+ break;
+ }
+ default:
+ printf(" ???");
+ }
+ printf("\n");
+}
+
+void mixer_dump(struct mixer *mixer)
+{
+ unsigned n;
+
+ printf(" id iface dev sub idx num perms type name\n");
+ for (n = 0; n < mixer->count; n++) {
+ struct snd_ctl_elem_info *ei = mixer->info + n;
+
+ printf("%4d %5s %3d %3d %3d %3d %c%c%c%c%c%c%c%c%c %-6s ",
+ ei->id.numid, elem_iface_name(ei->id.iface),
+ ei->id.device, ei->id.subdevice, ei->id.index,
+ ei->count,
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_READ) ? 'r' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_WRITE) ? 'w' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_VOLATILE) ? 'V' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_TIMESTAMP) ? 'T' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) ? 'R' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) ? 'W' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) ? 'C' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE) ? 'I' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_LOCK) ? 'L' : ' ',
+ elem_type_name(ei->type));
+
+ mixer_ctl_print(mixer->ctl + n);
+ }
+}
+
+struct mixer_ctl *mixer_get_control(struct mixer *mixer,
+ const char *name, unsigned index)
+{
+ unsigned n;
+ for (n = 0; n < mixer->count; n++) {
+ if (mixer->info[n].id.index == index) {
+ if (!strcmp(name, (char*) mixer->info[n].id.name)) {
+ ALOGV("mixer_get_control() %s access 0x%08x",mixer->info[n].id.name,mixer->info[n].access);
+ return mixer->ctl + n;
+ }
+ }
+ }
+ return 0;
+}
+
+struct mixer_ctl *mixer_get_nth_control(struct mixer *mixer, unsigned n)
+{
+ if (n < mixer->count)
+ return mixer->ctl + n;
+ return 0;
+}
+
+static long scale_int(struct snd_ctl_elem_info *ei, unsigned _percent)
+{
+ long percent;
+ long range;
+
+ if (_percent > 100)
+ percent = 100;
+ else
+ percent = (long) _percent;
+
+ range = (ei->value.integer.max - ei->value.integer.min);
+
+ return ei->value.integer.min + (range * percent) / 100LL;
+}
+
+static long long scale_int64(struct snd_ctl_elem_info *ei, unsigned _percent)
+{
+ long long percent;
+ long long range;
+
+ if (_percent > 100)
+ percent = 100;
+ else
+ percent = (long) _percent;
+
+ range = (ei->value.integer.max - ei->value.integer.min) * 100LL;
+
+ return ei->value.integer.min + (range / percent);
+}
+
+int mixer_ctl_set(struct mixer_ctl *ctl, unsigned percent)
+{
+ struct snd_ctl_elem_value ev;
+ unsigned n;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.id.numid = ctl->info->id.numid;
+ switch (ctl->info->type) {
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+ for (n = 0; n < ctl->info->count; n++)
+ ev.value.integer.value[n] = !!percent;
+ break;
+ case SNDRV_CTL_ELEM_TYPE_INTEGER: {
+ long value = scale_int(ctl->info, percent);
+ for (n = 0; n < ctl->info->count; n++)
+ ev.value.integer.value[n] = value;
+ break;
+ }
+ case SNDRV_CTL_ELEM_TYPE_INTEGER64: {
+ long long value = scale_int64(ctl->info, percent);
+ for (n = 0; n < ctl->info->count; n++)
+ ev.value.integer64.value[n] = value;
+ break;
+ }
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
+}
+
+int mixer_ctl_select(struct mixer_ctl *ctl, const char *value)
+{
+ unsigned n, max;
+ struct snd_ctl_elem_value ev;
+
+ if (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ max = ctl->info->value.enumerated.items;
+ for (n = 0; n < max; n++) {
+ if (!strcmp(value, ctl->ename[n])) {
+ memset(&ev, 0, sizeof(ev));
+ ev.value.enumerated.item[0] = n;
+ ev.id.numid = ctl->info->id.numid;
+ if (ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev) < 0)
+ return -1;
+ return 0;
+ }
+ }
+
+ errno = EINVAL;
+ return -1;
+}
+
+//add for incall volume by Jear.Chen
+/*
+ set value to control
+*/
+
+int mixer_ctl_set_int_double(struct mixer_ctl *ctl, long long left, long long right)
+{
+ struct snd_ctl_elem_value ev;
+ unsigned n;
+ long long max, min, value = left;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.id.numid = ctl->info->id.numid;
+ switch (ctl->info->type) {
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+ for (n = 0; n < ctl->info->count; n++) {
+ ev.value.integer.value[n] = !!value;
+ value = right;
+ }
+ break;
+ case SNDRV_CTL_ELEM_TYPE_INTEGER: {
+ max = ctl->info->value.integer.max;
+ min = ctl->info->value.integer.min;
+
+ left = left > max ? max : left;
+ left = left < min ? min : left;
+ right = right > max ? max : right;
+ right = right < min ? min : right;
+
+ value = left;
+
+ for (n = 0; n < ctl->info->count; n++) {
+ ev.value.integer.value[n] = (long)value;
+ value = right;
+ }
+ break;
+ }
+ case SNDRV_CTL_ELEM_TYPE_INTEGER64: {
+ max = ctl->info->value.integer64.max;
+ min = ctl->info->value.integer64.min;
+
+ left = left > max ? max : left;
+ left = left < min ? min : left;
+ right = right > max ? max : right;
+ right = right < min ? min : right;
+
+ value = left;
+
+ for (n = 0; n < ctl->info->count; n++) {
+ ev.value.integer64.value[n] = value;
+ value = right;
+ }
+ break;
+ }
+ case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
+ max = ctl->info->value.enumerated.items;
+ return mixer_ctl_select(ctl, ctl->ename[value > max ? max : value]);
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
+}
+
+int mixer_ctl_set_int(struct mixer_ctl *ctl, long long value)
+{
+ return mixer_ctl_set_int_double(ctl, value, value);
+}
+
+/*
+ Get min and max value of control
+ */
+int mixer_get_ctl_minmax(struct mixer_ctl *ctl, long long *min, long long *max)
+{
+ struct snd_ctl_elem_info *ei = ctl->info;
+
+ switch (ei->type) {
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+ case SNDRV_CTL_ELEM_TYPE_INTEGER:
+ *min = ei->value.integer.min;
+ *max = ei->value.integer.max;
+ break;
+ case SNDRV_CTL_ELEM_TYPE_INTEGER64:
+ *min = ei->value.integer64.min;
+ *max = ei->value.integer64.max;
+ break;
+ case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
+ *min = 0;
+ *max = ei->value.enumerated.items;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ Get dB range from tlv[] which is obtained from control
+ */
+int mixer_tlv_get_dB_range(unsigned int *tlv, long rangemin, long rangemax,
+ long *min, long *max)
+{
+ int err;
+
+ switch (tlv[0]) {
+ case SND_CTL_TLVT_DB_RANGE: {
+ unsigned int pos, len;
+ len = int_index(tlv[1]);
+ if (len > MAX_TLV_RANGE_SIZE)
+ return -EINVAL;
+ pos = 2;
+ while (pos + 4 <= len) {
+ long rmin, rmax;
+ rangemin = (int)tlv[pos];
+ rangemax = (int)tlv[pos + 1];
+ err = mixer_tlv_get_dB_range(tlv + pos + 2,
+ rangemin, rangemax,
+ &rmin, &rmax);
+ if (err < 0)
+ return err;
+ if (pos > 2) {
+ if (rmin < *min)
+ *min = rmin;
+ if (rmax > *max)
+ *max = rmax;
+ } else {
+ *min = rmin;
+ *max = rmax;
+ }
+ pos += int_index(tlv[pos + 3]) + 4;
+ }
+ return 0;
+ }
+ case SND_CTL_TLVT_DB_SCALE: {
+ long step;
+ *min = (int)tlv[2];
+ step = (tlv[3] & 0xffff);
+ *max = *min + (long)(step * (rangemax - rangemin));
+ return 0;
+ }
+ case SND_CTL_TLVT_DB_MINMAX:
+ case SND_CTL_TLVT_DB_MINMAX_MUTE:
+ case SND_CTL_TLVT_DB_LINEAR:
+ *min = (int)tlv[2];
+ *max = (int)tlv[3];
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/*
+ Get dB range of control
+ */
+int mixer_get_dB_range(struct mixer_ctl *ctl, long rangemin, long rangemax,
+ float *dB_min, float *dB_max, float *dB_step)
+{
+ unsigned int *tlv;
+ long min, max;
+
+ if (ctl->tlv == NULL) {
+ ALOGE("mixer_get_dB_range() tlv of control %s is NULL", ctl->info->id.name);
+ return -EINVAL;
+ }
+
+ if (mixer_tlv_get_dB_range(ctl->tlv->tlv, rangemin, rangemax,
+ &min, &max) < 0) {
+ ALOGE("mixer_get_dB_range() get control dB range fail");
+ return -EINVAL;
+ }
+
+ *dB_min = min * 1.0 / 100;
+ *dB_max = max * 1.0 / 100;
+ *dB_step = (max - min) * 1.0 / (rangemax - rangemin) / 100;
+
+ ALOGV("control %s : dB min = %f, dB max = %f, dB step = %f",
+ ctl->info->id.name,
+ *dB_min,
+ *dB_max,
+ *dB_step);
+
+ return 0;
+}
+//add for incall volume end
diff --git a/legacy_hal/alsa_pcm.c b/legacy_hal/alsa_pcm.c
new file mode 100755
index 0000000..d2821b9
--- /dev/null
+++ b/legacy_hal/alsa_pcm.c
@@ -0,0 +1,594 @@
+/*
+** Copyright 2010, The Android Open-Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "alsa_pcm"
+//#define LOG_NDEBUG 0
+#include <cutils/log.h>
+#include <cutils/config_utils.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include <linux/ioctl.h>
+
+#include "alsa_audio.h"
+
+#define __force
+#define __bitwise
+#define __user
+#include "asound.h"
+
+#define PARAM_MAX SNDRV_PCM_HW_PARAM_LAST_INTERVAL
+
+int64_t last_read_time = 0;
+
+static int64_t systemTime()
+{
+ struct timespec t;
+ t.tv_sec = t.tv_nsec = 0;
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ return t.tv_sec*1000000000LL + t.tv_nsec;
+}
+
+static inline int param_is_mask(int p)
+{
+ return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
+ (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
+}
+
+static inline int param_is_interval(int p)
+{
+ return (p >= SNDRV_PCM_HW_PARAM_FIRST_INTERVAL) &&
+ (p <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL);
+}
+
+static inline struct snd_interval *param_to_interval(struct snd_pcm_hw_params *p, int n)
+{
+ return &(p->intervals[n - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]);
+}
+
+static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
+{
+ return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
+}
+
+static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit)
+{
+ if (bit >= SNDRV_MASK_MAX)
+ return;
+ if (param_is_mask(n)) {
+ struct snd_mask *m = param_to_mask(p, n);
+ m->bits[0] = 0;
+ m->bits[1] = 0;
+ m->bits[bit >> 5] |= (1 << (bit & 31));
+ }
+}
+
+static void param_set_min(struct snd_pcm_hw_params *p, int n, unsigned val)
+{
+ if (param_is_interval(n)) {
+ struct snd_interval *i = param_to_interval(p, n);
+ i->min = val;
+ }
+}
+
+static void param_set_max(struct snd_pcm_hw_params *p, int n, unsigned val)
+{
+ if (param_is_interval(n)) {
+ struct snd_interval *i = param_to_interval(p, n);
+ i->max = val;
+ }
+}
+
+static void param_set_int(struct snd_pcm_hw_params *p, int n, unsigned val)
+{
+ if (param_is_interval(n)) {
+ struct snd_interval *i = param_to_interval(p, n);
+ i->min = val;
+ i->max = val;
+ i->integer = 1;
+ }
+}
+
+static void param_init(struct snd_pcm_hw_params *p)
+{
+ int n;
+ memset(p, 0, sizeof(*p));
+ for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK;
+ n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) {
+ struct snd_mask *m = param_to_mask(p, n);
+ m->bits[0] = ~0;
+ m->bits[1] = ~0;
+ }
+ for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL;
+ n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) {
+ struct snd_interval *i = param_to_interval(p, n);
+ i->min = 0;
+ i->max = ~0;
+ }
+}
+
+/* debugging gunk */
+
+#if DEBUG
+static const char *param_name[PARAM_MAX+1] = {
+ [SNDRV_PCM_HW_PARAM_ACCESS] = "access",
+ [SNDRV_PCM_HW_PARAM_FORMAT] = "format",
+ [SNDRV_PCM_HW_PARAM_SUBFORMAT] = "subformat",
+
+ [SNDRV_PCM_HW_PARAM_SAMPLE_BITS] = "sample_bits",
+ [SNDRV_PCM_HW_PARAM_FRAME_BITS] = "frame_bits",
+ [SNDRV_PCM_HW_PARAM_CHANNELS] = "channels",
+ [SNDRV_PCM_HW_PARAM_RATE] = "rate",
+ [SNDRV_PCM_HW_PARAM_PERIOD_TIME] = "period_time",
+ [SNDRV_PCM_HW_PARAM_PERIOD_SIZE] = "period_size",
+ [SNDRV_PCM_HW_PARAM_PERIOD_BYTES] = "period_bytes",
+ [SNDRV_PCM_HW_PARAM_PERIODS] = "periods",
+ [SNDRV_PCM_HW_PARAM_BUFFER_TIME] = "buffer_time",
+ [SNDRV_PCM_HW_PARAM_BUFFER_SIZE] = "buffer_size",
+ [SNDRV_PCM_HW_PARAM_BUFFER_BYTES] = "buffer_bytes",
+ [SNDRV_PCM_HW_PARAM_TICK_TIME] = "tick_time",
+};
+
+static void param_dump(struct snd_pcm_hw_params *p)
+{
+ int n;
+
+ for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK;
+ n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) {
+ struct snd_mask *m = param_to_mask(p, n);
+ ALOGV("%s = %08x%08x\n", param_name[n],
+ m->bits[1], m->bits[0]);
+ }
+ for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL;
+ n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) {
+ struct snd_interval *i = param_to_interval(p, n);
+ ALOGV("%s = (%d,%d) omin=%d omax=%d int=%d empty=%d\n",
+ param_name[n], i->min, i->max, i->openmin,
+ i->openmax, i->integer, i->empty);
+ }
+ ALOGV("info = %08x\n", p->info);
+ ALOGV("msbits = %d\n", p->msbits);
+ ALOGV("rate = %d/%d\n", p->rate_num, p->rate_den);
+ ALOGV("fifo = %d\n", (int) p->fifo_size);
+}
+
+static void info_dump(struct snd_pcm_info *info)
+{
+ ALOGV("device = %d\n", info->device);
+ ALOGV("subdevice = %d\n", info->subdevice);
+ ALOGV("stream = %d\n", info->stream);
+ ALOGV("card = %d\n", info->card);
+ ALOGV("id = '%s'\n", info->id);
+ ALOGV("name = '%s'\n", info->name);
+ ALOGV("subname = '%s'\n", info->subname);
+ ALOGV("dev_class = %d\n", info->dev_class);
+ ALOGV("dev_subclass = %d\n", info->dev_subclass);
+ ALOGV("subdevices_count = %d\n", info->subdevices_count);
+ ALOGV("subdevices_avail = %d\n", info->subdevices_avail);
+}
+#else
+static void param_dump(struct snd_pcm_hw_params *p) {}
+static void info_dump(struct snd_pcm_info *info) {}
+#endif
+
+unsigned pcm_buffer_size(struct pcm *pcm)
+{
+ return pcm->buffer_size;
+}
+
+const char* pcm_error(struct pcm *pcm)
+{
+ return pcm->error;
+}
+
+static int oops(struct pcm *pcm, int e, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
+static int oops(struct pcm *pcm, int e, const char *fmt, ...)
+{
+ va_list ap;
+ int sz;
+
+ va_start(ap, fmt);
+ vsnprintf(pcm->error, PCM_ERROR_MAX, fmt, ap);
+ va_end(ap);
+ sz = strlen(pcm->error);
+
+ if (errno)
+ snprintf(pcm->error + sz, PCM_ERROR_MAX - sz,
+ ": %s", strerror(e));
+ return -1;
+}
+
+int pcm_write(struct pcm *pcm, void *data, unsigned count)
+{
+ struct snd_xferi x;
+
+ if (pcm->flags & PCM_IN)
+ return -EINVAL;
+
+ x.buf = data;
+ x.frames = (pcm->flags & PCM_MONO) ? (count / 2) : (count / 4);
+
+ for (;;) {
+ if (!pcm->running) {
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE))
+ return oops(pcm, errno, "cannot prepare channel");
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x))
+ return oops(pcm, errno, "cannot write initial data");
+ pcm->running = 1;
+ return 0;
+ }
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) {
+#ifdef SUPPORT_USB
+ //usb sound card out, so sleep for data and return no error.
+ unsigned int usleep_time = 0;
+ unsigned int frames = (pcm->flags & PCM_MONO) ? (count / 2) : (count / 4);
+
+ if ((pcm->flags & PCM_RATE_MASK) == PCM_8000HZ)
+ usleep_time = frames * 1000 * 1000 / 8000;
+ else if ((pcm->flags & PCM_RATE_MASK) == PCM_48000HZ)
+ usleep_time = frames * 1000 * 1000 / 48000;
+ else
+ usleep_time = frames * 1000 * 1000 / 44100;
+ usleep(usleep_time);
+
+ return 0;
+#endif
+ pcm->running = 0;
+ if (errno == EPIPE) {
+ /* we failed to make our window -- try to restart */
+ pcm->underruns++;
+ continue;
+ }
+ return oops(pcm, errno, "cannot write stream data");
+ }
+ return 0;
+ }
+}
+
+/********************************
+ author:charles chen
+ data:2012.09.27
+ parameter
+ data: the input data buf point
+ len: the input data len need consider the pcm_format
+ ret: 0:Left and right channel is valid
+ 1:Left channel is valid
+ 2:Right channel is valid
+
+defalt the input signal is like LRLRLR,default pcm_format is 16bit
+*********************************/
+#define SAMPLECOUNT 441*5*2*2
+int channalFlags = -1;//mean the channel is not checked now
+
+int startCheckCount = 0;
+
+int channel_check(void * data, unsigned len)
+{
+ short * pcmLeftChannel = (short *)data;
+ short * pcmRightChannel = pcmLeftChannel+1;
+ unsigned index = 0;
+ int leftValid = 0x0;
+ int rightValid = 0x0;
+ short checkValue = 0;
+
+ checkValue = *pcmLeftChannel;
+
+ //checkleft first
+ for(index = 0; index < len; index += 2)
+ {
+
+ if((pcmLeftChannel[index] >= checkValue+50)||(pcmLeftChannel[index] <= checkValue-50))
+ {
+ leftValid++;// = 0x01;
+ //ALOGI("-->pcmLeftChannel[%d] = %d checkValue %d leftValid %d",index,pcmLeftChannel[index],checkValue,leftValid);
+ //break;
+ }
+ }
+
+ if(leftValid >20)
+ leftValid = 0x01;
+ else
+ leftValid = 0;
+ checkValue = *pcmRightChannel;
+
+ //then check right
+ for(index = 0; index < len; index += 2)
+ {
+
+ if((pcmRightChannel[index] >= checkValue+50)||(pcmRightChannel[index] <= checkValue-50))
+ {
+ rightValid++;//= 0x02;
+ //ALOGI("-->pcmRightChannel[%d] = %d checkValue %d rightValid %d",index,pcmRightChannel[index],checkValue,rightValid);
+ //break;
+ }
+ }
+
+ if(rightValid >20)
+ rightValid = 0x02;
+ else
+ rightValid = 0;
+ ALOGI("leftValid %d rightValid %d",leftValid,rightValid);
+ return leftValid|rightValid;
+}
+
+void channel_fixed(void * data, unsigned len, int chFlag)
+{
+ //we just fixed when chFlag is 1 or 2.
+ if(chFlag <= 0 || chFlag > 2 )
+ return;
+
+ short * pcmValid = (short *)data;
+ short * pcmInvalid = pcmValid;
+
+ if(chFlag == 1)
+ pcmInvalid += 1;
+ else if (chFlag == 2)
+ pcmValid += 1;
+
+ unsigned index ;
+
+ for(index = 0; index < len; index += 2)
+ {
+ pcmInvalid[index] = pcmValid[index];
+ }
+ return;
+}
+int pcm_read(struct pcm *pcm, void *data, unsigned count)
+{
+ struct snd_xferi x;
+ int ret = 0;
+
+ if (!(pcm->flags & PCM_IN))
+ return -EINVAL;
+
+ x.buf = data;
+ x.frames = (pcm->flags & PCM_MONO) ? (count / 2) : (count / 4);
+
+// ALOGV("read() %d frames", x.frames);
+ for (;;) {
+ if (!pcm->running) {
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE))
+ return oops(pcm, errno, "cannot prepare channel");
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START))
+ return oops(pcm, errno, "cannot start channel");
+ pcm->running = 1;
+ }
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) {
+//#ifdef SUPPORT_USB
+ if (((pcm->flags & PCM_CARD_MASK) >> PCM_CARD_SHIFT) == PCM_CARD2) {
+ //usb sound card out, so set data to 0, and sleep for data
+ int need_usleep_time;
+ unsigned int usleep_time = 0;
+ unsigned int frames = (pcm->flags & PCM_MONO) ? (count / 2) : (count / 4);
+
+ if ((pcm->flags & PCM_RATE_MASK) == PCM_8000HZ)
+ usleep_time = frames * 1000 * 1000 / 8000;
+ else if ((pcm->flags & PCM_RATE_MASK) == PCM_48000HZ)
+ usleep_time = frames * 1000 * 1000 / 48000;
+ else
+ usleep_time = frames * 1000 * 1000 / 44100;
+
+ memset(data, 0, count);
+
+ if (last_read_time == 0)
+ last_read_time = systemTime();
+
+ need_usleep_time = usleep_time - (systemTime() - last_read_time) / 1000;
+ if (need_usleep_time > 0)
+ usleep(need_usleep_time);
+
+ last_read_time = systemTime();
+
+ return 0;
+ }
+//#endif
+ pcm->running = 0;
+ if (errno == EPIPE) {
+ /* we failed to make our window -- try to restart */
+ pcm->underruns++;
+ continue;
+ }
+ return oops(pcm, errno, "cannot read stream data");
+ }
+ last_read_time = systemTime();
+// ALOGV("read() got %d frames", x.frames);
+ if(!(pcm->flags & PCM_MONO))
+ {
+ //LOGI("read() get %d", x.frames);
+ if(channalFlags == -1 )
+ {
+ if(startCheckCount < SAMPLECOUNT)
+ {
+ startCheckCount += count;
+ }
+ else
+ {
+ channalFlags = channel_check(data,count/2);
+ }
+ }//if(channalFlags == -1)
+
+ channel_fixed(data,count/2, channalFlags);
+ }
+ return 0;
+ }
+}
+
+
+
+static struct pcm bad_pcm = {
+ .fd = -1,
+};
+
+int pcm_close(struct pcm *pcm)
+{
+ ALOGD("pcm_close() card %u, device %u, %s",
+ (pcm->flags & PCM_CARD_MASK) >> PCM_CARD_SHIFT,
+ (pcm->flags & PCM_DEVICE_MASK) >> PCM_DEVICE_SHIFT,
+ (pcm->flags & PCM_IN) ? "Capture" : "Playback");
+
+ if (pcm == &bad_pcm)
+ return 0;
+
+ if (pcm->fd >= 0)
+ close(pcm->fd);
+ pcm->running = 0;
+ pcm->buffer_size = 0;
+ pcm->fd = -1;
+ free(pcm);
+ return 0;
+}
+
+struct pcm *pcm_open(unsigned flags)
+{
+ const char *dfmt = "/dev/snd/pcmC%uD%u%c";
+ char dname[sizeof(dfmt) + 20];
+ struct pcm *pcm;
+ struct snd_pcm_info info;
+ struct snd_pcm_hw_params params;
+ struct snd_pcm_sw_params sparams;
+ unsigned card;
+ unsigned device;
+ unsigned period_sz;
+ unsigned period_cnt;
+
+ ALOGD("pcm_open(0x%08x)", flags);
+
+ pcm = calloc(1, sizeof(struct pcm));
+ if (!pcm)
+ return &bad_pcm;
+
+__open_again:
+
+ card = (flags & PCM_CARD_MASK) >> PCM_CARD_SHIFT;
+ device = (flags & PCM_DEVICE_MASK) >> PCM_DEVICE_SHIFT;
+
+ sprintf(dname, dfmt, card, device, flags & PCM_IN ? 'c' : 'p');
+
+ ALOGD("pcm_open() card %u, device %u, %s",
+ card, device, (flags & PCM_IN) ? "Capture" : "Playback");
+
+ pcm->flags = flags;
+ pcm->fd = open(dname, O_RDWR|O_CLOEXEC);
+ if (pcm->fd < 0) {
+ oops(pcm, errno, "cannot open device '%s'", dname);
+ if ((flags & PCM_CARD_MASK) == PCM_CARD1) {
+ ALOGD("Open sound card1 for HDMI error, open sound card0");
+ flags &= ~PCM_CARD_MASK;
+ goto __open_again;
+ }
+ return pcm;
+ }
+
+ while(pcm->fd == 0 || pcm->fd == 1 || pcm->fd == 2)
+ {
+ ALOGD("pcm_open old_fd=%d",pcm->fd);
+ int tmp_fd = pcm->fd;
+ pcm->fd = dup(tmp_fd);
+ close(tmp_fd);
+ ALOGD("pcm_open new_fd=%d",pcm->fd);
+ }
+
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_INFO, &info)) {
+ oops(pcm, errno, "cannot get info - %s", dname);
+ goto fail;
+ }
+ info_dump(&info);
+
+ ALOGV("pcm_open() period sz multiplier %d",
+ ((flags & PCM_PERIOD_SZ_MASK) >> PCM_PERIOD_SZ_SHIFT) + 1);
+ period_sz = PCM_PERIOD_SZ_MIN * (((flags & PCM_PERIOD_SZ_MASK) >> PCM_PERIOD_SZ_SHIFT) + 1);
+ ALOGV("pcm_open() period cnt %d",
+ ((flags & PCM_PERIOD_CNT_MASK) >> PCM_PERIOD_CNT_SHIFT) + PCM_PERIOD_CNT_MIN);
+ period_cnt = ((flags & PCM_PERIOD_CNT_MASK) >> PCM_PERIOD_CNT_SHIFT) + PCM_PERIOD_CNT_MIN;
+
+ ALOGV("pcm_open() period_cnt %d period_sz %d channels %d",
+ period_cnt, period_sz, (flags & PCM_MONO) ? 1 : 2);
+
+ param_init(&params);
+ param_set_mask(&params, SNDRV_PCM_HW_PARAM_ACCESS,
+ SNDRV_PCM_ACCESS_RW_INTERLEAVED);
+ param_set_mask(&params, SNDRV_PCM_HW_PARAM_FORMAT,
+ SNDRV_PCM_FORMAT_S16_LE);
+ param_set_mask(&params, SNDRV_PCM_HW_PARAM_SUBFORMAT,
+ SNDRV_PCM_SUBFORMAT_STD);
+
+ param_set_min(&params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, period_sz);
+ param_set_int(&params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16);
+ param_set_int(&params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
+ (flags & PCM_MONO) ? 16 : 32);
+ param_set_int(&params, SNDRV_PCM_HW_PARAM_CHANNELS,
+ (flags & PCM_MONO) ? 1 : 2);
+ param_set_int(&params, SNDRV_PCM_HW_PARAM_PERIODS, period_cnt);
+ if ((flags & PCM_RATE_MASK) == PCM_8000HZ) {
+ ALOGD("set audio rate 8KHz");
+ param_set_int(&params, SNDRV_PCM_HW_PARAM_RATE, 8000);
+ } else if ((flags & PCM_RATE_MASK) == PCM_48000HZ) {
+ ALOGD("set audio rate 48KHz");
+ param_set_int(&params, SNDRV_PCM_HW_PARAM_RATE, 48000);
+ } else
+ param_set_int(&params, SNDRV_PCM_HW_PARAM_RATE, 44100);
+
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, &params)) {
+ oops(pcm, errno, "cannot set hw params");
+ goto fail;
+ }
+ param_dump(&params);
+
+ memset(&sparams, 0, sizeof(sparams));
+ sparams.tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
+ sparams.period_step = 1;
+ sparams.avail_min = 1;
+ sparams.start_threshold = period_cnt * period_sz;
+ sparams.stop_threshold = period_cnt * period_sz;
+ sparams.xfer_align = period_sz / 2; /* needed for old kernels */
+ sparams.silence_size = 0;
+ sparams.silence_threshold = 0;
+
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) {
+ oops(pcm, errno, "cannot set sw params");
+ goto fail;
+ }
+
+ //Set prepare for device 1/2 of codec
+ if (device != 0 && card == 0) {
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE))
+ ALOGE("pcm_open() cannot set prepare for card %d, device %d", card, device);
+ }
+
+ pcm->buffer_size = period_cnt * period_sz;
+ pcm->underruns = 0;
+ return pcm;
+
+fail:
+ close(pcm->fd);
+ pcm->fd = -1;
+ return pcm;
+}
+
+int pcm_ready(struct pcm *pcm)
+{
+ return pcm->fd >= 0;
+}
diff --git a/legacy_hal/alsa_route.c b/legacy_hal/alsa_route.c
new file mode 100755
index 0000000..46ab9a3
--- /dev/null
+++ b/legacy_hal/alsa_route.c
@@ -0,0 +1,567 @@
+/*
+ * Copyright (C) 2015 Rockchip Electronics Co., Ltd.
+*/
+
+#define LOG_TAG "alsa_route"
+
+//#define LOG_NDEBUG 0
+
+#include <cutils/log.h>
+#include <cutils/config_utils.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <math.h>
+
+#include <linux/ioctl.h>
+#include "alsa_audio.h"
+
+#define __force
+#define __bitwise
+#define __user
+#include "asound.h"
+
+#include "codec_config/config_list.h"
+
+#define PCM_DEVICE0_PLAYBACK 0
+#define PCM_DEVICE0_CAPTURE 1
+#define PCM_DEVICE1_PLAYBACK 2
+#define PCM_DEVICE1_CAPTURE 3
+#define PCM_DEVICE2_PLAYBACK 4
+#define PCM_DEVICE2_CAPTURE 5
+
+#define PCM_MAX PCM_DEVICE2_CAPTURE
+
+const struct config_route_table *route_table;
+
+struct pcm* mPcm[PCM_MAX + 1];
+struct mixer* mMixerPlayback;
+struct mixer* mMixerCapture;
+
+int route_init(void)
+{
+ char soundCardID[20] = "";
+ static FILE * fp;
+ unsigned i, config_count = sizeof(sound_card_config_list) / sizeof(struct alsa_sound_card_config);
+ size_t read_size;
+
+ ALOGV("route_init()");
+
+ fp = fopen("/proc/asound/card0/id", "rt");
+ if (!fp) {
+ ALOGE("Open sound card0 id error!");
+ } else {
+ read_size = fread(soundCardID, sizeof(char), sizeof(soundCardID), fp);
+ fclose(fp);
+
+ if (soundCardID[read_size - 1] == '\n') {
+ read_size--;
+ soundCardID[read_size] = '\0';
+ }
+
+ ALOGV("Sound card0 is %s", soundCardID);
+
+ for (i = 0; i < config_count; i++) {
+ if (!(sound_card_config_list + i) || !sound_card_config_list[i].sound_card_name ||
+ !sound_card_config_list[i].route_table)
+ continue;
+
+ if (strncmp(sound_card_config_list[i].sound_card_name, soundCardID,
+ read_size) == 0) {
+ route_table = sound_card_config_list[i].route_table;
+ ALOGD("Get route table for sound card0 %s", soundCardID);
+ }
+ }
+ }
+
+ if (!route_table) {
+ route_table = &default_config_table;
+ ALOGD("Can not get config table for sound card0 %s, so get default config table.", soundCardID);
+ }
+
+ for (i = PCM_DEVICE0_PLAYBACK; i < PCM_MAX; i++)
+ mPcm[i] = NULL;
+
+ return 0;
+}
+
+void route_uninit(void)
+{
+ ALOGV("route_uninit()");
+
+ if (mPcm[PCM_DEVICE0_PLAYBACK]) {
+ route_pcm_close(PLAYBACK_OFF_ROUTE);
+ }
+
+ if (mPcm[PCM_DEVICE0_CAPTURE]) {
+ route_pcm_close(CAPTURE_OFF_ROUTE);
+ }
+}
+
+int is_playback_route(unsigned route)
+{
+ switch (route) {
+ case MAIN_MIC_CAPTURE_ROUTE:
+ case HANDS_FREE_MIC_CAPTURE_ROUTE:
+ case BLUETOOTH_SOC_MIC_CAPTURE_ROUTE:
+ case CAPTURE_OFF_ROUTE:
+ case USB_CAPTURE_ROUTE:
+ return 0;
+ case SPEAKER_NORMAL_ROUTE:
+ case SPEAKER_INCALL_ROUTE:
+ case SPEAKER_RINGTONE_ROUTE:
+ case SPEAKER_VOIP_ROUTE:
+ case EARPIECE_NORMAL_ROUTE:
+ case EARPIECE_INCALL_ROUTE:
+ case EARPIECE_RINGTONE_ROUTE:
+ case EARPIECE_VOIP_ROUTE:
+ case HEADPHONE_NORMAL_ROUTE:
+ case HEADPHONE_INCALL_ROUTE:
+ case HEADPHONE_RINGTONE_ROUTE:
+ case SPEAKER_HEADPHONE_NORMAL_ROUTE:
+ case SPEAKER_HEADPHONE_RINGTONE_ROUTE:
+ case HEADPHONE_VOIP_ROUTE:
+ case HEADSET_NORMAL_ROUTE:
+ case HEADSET_INCALL_ROUTE:
+ case HEADSET_RINGTONE_ROUTE:
+ case HEADSET_VOIP_ROUTE:
+ case BLUETOOTH_NORMAL_ROUTE:
+ case BLUETOOTH_INCALL_ROUTE:
+ case BLUETOOTH_VOIP_ROUTE:
+ case PLAYBACK_OFF_ROUTE:
+ case INCALL_OFF_ROUTE:
+ case VOIP_OFF_ROUTE:
+ case HDMI_NORMAL_ROUTE:
+ case USB_NORMAL_ROUTE:
+ return 1;
+ default:
+ ALOGE("is_playback_route() Error route %d", route);
+ return -EINVAL;
+ }
+}
+
+int route_set_input_source(const char *source)
+{
+ struct mixer* mMixer = mMixerCapture;
+
+ if (mMixer == NULL || source[0] == '\0') return 0;
+
+ struct mixer_ctl *ctl= mixer_get_control(mMixer, "Input Source", 0);
+
+ if (ctl == NULL)
+ return 0;
+
+ ALOGV("mixer_ctl_select, Input Source, (%s)", source);
+ return mixer_ctl_select(ctl, source);
+}
+
+int route_set_voice_volume(const char *ctlName, float volume)
+{
+ struct mixer* mMixer = mMixerPlayback;
+
+ if (mMixer == NULL || ctlName[0] == '\0')
+ return 0;
+
+ struct mixer_ctl *ctl = mixer_get_control(mMixer, ctlName, 0);
+ if (ctl == NULL)
+ return 0;
+
+ long long vol, vol_min, vol_max;
+ unsigned int Nmax = 6, N = volume * 5 + 1;
+ float e = 2.71828, dB_min, dB_max, dB_vol, dB_step, volFloat;
+
+ ALOGD("route_set_voice_volume() set incall voice volume %f to control %s", volume, ctlName);
+
+ if (mixer_get_ctl_minmax(ctl, &vol_min, &vol_max) < 0) {
+ ALOGE("mixer_get_dB_range() get control min max value fail");
+ return 0;
+ }
+
+ mixer_get_dB_range(ctl, (long)vol_min, (long)vol_max, &dB_min, &dB_max, &dB_step);
+
+ dB_vol = 20 * log((Nmax * pow(e, dB_min / 20) + N * (pow(e, dB_max / 20) - pow(e, dB_min / 20))) / Nmax);
+
+ volFloat = vol_min + (dB_vol - dB_min) / dB_step;
+ vol = (long long)volFloat;
+
+ if (((unsigned)(volFloat * 10) % 10) >= 5)
+ vol++;
+
+ ALOGV("dB_min = %f, dB_step = %f, dB_max = %f, dB_vol = %f",
+ dB_min,
+ dB_step,
+ dB_max,
+ dB_vol);
+
+ ALOGV("N = %u, volFloat = %f, vol = %lld", N, volFloat, vol);
+
+ return mixer_ctl_set_int(ctl, vol);
+}
+
+const struct config_route *get_route_config(unsigned route)
+{
+ ALOGV("get_route_config() route %d", route);
+
+ if (!route_table) {
+ ALOGE("get_route_config() route_table is NULL!");
+ return NULL;
+ }
+ switch (route) {
+ case SPEAKER_NORMAL_ROUTE:
+ return &(route_table->speaker_normal);
+ case SPEAKER_INCALL_ROUTE:
+ return &(route_table->speaker_incall);
+ case SPEAKER_RINGTONE_ROUTE:
+ return &(route_table->speaker_ringtone);
+ case SPEAKER_VOIP_ROUTE:
+ return &(route_table->speaker_voip);
+ case EARPIECE_NORMAL_ROUTE:
+ return &(route_table->earpiece_normal);
+ case EARPIECE_INCALL_ROUTE:
+ return &(route_table->earpiece_incall);
+ case EARPIECE_RINGTONE_ROUTE:
+ return &(route_table->earpiece_ringtone);
+ case EARPIECE_VOIP_ROUTE:
+ return &(route_table->earpiece_voip);
+ case HEADPHONE_NORMAL_ROUTE:
+ return &(route_table->headphone_normal);
+ case HEADPHONE_INCALL_ROUTE:
+ return &(route_table->headphone_incall);
+ case HEADPHONE_RINGTONE_ROUTE:
+ return &(route_table->headphone_ringtone);
+ case SPEAKER_HEADPHONE_NORMAL_ROUTE:
+ return &(route_table->speaker_headphone_normal);
+ case SPEAKER_HEADPHONE_RINGTONE_ROUTE:
+ return &(route_table->speaker_headphone_ringtone);
+ case HEADPHONE_VOIP_ROUTE:
+ return &(route_table->headphone_voip);
+ case HEADSET_NORMAL_ROUTE:
+ return &(route_table->headset_normal);
+ case HEADSET_INCALL_ROUTE:
+ return &(route_table->headset_incall);
+ case HEADSET_RINGTONE_ROUTE:
+ return &(route_table->headset_ringtone);
+ case HEADSET_VOIP_ROUTE:
+ return &(route_table->headset_voip);
+ case BLUETOOTH_NORMAL_ROUTE:
+ return &(route_table->bluetooth_normal);
+ case BLUETOOTH_INCALL_ROUTE:
+ return &(route_table->bluetooth_incall);
+ case BLUETOOTH_VOIP_ROUTE:
+ return &(route_table->bluetooth_voip);
+ case MAIN_MIC_CAPTURE_ROUTE:
+ return &(route_table->main_mic_capture);
+ case HANDS_FREE_MIC_CAPTURE_ROUTE:
+ return &(route_table->hands_free_mic_capture);
+ case BLUETOOTH_SOC_MIC_CAPTURE_ROUTE:
+ return &(route_table->bluetooth_sco_mic_capture);
+ case PLAYBACK_OFF_ROUTE:
+ return &(route_table->playback_off);
+ case CAPTURE_OFF_ROUTE:
+ return &(route_table->capture_off);
+ case INCALL_OFF_ROUTE:
+ return &(route_table->incall_off);
+ case VOIP_OFF_ROUTE:
+ return &(route_table->voip_off);
+ case HDMI_NORMAL_ROUTE:
+ return &(route_table->hdmi_normal);
+ case USB_NORMAL_ROUTE:
+ return &(route_table->usb_normal);
+ case USB_CAPTURE_ROUTE:
+ return &(route_table->usb_capture);
+ default:
+ ALOGE("get_route_config() Error route %d", route);
+ return NULL;
+ }
+}
+
+int set_controls(struct mixer *mixer, const struct config_control *ctls, const unsigned ctls_count)
+{
+ struct mixer_ctl *ctl;
+ unsigned i;
+
+ ALOGV("set_controls() ctls_count %d", ctls_count);
+
+ if (!ctls || ctls_count <= 0) {
+ ALOGV("set_controls() ctls is NULL");
+ return 0;
+ }
+
+ for (i = 0; i < ctls_count; i++) {
+ ctl = mixer_get_control(mixer, ctls[i].ctl_name, 0);
+ if (!ctl) {
+ ALOGE_IF(route_table != &default_config_table, "set_controls() Can not get ctl : %s", ctls[i].ctl_name);
+ ALOGV_IF(route_table == &default_config_table, "set_controls() Can not get ctl : %s", ctls[i].ctl_name);
+ return -EINVAL;
+ }
+
+ if (ctl->info->type != SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
+ ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER &&
+ ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER64 &&
+ ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
+ ALOGE("set_controls() ctl %s is not a type of INT or ENUMERATED", ctls[i].ctl_name);
+ return -EINVAL;
+ }
+
+ if (ctls[i].str_val) {
+ if (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
+ ALOGE("set_controls() ctl %s is not a type of ENUMERATED", ctls[i].ctl_name);
+ return -EINVAL;
+ }
+ if (mixer_ctl_select(ctl, ctls[i].str_val) != 0) {
+ ALOGE("set_controls() Can not set ctl %s to %s", ctls[i].ctl_name, ctls[i].str_val);
+ return -EINVAL;
+ }
+ ALOGV("set_controls() set ctl %s to %s", ctls[i].ctl_name, ctls[i].str_val);
+ } else {
+ if (mixer_ctl_set_int_double(ctl, ctls[i].int_val[0], ctls[i].int_val[1]) != 0) {
+ ALOGE("set_controls() can not set ctl %s to %d", ctls[i].ctl_name, ctls[i].int_val[0]);
+ return -EINVAL;
+ }
+ ALOGV("set_controls() set ctl %s to %d", ctls[i].ctl_name, ctls[i].int_val[0]);
+ }
+ }
+
+ return 0;
+}
+
+int route_set_controls(unsigned route)
+{
+ struct mixer* mMixer;
+
+ if (route >= MAX_ROUTE) {
+ ALOGE("route_set_controls() route %d error!", route);
+ return -EINVAL;
+ }
+
+#ifdef SUPPORT_USB //usb input maybe used for primary
+ if (route != USB_NORMAL_ROUTE &&
+ route != USB_CAPTURE_ROUTE &&
+ route != CAPTURE_OFF_ROUTE &&
+ route != MAIN_MIC_CAPTURE_ROUTE &&
+ route != HANDS_FREE_MIC_CAPTURE_ROUTE &&
+ route != BLUETOOTH_SOC_MIC_CAPTURE_ROUTE) {
+ ALOGV("route %d error for usb sound card!", route);
+ return -EINVAL;
+ }
+#else //primary input maybe used for usb
+ if (route > HDMI_NORMAL_ROUTE &&
+ route != USB_CAPTURE_ROUTE) {
+ ALOGV("route %d error for codec or hdmi!", route);
+ return -EINVAL;
+ }
+#endif
+
+ ALOGD("route_set_controls() set route %d", route);
+
+ mMixer = is_playback_route(route) ? mMixerPlayback : mMixerCapture;
+
+ if (!mMixer) {
+ ALOGE("route_set_controls() mMixer is NULL!");
+ return -EINVAL;
+ }
+
+ const struct config_route *route_info = get_route_config(route);
+ if (!route_info) {
+ ALOGE("route_set_controls() Can not get config of route");
+ return -EINVAL;
+ }
+
+ if (route_info->controls_count > 0)
+ set_controls(mMixer, route_info->controls, route_info->controls_count);
+
+ return 0;
+}
+
+struct pcm *route_pcm_open(unsigned route, unsigned int flags)
+{
+ int is_playback;
+
+ if (route >= MAX_ROUTE) {
+ ALOGE("route_pcm_open() route %d error!", route);
+ return NULL;
+ }
+
+#ifdef SUPPORT_USB //usb input maybe used for primary
+ if (route != USB_NORMAL_ROUTE &&
+ route != USB_CAPTURE_ROUTE &&
+ route != CAPTURE_OFF_ROUTE &&
+ route != MAIN_MIC_CAPTURE_ROUTE &&
+ route != HANDS_FREE_MIC_CAPTURE_ROUTE &&
+ route != BLUETOOTH_SOC_MIC_CAPTURE_ROUTE) {
+ ALOGV("route %d error for usb sound card!", route);
+ return NULL;
+ }
+#else //primary input maybe used for usb
+ if (route > BLUETOOTH_SOC_MIC_CAPTURE_ROUTE &&
+ route != HDMI_NORMAL_ROUTE &&
+ route != USB_CAPTURE_ROUTE) {
+ ALOGV("route %d error for codec or hdmi!", route);
+ return NULL;
+ }
+#endif
+
+ ALOGV("route_pcm_open() route %d", route);
+
+ is_playback = is_playback_route(route);
+
+ if (!route_table) {
+ route_init();
+ }
+
+ const struct config_route *route_info = get_route_config(route);
+ if (!route_info) {
+ ALOGE("route_pcm_open() Can not get config of route");
+ return NULL;
+ }
+
+ ALOGD("route_info->sound_card %d, route_info->devices 0 %s %s",
+ route_info->sound_card,
+ (route_info->devices == DEVICES_0_1 || route_info->devices == DEVICES_0_2 ||
+ route_info->devices == DEVICES_0_1_2) ? (route_info->devices == DEVICES_0_2 ? "2" : "1") : "",
+ route_info->devices == DEVICES_0_1_2 ? "2" : "");
+
+ flags &= ~PCM_CARD_MASK;
+ switch(route_info->sound_card) {
+ case 1:
+ flags |= PCM_CARD1;
+ break;
+ case 2:
+ flags |= PCM_CARD2;
+ break;
+ default:
+ flags |= PCM_CARD0;
+ break;
+ }
+
+ flags &= ~PCM_DEVICE_MASK;
+ flags |= PCM_DEVICE0;
+
+ if (is_playback) {
+ //close all route and pcm
+ if (mMixerPlayback) {
+ route_set_controls(INCALL_OFF_ROUTE);
+ route_set_controls(VOIP_OFF_ROUTE);
+ }
+ route_pcm_close(PLAYBACK_OFF_ROUTE);
+
+ mPcm[PCM_DEVICE0_PLAYBACK] = pcm_open(flags);
+
+ //Open playback and capture of device 1
+ if (((flags & PCM_CARD_MASK) == PCM_CARD0) &&
+ (route_info->devices == DEVICES_0_1 ||
+ route_info->devices == DEVICES_0_1_2)) {
+ unsigned int open_flags = flags;
+
+ open_flags &= ~PCM_DEVICE_MASK;
+ open_flags |= PCM_DEVICE1;
+
+ if (mPcm[PCM_DEVICE1_PLAYBACK] == NULL)
+ mPcm[PCM_DEVICE1_PLAYBACK] = pcm_open(open_flags);
+
+ open_flags |= PCM_IN;
+
+ if (mPcm[PCM_DEVICE1_CAPTURE] == NULL)
+ mPcm[PCM_DEVICE1_CAPTURE] = pcm_open(open_flags);
+ }
+
+ //Open playback and capture of device 2
+ if (((flags & PCM_CARD_MASK) == PCM_CARD0) &&
+ (route_info->devices == DEVICES_0_2 ||
+ route_info->devices == DEVICES_0_1_2)) {
+ unsigned int open_flags = flags;
+
+ open_flags &= ~PCM_DEVICE_MASK;
+ open_flags |= PCM_DEVICE2;
+
+ if (mPcm[PCM_DEVICE2_PLAYBACK] == NULL)
+ mPcm[PCM_DEVICE2_PLAYBACK] = pcm_open(open_flags);
+
+ open_flags |= PCM_IN;
+
+ if (mPcm[PCM_DEVICE2_CAPTURE] == NULL)
+ mPcm[PCM_DEVICE2_CAPTURE] = pcm_open(open_flags);
+ }
+ } else {
+ route_pcm_close(CAPTURE_OFF_ROUTE);
+
+ if (mPcm[PCM_DEVICE0_CAPTURE] == NULL)
+ mPcm[PCM_DEVICE0_CAPTURE] = pcm_open(flags);
+ }
+
+ //update mMixer
+ if (is_playback) {
+ if (mMixerPlayback == NULL)
+ mMixerPlayback = mixer_open(route_info->sound_card == 1 ? 0 : route_info->sound_card);
+ } else {
+ if (mMixerCapture == NULL)
+ mMixerCapture = mixer_open(route_info->sound_card == 1 ? 0 : route_info->sound_card);
+ }
+
+ //set controls
+ if (route_info->controls_count > 0)
+ route_set_controls(route);
+
+ return is_playback ? mPcm[PCM_DEVICE0_PLAYBACK] : mPcm[PCM_DEVICE0_CAPTURE];
+}
+
+int route_pcm_close(unsigned route)
+{
+ unsigned i;
+
+ if (route != PLAYBACK_OFF_ROUTE &&
+ route != CAPTURE_OFF_ROUTE &&
+ route != INCALL_OFF_ROUTE &&
+ route != VOIP_OFF_ROUTE) {
+ ALOGE("route_pcm_close() is not a off route");
+ return 0;
+ }
+
+ ALOGV("route_pcm_close() route %d", route);
+
+ //close pcm
+ if (route == PLAYBACK_OFF_ROUTE) {
+ if (mPcm[PCM_DEVICE0_PLAYBACK]) {
+ pcm_close(mPcm[PCM_DEVICE0_PLAYBACK]);
+ mPcm[PCM_DEVICE0_PLAYBACK] = NULL;
+ }
+
+ //close playback, we need to close device 1 and device 2
+ for (i = PCM_DEVICE1_PLAYBACK; i < PCM_MAX; i++) {
+ if (mPcm[i]) {
+ pcm_close(mPcm[i]);
+ mPcm[i] = NULL;
+ }
+ }
+ } else if (route == CAPTURE_OFF_ROUTE) {
+ if (mPcm[PCM_DEVICE0_CAPTURE]) {
+ pcm_close(mPcm[PCM_DEVICE0_CAPTURE]);
+ mPcm[PCM_DEVICE0_CAPTURE] = NULL;
+ }
+ }
+
+ //set controls
+ if (is_playback_route(route) ? mMixerPlayback : mMixerCapture)
+ route_set_controls(route);
+
+ //close mixer
+ if (route == PLAYBACK_OFF_ROUTE) {
+ if (mMixerPlayback) {
+ mixer_close(mMixerPlayback);
+ mMixerPlayback = NULL;
+ }
+ } else if (route == CAPTURE_OFF_ROUTE) {
+ if (mMixerCapture) {
+ mixer_close(mMixerCapture);
+ mMixerCapture = NULL;
+ }
+ }
+
+ return 0;
+}
+
diff --git a/legacy_hal/amix.c b/legacy_hal/amix.c
new file mode 100755
index 0000000..0a1a9a9
--- /dev/null
+++ b/legacy_hal/amix.c
@@ -0,0 +1,103 @@
+/*
+** Copyright 2010, The Android Open-Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "alsa_audio.h"
+
+
+struct mixer_ctl *get_ctl(struct mixer *mixer, char *name)
+{
+ char *p;
+ unsigned idx = 0;
+
+ if (isdigit(name[0]))
+ return mixer_get_nth_control(mixer, atoi(name) - 1);
+
+ p = strrchr(name, '#');
+ if (p) {
+ *p++ = 0;
+ idx = atoi(p);
+ }
+
+ return mixer_get_control(mixer, name, idx);
+}
+
+int main(int argc, char **argv)
+{
+ struct mixer *mixer;
+ struct mixer_ctl *ctl;
+ int card = 0;
+ int r, i, c;
+
+ for (i = 0; i < argc; i++) {
+ if ((strncmp(argv[i], "-c", sizeof(argv[i])) == 0) ||
+ (strncmp(argv[i], "-card", sizeof(argv[i])) == 0)) {
+
+ i++;
+ if (i >= argc) {
+ argc -= 1;
+ argv += 1;
+ break;
+ }
+
+ card = atoi(argv[i]);
+ argc -= 2;
+ argv += 2;
+ break;
+ }
+ }
+
+ printf("Card:%i\n", card);
+
+ mixer = mixer_open(card);
+
+ if (!mixer)
+ return -1;
+
+ if (argc == 1) {
+ mixer_dump(mixer);
+ return 0;
+ }
+
+ ctl = get_ctl(mixer, argv[1]);
+ argc -= 2;
+ argv += 2;
+
+ if (!ctl) {
+ printf("can't find control\n");
+ return -1;
+ }
+
+ if (argc) {
+ if (isdigit(argv[0][0]))
+ r = mixer_ctl_set_int(ctl, atoi(argv[0]));
+ else
+ r = mixer_ctl_select(ctl, argv[0]);
+ if (r)
+ printf("oops: %s\n", strerror(errno));
+ }
+
+ mixer_ctl_print(ctl);
+
+ mixer_close(mixer);
+
+ return 0;
+}
diff --git a/legacy_hal/asound.h b/legacy_hal/asound.h
new file mode 100755
index 0000000..0fdb029
--- /dev/null
+++ b/legacy_hal/asound.h
@@ -0,0 +1,836 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ *** This header was automatically generated from a Linux kernel header
+ *** of the same name, to make information necessary for userspace to
+ *** call into the kernel available to libc. It contains only constants,
+ *** structures, and macros generated from the original header, and thus,
+ *** contains no copyrightable information.
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef __SOUND_ASOUND_H
+#define __SOUND_ASOUND_H
+
+#include <linux/types.h>
+
+#define SNDRV_PROTOCOL_VERSION(major, minor, subminor) (((major)<<16)|((minor)<<8)|(subminor))
+#define SNDRV_PROTOCOL_MAJOR(version) (((version)>>16)&0xffff)
+#define SNDRV_PROTOCOL_MINOR(version) (((version)>>8)&0xff)
+#define SNDRV_PROTOCOL_MICRO(version) ((version)&0xff)
+#define SNDRV_PROTOCOL_INCOMPATIBLE(kversion, uversion) (SNDRV_PROTOCOL_MAJOR(kversion) != SNDRV_PROTOCOL_MAJOR(uversion) || (SNDRV_PROTOCOL_MAJOR(kversion) == SNDRV_PROTOCOL_MAJOR(uversion) && SNDRV_PROTOCOL_MINOR(kversion) != SNDRV_PROTOCOL_MINOR(uversion)))
+
+struct snd_aes_iec958 {
+ unsigned char status[24];
+ unsigned char subcode[147];
+ unsigned char pad;
+ unsigned char dig_subframe[4];
+};
+
+#define SNDRV_HWDEP_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 1)
+
+enum {
+ SNDRV_HWDEP_IFACE_OPL2 = 0,
+ SNDRV_HWDEP_IFACE_OPL3,
+ SNDRV_HWDEP_IFACE_OPL4,
+ SNDRV_HWDEP_IFACE_SB16CSP,
+ SNDRV_HWDEP_IFACE_EMU10K1,
+ SNDRV_HWDEP_IFACE_YSS225,
+ SNDRV_HWDEP_IFACE_ICS2115,
+ SNDRV_HWDEP_IFACE_SSCAPE,
+ SNDRV_HWDEP_IFACE_VX,
+ SNDRV_HWDEP_IFACE_MIXART,
+ SNDRV_HWDEP_IFACE_USX2Y,
+ SNDRV_HWDEP_IFACE_EMUX_WAVETABLE,
+ SNDRV_HWDEP_IFACE_BLUETOOTH,
+ SNDRV_HWDEP_IFACE_USX2Y_PCM,
+ SNDRV_HWDEP_IFACE_PCXHR,
+ SNDRV_HWDEP_IFACE_SB_RC,
+ SNDRV_HWDEP_IFACE_HDA,
+ SNDRV_HWDEP_IFACE_USB_STREAM,
+
+ SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_USB_STREAM
+};
+
+struct snd_hwdep_info {
+ unsigned int device;
+ int card;
+ unsigned char id[64];
+ unsigned char name[80];
+ int iface;
+ unsigned char reserved[64];
+};
+
+struct snd_hwdep_dsp_status {
+ unsigned int version;
+ unsigned char id[32];
+ unsigned int num_dsps;
+ unsigned int dsp_loaded;
+ unsigned int chip_ready;
+ unsigned char reserved[16];
+};
+
+struct snd_hwdep_dsp_image {
+ unsigned int index;
+ unsigned char name[64];
+ unsigned char __user *image;
+ size_t length;
+ unsigned long driver_data;
+};
+
+#define SNDRV_HWDEP_IOCTL_PVERSION _IOR ('H', 0x00, int)
+#define SNDRV_HWDEP_IOCTL_INFO _IOR ('H', 0x01, struct snd_hwdep_info)
+#define SNDRV_HWDEP_IOCTL_DSP_STATUS _IOR('H', 0x02, struct snd_hwdep_dsp_status)
+#define SNDRV_HWDEP_IOCTL_DSP_LOAD _IOW('H', 0x03, struct snd_hwdep_dsp_image)
+
+#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 10)
+
+typedef unsigned long snd_pcm_uframes_t;
+typedef signed long snd_pcm_sframes_t;
+
+enum {
+ SNDRV_PCM_CLASS_GENERIC = 0,
+ SNDRV_PCM_CLASS_MULTI,
+ SNDRV_PCM_CLASS_MODEM,
+ SNDRV_PCM_CLASS_DIGITIZER,
+
+ SNDRV_PCM_CLASS_LAST = SNDRV_PCM_CLASS_DIGITIZER,
+};
+
+enum {
+ SNDRV_PCM_SUBCLASS_GENERIC_MIX = 0,
+ SNDRV_PCM_SUBCLASS_MULTI_MIX,
+
+ SNDRV_PCM_SUBCLASS_LAST = SNDRV_PCM_SUBCLASS_MULTI_MIX,
+};
+
+enum {
+ SNDRV_PCM_STREAM_PLAYBACK = 0,
+ SNDRV_PCM_STREAM_CAPTURE,
+ SNDRV_PCM_STREAM_LAST = SNDRV_PCM_STREAM_CAPTURE,
+};
+
+typedef int __bitwise snd_pcm_access_t;
+#define SNDRV_PCM_ACCESS_MMAP_INTERLEAVED ((__force snd_pcm_access_t) 0)
+#define SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED ((__force snd_pcm_access_t) 1)
+#define SNDRV_PCM_ACCESS_MMAP_COMPLEX ((__force snd_pcm_access_t) 2)
+#define SNDRV_PCM_ACCESS_RW_INTERLEAVED ((__force snd_pcm_access_t) 3)
+#define SNDRV_PCM_ACCESS_RW_NONINTERLEAVED ((__force snd_pcm_access_t) 4)
+#define SNDRV_PCM_ACCESS_LAST SNDRV_PCM_ACCESS_RW_NONINTERLEAVED
+
+typedef int __bitwise snd_pcm_format_t;
+#define SNDRV_PCM_FORMAT_S8 ((__force snd_pcm_format_t) 0)
+#define SNDRV_PCM_FORMAT_U8 ((__force snd_pcm_format_t) 1)
+#define SNDRV_PCM_FORMAT_S16_LE ((__force snd_pcm_format_t) 2)
+#define SNDRV_PCM_FORMAT_S16_BE ((__force snd_pcm_format_t) 3)
+#define SNDRV_PCM_FORMAT_U16_LE ((__force snd_pcm_format_t) 4)
+#define SNDRV_PCM_FORMAT_U16_BE ((__force snd_pcm_format_t) 5)
+#define SNDRV_PCM_FORMAT_S24_LE ((__force snd_pcm_format_t) 6)
+#define SNDRV_PCM_FORMAT_S24_BE ((__force snd_pcm_format_t) 7)
+#define SNDRV_PCM_FORMAT_U24_LE ((__force snd_pcm_format_t) 8)
+#define SNDRV_PCM_FORMAT_U24_BE ((__force snd_pcm_format_t) 9)
+#define SNDRV_PCM_FORMAT_S32_LE ((__force snd_pcm_format_t) 10)
+#define SNDRV_PCM_FORMAT_S32_BE ((__force snd_pcm_format_t) 11)
+#define SNDRV_PCM_FORMAT_U32_LE ((__force snd_pcm_format_t) 12)
+#define SNDRV_PCM_FORMAT_U32_BE ((__force snd_pcm_format_t) 13)
+#define SNDRV_PCM_FORMAT_FLOAT_LE ((__force snd_pcm_format_t) 14)
+#define SNDRV_PCM_FORMAT_FLOAT_BE ((__force snd_pcm_format_t) 15)
+#define SNDRV_PCM_FORMAT_FLOAT64_LE ((__force snd_pcm_format_t) 16)
+#define SNDRV_PCM_FORMAT_FLOAT64_BE ((__force snd_pcm_format_t) 17)
+#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE ((__force snd_pcm_format_t) 18)
+#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE ((__force snd_pcm_format_t) 19)
+#define SNDRV_PCM_FORMAT_MU_LAW ((__force snd_pcm_format_t) 20)
+#define SNDRV_PCM_FORMAT_A_LAW ((__force snd_pcm_format_t) 21)
+#define SNDRV_PCM_FORMAT_IMA_ADPCM ((__force snd_pcm_format_t) 22)
+#define SNDRV_PCM_FORMAT_MPEG ((__force snd_pcm_format_t) 23)
+#define SNDRV_PCM_FORMAT_GSM ((__force snd_pcm_format_t) 24)
+#define SNDRV_PCM_FORMAT_SPECIAL ((__force snd_pcm_format_t) 31)
+#define SNDRV_PCM_FORMAT_S24_3LE ((__force snd_pcm_format_t) 32)
+#define SNDRV_PCM_FORMAT_S24_3BE ((__force snd_pcm_format_t) 33)
+#define SNDRV_PCM_FORMAT_U24_3LE ((__force snd_pcm_format_t) 34)
+#define SNDRV_PCM_FORMAT_U24_3BE ((__force snd_pcm_format_t) 35)
+#define SNDRV_PCM_FORMAT_S20_3LE ((__force snd_pcm_format_t) 36)
+#define SNDRV_PCM_FORMAT_S20_3BE ((__force snd_pcm_format_t) 37)
+#define SNDRV_PCM_FORMAT_U20_3LE ((__force snd_pcm_format_t) 38)
+#define SNDRV_PCM_FORMAT_U20_3BE ((__force snd_pcm_format_t) 39)
+#define SNDRV_PCM_FORMAT_S18_3LE ((__force snd_pcm_format_t) 40)
+#define SNDRV_PCM_FORMAT_S18_3BE ((__force snd_pcm_format_t) 41)
+#define SNDRV_PCM_FORMAT_U18_3LE ((__force snd_pcm_format_t) 42)
+#define SNDRV_PCM_FORMAT_U18_3BE ((__force snd_pcm_format_t) 43)
+#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_U18_3BE
+
+#ifdef SNDRV_LITTLE_ENDIAN
+#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE
+#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_LE
+#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_LE
+#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_LE
+#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_LE
+#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_LE
+#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_LE
+#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_LE
+#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE
+#endif
+#ifdef SNDRV_BIG_ENDIAN
+#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_BE
+#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_BE
+#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_BE
+#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_BE
+#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_BE
+#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_BE
+#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_BE
+#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_BE
+#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE
+#endif
+
+typedef int __bitwise snd_pcm_subformat_t;
+#define SNDRV_PCM_SUBFORMAT_STD ((__force snd_pcm_subformat_t) 0)
+#define SNDRV_PCM_SUBFORMAT_LAST SNDRV_PCM_SUBFORMAT_STD
+
+#define SNDRV_PCM_INFO_MMAP 0x00000001
+#define SNDRV_PCM_INFO_MMAP_VALID 0x00000002
+#define SNDRV_PCM_INFO_DOUBLE 0x00000004
+#define SNDRV_PCM_INFO_BATCH 0x00000010
+#define SNDRV_PCM_INFO_INTERLEAVED 0x00000100
+#define SNDRV_PCM_INFO_NONINTERLEAVED 0x00000200
+#define SNDRV_PCM_INFO_COMPLEX 0x00000400
+#define SNDRV_PCM_INFO_BLOCK_TRANSFER 0x00010000
+#define SNDRV_PCM_INFO_OVERRANGE 0x00020000
+#define SNDRV_PCM_INFO_RESUME 0x00040000
+#define SNDRV_PCM_INFO_PAUSE 0x00080000
+#define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000
+#define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000
+#define SNDRV_PCM_INFO_SYNC_START 0x00400000
+#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000
+
+typedef int __bitwise snd_pcm_state_t;
+#define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0)
+#define SNDRV_PCM_STATE_SETUP ((__force snd_pcm_state_t) 1)
+#define SNDRV_PCM_STATE_PREPARED ((__force snd_pcm_state_t) 2)
+#define SNDRV_PCM_STATE_RUNNING ((__force snd_pcm_state_t) 3)
+#define SNDRV_PCM_STATE_XRUN ((__force snd_pcm_state_t) 4)
+#define SNDRV_PCM_STATE_DRAINING ((__force snd_pcm_state_t) 5)
+#define SNDRV_PCM_STATE_PAUSED ((__force snd_pcm_state_t) 6)
+#define SNDRV_PCM_STATE_SUSPENDED ((__force snd_pcm_state_t) 7)
+#define SNDRV_PCM_STATE_DISCONNECTED ((__force snd_pcm_state_t) 8)
+#define SNDRV_PCM_STATE_LAST SNDRV_PCM_STATE_DISCONNECTED
+
+enum {
+ SNDRV_PCM_MMAP_OFFSET_DATA = 0x00000000,
+ SNDRV_PCM_MMAP_OFFSET_STATUS = 0x80000000,
+ SNDRV_PCM_MMAP_OFFSET_CONTROL = 0x81000000,
+};
+
+union snd_pcm_sync_id {
+ unsigned char id[16];
+ unsigned short id16[8];
+ unsigned int id32[4];
+};
+
+struct snd_pcm_info {
+ unsigned int device;
+ unsigned int subdevice;
+ int stream;
+ int card;
+ unsigned char id[64];
+ unsigned char name[80];
+ unsigned char subname[32];
+ int dev_class;
+ int dev_subclass;
+ unsigned int subdevices_count;
+ unsigned int subdevices_avail;
+ union snd_pcm_sync_id sync;
+ unsigned char reserved[64];
+};
+
+typedef int snd_pcm_hw_param_t;
+#define SNDRV_PCM_HW_PARAM_ACCESS 0
+#define SNDRV_PCM_HW_PARAM_FORMAT 1
+#define SNDRV_PCM_HW_PARAM_SUBFORMAT 2
+#define SNDRV_PCM_HW_PARAM_FIRST_MASK SNDRV_PCM_HW_PARAM_ACCESS
+#define SNDRV_PCM_HW_PARAM_LAST_MASK SNDRV_PCM_HW_PARAM_SUBFORMAT
+
+#define SNDRV_PCM_HW_PARAM_SAMPLE_BITS 8
+#define SNDRV_PCM_HW_PARAM_FRAME_BITS 9
+#define SNDRV_PCM_HW_PARAM_CHANNELS 10
+#define SNDRV_PCM_HW_PARAM_RATE 11
+#define SNDRV_PCM_HW_PARAM_PERIOD_TIME 12
+#define SNDRV_PCM_HW_PARAM_PERIOD_SIZE 13
+#define SNDRV_PCM_HW_PARAM_PERIOD_BYTES 14
+#define SNDRV_PCM_HW_PARAM_PERIODS 15
+#define SNDRV_PCM_HW_PARAM_BUFFER_TIME 16
+#define SNDRV_PCM_HW_PARAM_BUFFER_SIZE 17
+#define SNDRV_PCM_HW_PARAM_BUFFER_BYTES 18
+#define SNDRV_PCM_HW_PARAM_TICK_TIME 19
+#define SNDRV_PCM_HW_PARAM_FIRST_INTERVAL SNDRV_PCM_HW_PARAM_SAMPLE_BITS
+#define SNDRV_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_TICK_TIME
+
+#define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0)
+
+struct snd_interval {
+ unsigned int min, max;
+ unsigned int openmin:1,
+ openmax:1,
+ integer:1,
+ empty:1;
+};
+
+#define SNDRV_MASK_MAX 256
+
+struct snd_mask {
+ __u32 bits[(SNDRV_MASK_MAX+31)/32];
+};
+
+struct snd_pcm_hw_params {
+ unsigned int flags;
+ struct snd_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK -
+ SNDRV_PCM_HW_PARAM_FIRST_MASK + 1];
+ struct snd_mask mres[5];
+ struct snd_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL -
+ SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
+ struct snd_interval ires[9];
+ unsigned int rmask;
+ unsigned int cmask;
+ unsigned int info;
+ unsigned int msbits;
+ unsigned int rate_num;
+ unsigned int rate_den;
+ snd_pcm_uframes_t fifo_size;
+ unsigned char reserved[64];
+};
+
+enum {
+ SNDRV_PCM_TSTAMP_NONE = 0,
+ SNDRV_PCM_TSTAMP_ENABLE,
+ SNDRV_PCM_TSTAMP_LAST = SNDRV_PCM_TSTAMP_ENABLE,
+};
+
+struct snd_pcm_sw_params {
+ int tstamp_mode;
+ unsigned int period_step;
+ unsigned int sleep_min;
+ snd_pcm_uframes_t avail_min;
+ snd_pcm_uframes_t xfer_align;
+ snd_pcm_uframes_t start_threshold;
+ snd_pcm_uframes_t stop_threshold;
+ snd_pcm_uframes_t silence_threshold;
+ snd_pcm_uframes_t silence_size;
+ snd_pcm_uframes_t boundary;
+ unsigned char reserved[64];
+};
+
+struct snd_pcm_channel_info {
+ unsigned int channel;
+ __kernel_off_t offset;
+ unsigned int first;
+ unsigned int step;
+};
+
+struct snd_pcm_status {
+ snd_pcm_state_t state;
+ struct timespec trigger_tstamp;
+ struct timespec tstamp;
+ snd_pcm_uframes_t appl_ptr;
+ snd_pcm_uframes_t hw_ptr;
+ snd_pcm_sframes_t delay;
+ snd_pcm_uframes_t avail;
+ snd_pcm_uframes_t avail_max;
+ snd_pcm_uframes_t overrange;
+ snd_pcm_state_t suspended_state;
+ unsigned char reserved[60];
+};
+
+struct snd_pcm_mmap_status {
+ snd_pcm_state_t state;
+ int pad1;
+ snd_pcm_uframes_t hw_ptr;
+ struct timespec tstamp;
+ snd_pcm_state_t suspended_state;
+};
+
+struct snd_pcm_mmap_control {
+ snd_pcm_uframes_t appl_ptr;
+ snd_pcm_uframes_t avail_min;
+};
+
+#define SNDRV_PCM_SYNC_PTR_HWSYNC (1<<0)
+#define SNDRV_PCM_SYNC_PTR_APPL (1<<1)
+#define SNDRV_PCM_SYNC_PTR_AVAIL_MIN (1<<2)
+
+struct snd_pcm_sync_ptr {
+ unsigned int flags;
+ union {
+ struct snd_pcm_mmap_status status;
+ unsigned char reserved[64];
+ } s;
+ union {
+ struct snd_pcm_mmap_control control;
+ unsigned char reserved[64];
+ } c;
+};
+
+struct snd_xferi {
+ snd_pcm_sframes_t result;
+ void __user *buf;
+ snd_pcm_uframes_t frames;
+};
+
+struct snd_xfern {
+ snd_pcm_sframes_t result;
+ void __user * __user *bufs;
+ snd_pcm_uframes_t frames;
+};
+
+enum {
+ SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0,
+ SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,
+ SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,
+};
+
+#define SNDRV_PCM_IOCTL_PVERSION _IOR('A', 0x00, int)
+#define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct snd_pcm_info)
+#define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int)
+#define SNDRV_PCM_IOCTL_TTSTAMP _IOW('A', 0x03, int)
+#define SNDRV_PCM_IOCTL_HW_REFINE _IOWR('A', 0x10, struct snd_pcm_hw_params)
+#define SNDRV_PCM_IOCTL_HW_PARAMS _IOWR('A', 0x11, struct snd_pcm_hw_params)
+#define SNDRV_PCM_IOCTL_HW_FREE _IO('A', 0x12)
+#define SNDRV_PCM_IOCTL_SW_PARAMS _IOWR('A', 0x13, struct snd_pcm_sw_params)
+#define SNDRV_PCM_IOCTL_STATUS _IOR('A', 0x20, struct snd_pcm_status)
+#define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t)
+#define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22)
+#define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr)
+#define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info)
+#define SNDRV_PCM_IOCTL_PREPARE _IO('A', 0x40)
+#define SNDRV_PCM_IOCTL_RESET _IO('A', 0x41)
+#define SNDRV_PCM_IOCTL_START _IO('A', 0x42)
+#define SNDRV_PCM_IOCTL_DROP _IO('A', 0x43)
+#define SNDRV_PCM_IOCTL_DRAIN _IO('A', 0x44)
+#define SNDRV_PCM_IOCTL_PAUSE _IOW('A', 0x45, int)
+#define SNDRV_PCM_IOCTL_REWIND _IOW('A', 0x46, snd_pcm_uframes_t)
+#define SNDRV_PCM_IOCTL_RESUME _IO('A', 0x47)
+#define SNDRV_PCM_IOCTL_XRUN _IO('A', 0x48)
+#define SNDRV_PCM_IOCTL_FORWARD _IOW('A', 0x49, snd_pcm_uframes_t)
+#define SNDRV_PCM_IOCTL_WRITEI_FRAMES _IOW('A', 0x50, struct snd_xferi)
+#define SNDRV_PCM_IOCTL_READI_FRAMES _IOR('A', 0x51, struct snd_xferi)
+#define SNDRV_PCM_IOCTL_WRITEN_FRAMES _IOW('A', 0x52, struct snd_xfern)
+#define SNDRV_PCM_IOCTL_READN_FRAMES _IOR('A', 0x53, struct snd_xfern)
+#define SNDRV_PCM_IOCTL_LINK _IOW('A', 0x60, int)
+#define SNDRV_PCM_IOCTL_UNLINK _IO('A', 0x61)
+
+#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 0)
+
+enum {
+ SNDRV_RAWMIDI_STREAM_OUTPUT = 0,
+ SNDRV_RAWMIDI_STREAM_INPUT,
+ SNDRV_RAWMIDI_STREAM_LAST = SNDRV_RAWMIDI_STREAM_INPUT,
+};
+
+#define SNDRV_RAWMIDI_INFO_OUTPUT 0x00000001
+#define SNDRV_RAWMIDI_INFO_INPUT 0x00000002
+#define SNDRV_RAWMIDI_INFO_DUPLEX 0x00000004
+
+struct snd_rawmidi_info {
+ unsigned int device;
+ unsigned int subdevice;
+ int stream;
+ int card;
+ unsigned int flags;
+ unsigned char id[64];
+ unsigned char name[80];
+ unsigned char subname[32];
+ unsigned int subdevices_count;
+ unsigned int subdevices_avail;
+ unsigned char reserved[64];
+};
+
+struct snd_rawmidi_params {
+ int stream;
+ size_t buffer_size;
+ size_t avail_min;
+ unsigned int no_active_sensing: 1;
+ unsigned char reserved[16];
+};
+
+struct snd_rawmidi_status {
+ int stream;
+ struct timespec tstamp;
+ size_t avail;
+ size_t xruns;
+ unsigned char reserved[16];
+};
+
+#define SNDRV_RAWMIDI_IOCTL_PVERSION _IOR('W', 0x00, int)
+#define SNDRV_RAWMIDI_IOCTL_INFO _IOR('W', 0x01, struct snd_rawmidi_info)
+#define SNDRV_RAWMIDI_IOCTL_PARAMS _IOWR('W', 0x10, struct snd_rawmidi_params)
+#define SNDRV_RAWMIDI_IOCTL_STATUS _IOWR('W', 0x20, struct snd_rawmidi_status)
+#define SNDRV_RAWMIDI_IOCTL_DROP _IOW('W', 0x30, int)
+#define SNDRV_RAWMIDI_IOCTL_DRAIN _IOW('W', 0x31, int)
+
+#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6)
+
+enum {
+ SNDRV_TIMER_CLASS_NONE = -1,
+ SNDRV_TIMER_CLASS_SLAVE = 0,
+ SNDRV_TIMER_CLASS_GLOBAL,
+ SNDRV_TIMER_CLASS_CARD,
+ SNDRV_TIMER_CLASS_PCM,
+ SNDRV_TIMER_CLASS_LAST = SNDRV_TIMER_CLASS_PCM,
+};
+
+enum {
+ SNDRV_TIMER_SCLASS_NONE = 0,
+ SNDRV_TIMER_SCLASS_APPLICATION,
+ SNDRV_TIMER_SCLASS_SEQUENCER,
+ SNDRV_TIMER_SCLASS_OSS_SEQUENCER,
+ SNDRV_TIMER_SCLASS_LAST = SNDRV_TIMER_SCLASS_OSS_SEQUENCER,
+};
+
+#define SNDRV_TIMER_GLOBAL_SYSTEM 0
+#define SNDRV_TIMER_GLOBAL_RTC 1
+#define SNDRV_TIMER_GLOBAL_HPET 2
+#define SNDRV_TIMER_GLOBAL_HRTIMER 3
+
+#define SNDRV_TIMER_FLG_SLAVE (1<<0)
+
+struct snd_timer_id {
+ int dev_class;
+ int dev_sclass;
+ int card;
+ int device;
+ int subdevice;
+};
+
+struct snd_timer_ginfo {
+ struct snd_timer_id tid;
+ unsigned int flags;
+ int card;
+ unsigned char id[64];
+ unsigned char name[80];
+ unsigned long reserved0;
+ unsigned long resolution;
+ unsigned long resolution_min;
+ unsigned long resolution_max;
+ unsigned int clients;
+ unsigned char reserved[32];
+};
+
+struct snd_timer_gparams {
+ struct snd_timer_id tid;
+ unsigned long period_num;
+ unsigned long period_den;
+ unsigned char reserved[32];
+};
+
+struct snd_timer_gstatus {
+ struct snd_timer_id tid;
+ unsigned long resolution;
+ unsigned long resolution_num;
+ unsigned long resolution_den;
+ unsigned char reserved[32];
+};
+
+struct snd_timer_select {
+ struct snd_timer_id id;
+ unsigned char reserved[32];
+};
+
+struct snd_timer_info {
+ unsigned int flags;
+ int card;
+ unsigned char id[64];
+ unsigned char name[80];
+ unsigned long reserved0;
+ unsigned long resolution;
+ unsigned char reserved[64];
+};
+
+#define SNDRV_TIMER_PSFLG_AUTO (1<<0)
+#define SNDRV_TIMER_PSFLG_EXCLUSIVE (1<<1)
+#define SNDRV_TIMER_PSFLG_EARLY_EVENT (1<<2)
+
+struct snd_timer_params {
+ unsigned int flags;
+ unsigned int ticks;
+ unsigned int queue_size;
+ unsigned int reserved0;
+ unsigned int filter;
+ unsigned char reserved[60];
+};
+
+struct snd_timer_status {
+ struct timespec tstamp;
+ unsigned int resolution;
+ unsigned int lost;
+ unsigned int overrun;
+ unsigned int queue;
+ unsigned char reserved[64];
+};
+
+#define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int)
+#define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct snd_timer_id)
+#define SNDRV_TIMER_IOCTL_TREAD _IOW('T', 0x02, int)
+#define SNDRV_TIMER_IOCTL_GINFO _IOWR('T', 0x03, struct snd_timer_ginfo)
+#define SNDRV_TIMER_IOCTL_GPARAMS _IOW('T', 0x04, struct snd_timer_gparams)
+#define SNDRV_TIMER_IOCTL_GSTATUS _IOWR('T', 0x05, struct snd_timer_gstatus)
+#define SNDRV_TIMER_IOCTL_SELECT _IOW('T', 0x10, struct snd_timer_select)
+#define SNDRV_TIMER_IOCTL_INFO _IOR('T', 0x11, struct snd_timer_info)
+#define SNDRV_TIMER_IOCTL_PARAMS _IOW('T', 0x12, struct snd_timer_params)
+#define SNDRV_TIMER_IOCTL_STATUS _IOR('T', 0x14, struct snd_timer_status)
+
+#define SNDRV_TIMER_IOCTL_START _IO('T', 0xa0)
+#define SNDRV_TIMER_IOCTL_STOP _IO('T', 0xa1)
+#define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2)
+#define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3)
+
+struct snd_timer_read {
+ unsigned int resolution;
+ unsigned int ticks;
+};
+
+enum {
+ SNDRV_TIMER_EVENT_RESOLUTION = 0,
+ SNDRV_TIMER_EVENT_TICK,
+ SNDRV_TIMER_EVENT_START,
+ SNDRV_TIMER_EVENT_STOP,
+ SNDRV_TIMER_EVENT_CONTINUE,
+ SNDRV_TIMER_EVENT_PAUSE,
+ SNDRV_TIMER_EVENT_EARLY,
+ SNDRV_TIMER_EVENT_SUSPEND,
+ SNDRV_TIMER_EVENT_RESUME,
+
+ SNDRV_TIMER_EVENT_MSTART = SNDRV_TIMER_EVENT_START + 10,
+ SNDRV_TIMER_EVENT_MSTOP = SNDRV_TIMER_EVENT_STOP + 10,
+ SNDRV_TIMER_EVENT_MCONTINUE = SNDRV_TIMER_EVENT_CONTINUE + 10,
+ SNDRV_TIMER_EVENT_MPAUSE = SNDRV_TIMER_EVENT_PAUSE + 10,
+ SNDRV_TIMER_EVENT_MSUSPEND = SNDRV_TIMER_EVENT_SUSPEND + 10,
+ SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10,
+};
+
+struct snd_timer_tread {
+ int event;
+ struct timespec tstamp;
+ unsigned int val;
+};
+
+#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6)
+
+struct snd_ctl_card_info {
+ int card;
+ int pad;
+ unsigned char id[16];
+ unsigned char driver[16];
+ unsigned char name[32];
+ unsigned char longname[80];
+ unsigned char reserved_[16];
+ unsigned char mixername[80];
+ unsigned char components[128];
+};
+
+typedef int __bitwise snd_ctl_elem_type_t;
+#define SNDRV_CTL_ELEM_TYPE_NONE ((__force snd_ctl_elem_type_t) 0)
+#define SNDRV_CTL_ELEM_TYPE_BOOLEAN ((__force snd_ctl_elem_type_t) 1)
+#define SNDRV_CTL_ELEM_TYPE_INTEGER ((__force snd_ctl_elem_type_t) 2)
+#define SNDRV_CTL_ELEM_TYPE_ENUMERATED ((__force snd_ctl_elem_type_t) 3)
+#define SNDRV_CTL_ELEM_TYPE_BYTES ((__force snd_ctl_elem_type_t) 4)
+#define SNDRV_CTL_ELEM_TYPE_IEC958 ((__force snd_ctl_elem_type_t) 5)
+#define SNDRV_CTL_ELEM_TYPE_INTEGER64 ((__force snd_ctl_elem_type_t) 6)
+#define SNDRV_CTL_ELEM_TYPE_LAST SNDRV_CTL_ELEM_TYPE_INTEGER64
+
+typedef int __bitwise snd_ctl_elem_iface_t;
+#define SNDRV_CTL_ELEM_IFACE_CARD ((__force snd_ctl_elem_iface_t) 0)
+#define SNDRV_CTL_ELEM_IFACE_HWDEP ((__force snd_ctl_elem_iface_t) 1)
+#define SNDRV_CTL_ELEM_IFACE_MIXER ((__force snd_ctl_elem_iface_t) 2)
+#define SNDRV_CTL_ELEM_IFACE_PCM ((__force snd_ctl_elem_iface_t) 3)
+#define SNDRV_CTL_ELEM_IFACE_RAWMIDI ((__force snd_ctl_elem_iface_t) 4)
+#define SNDRV_CTL_ELEM_IFACE_TIMER ((__force snd_ctl_elem_iface_t) 5)
+#define SNDRV_CTL_ELEM_IFACE_SEQUENCER ((__force snd_ctl_elem_iface_t) 6)
+#define SNDRV_CTL_ELEM_IFACE_LAST SNDRV_CTL_ELEM_IFACE_SEQUENCER
+
+#define SNDRV_CTL_ELEM_ACCESS_READ (1<<0)
+#define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1)
+#define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE)
+#define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2)
+#define SNDRV_CTL_ELEM_ACCESS_TIMESTAMP (1<<3)
+#define SNDRV_CTL_ELEM_ACCESS_TLV_READ (1<<4)
+#define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE (1<<5)
+#define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE (SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE)
+#define SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND (1<<6)
+#define SNDRV_CTL_ELEM_ACCESS_INACTIVE (1<<8)
+#define SNDRV_CTL_ELEM_ACCESS_LOCK (1<<9)
+#define SNDRV_CTL_ELEM_ACCESS_OWNER (1<<10)
+#define SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK (1<<28)
+#define SNDRV_CTL_ELEM_ACCESS_USER (1<<29)
+
+#define SNDRV_CTL_POWER_D0 0x0000
+#define SNDRV_CTL_POWER_D1 0x0100
+#define SNDRV_CTL_POWER_D2 0x0200
+#define SNDRV_CTL_POWER_D3 0x0300
+#define SNDRV_CTL_POWER_D3hot (SNDRV_CTL_POWER_D3|0x0000)
+#define SNDRV_CTL_POWER_D3cold (SNDRV_CTL_POWER_D3|0x0001)
+
+/** TLV type - Container */
+#define SND_CTL_TLVT_CONTAINER 0x0000
+/** TLV type - basic dB scale */
+#define SND_CTL_TLVT_DB_SCALE 0x0001
+/** TLV type - linear volume */
+#define SND_CTL_TLVT_DB_LINEAR 0x0002
+/** TLV type - dB range container */
+#define SND_CTL_TLVT_DB_RANGE 0x0003
+/** TLV type - dB scale specified by min/max values */
+#define SND_CTL_TLVT_DB_MINMAX 0x0004
+/** TLV type - dB scale specified by min/max values (with mute) */
+#define SND_CTL_TLVT_DB_MINMAX_MUTE 0x0005
+
+/** Mute state */
+#define SND_CTL_TLV_DB_GAIN_MUTE -9999999
+
+struct sndrv_ctl_tlv {
+ unsigned int numid; /* control element numeric identification */
+ unsigned int length; /* in bytes aligned to 4 */
+ unsigned int tlv[0]; /* first TLV */
+};
+
+struct snd_ctl_elem_id {
+ unsigned int numid;
+ snd_ctl_elem_iface_t iface;
+ unsigned int device;
+ unsigned int subdevice;
+ unsigned char name[44];
+ unsigned int index;
+};
+
+struct snd_ctl_elem_list {
+ unsigned int offset;
+ unsigned int space;
+ unsigned int used;
+ unsigned int count;
+ struct snd_ctl_elem_id __user *pids;
+ unsigned char reserved[50];
+};
+
+struct snd_ctl_elem_info {
+ struct snd_ctl_elem_id id;
+ snd_ctl_elem_type_t type;
+ unsigned int access;
+ unsigned int count;
+ __kernel_pid_t owner;
+ union {
+ struct {
+ long min;
+ long max;
+ long step;
+ } integer;
+ struct {
+ long long min;
+ long long max;
+ long long step;
+ } integer64;
+ struct {
+ unsigned int items;
+ unsigned int item;
+ char name[64];
+ } enumerated;
+ unsigned char reserved[128];
+ } value;
+ union {
+ unsigned short d[4];
+ unsigned short *d_ptr;
+ } dimen;
+ unsigned char reserved[64-4*sizeof(unsigned short)];
+};
+
+struct snd_ctl_elem_value {
+ struct snd_ctl_elem_id id;
+ unsigned int indirect: 1;
+ union {
+ union {
+ long value[128];
+ long *value_ptr;
+ } integer;
+ union {
+ long long value[64];
+ long long *value_ptr;
+ } integer64;
+ union {
+ unsigned int item[128];
+ unsigned int *item_ptr;
+ } enumerated;
+ union {
+ unsigned char data[512];
+ unsigned char *data_ptr;
+ } bytes;
+ struct snd_aes_iec958 iec958;
+ } value;
+ struct timespec tstamp;
+ unsigned char reserved[128-sizeof(struct timespec)];
+};
+
+struct snd_ctl_tlv {
+ unsigned int numid;
+ unsigned int length;
+ unsigned int tlv[0];
+};
+
+#define SNDRV_CTL_IOCTL_PVERSION _IOR('U', 0x00, int)
+#define SNDRV_CTL_IOCTL_CARD_INFO _IOR('U', 0x01, struct snd_ctl_card_info)
+#define SNDRV_CTL_IOCTL_ELEM_LIST _IOWR('U', 0x10, struct snd_ctl_elem_list)
+#define SNDRV_CTL_IOCTL_ELEM_INFO _IOWR('U', 0x11, struct snd_ctl_elem_info)
+#define SNDRV_CTL_IOCTL_ELEM_READ _IOWR('U', 0x12, struct snd_ctl_elem_value)
+#define SNDRV_CTL_IOCTL_ELEM_WRITE _IOWR('U', 0x13, struct snd_ctl_elem_value)
+#define SNDRV_CTL_IOCTL_ELEM_LOCK _IOW('U', 0x14, struct snd_ctl_elem_id)
+#define SNDRV_CTL_IOCTL_ELEM_UNLOCK _IOW('U', 0x15, struct snd_ctl_elem_id)
+#define SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS _IOWR('U', 0x16, int)
+#define SNDRV_CTL_IOCTL_ELEM_ADD _IOWR('U', 0x17, struct snd_ctl_elem_info)
+#define SNDRV_CTL_IOCTL_ELEM_REPLACE _IOWR('U', 0x18, struct snd_ctl_elem_info)
+#define SNDRV_CTL_IOCTL_ELEM_REMOVE _IOWR('U', 0x19, struct snd_ctl_elem_id)
+#define SNDRV_CTL_IOCTL_TLV_READ _IOWR('U', 0x1a, struct snd_ctl_tlv)
+#define SNDRV_CTL_IOCTL_TLV_WRITE _IOWR('U', 0x1b, struct snd_ctl_tlv)
+#define SNDRV_CTL_IOCTL_TLV_COMMAND _IOWR('U', 0x1c, struct snd_ctl_tlv)
+#define SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE _IOWR('U', 0x20, int)
+#define SNDRV_CTL_IOCTL_HWDEP_INFO _IOR('U', 0x21, struct snd_hwdep_info)
+#define SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE _IOR('U', 0x30, int)
+#define SNDRV_CTL_IOCTL_PCM_INFO _IOWR('U', 0x31, struct snd_pcm_info)
+#define SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE _IOW('U', 0x32, int)
+#define SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE _IOWR('U', 0x40, int)
+#define SNDRV_CTL_IOCTL_RAWMIDI_INFO _IOWR('U', 0x41, struct snd_rawmidi_info)
+#define SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE _IOW('U', 0x42, int)
+#define SNDRV_CTL_IOCTL_POWER _IOWR('U', 0xd0, int)
+#define SNDRV_CTL_IOCTL_POWER_STATE _IOR('U', 0xd1, int)
+
+enum sndrv_ctl_event_type {
+ SNDRV_CTL_EVENT_ELEM = 0,
+ SNDRV_CTL_EVENT_LAST = SNDRV_CTL_EVENT_ELEM,
+};
+
+#define SNDRV_CTL_EVENT_MASK_VALUE (1<<0)
+#define SNDRV_CTL_EVENT_MASK_INFO (1<<1)
+#define SNDRV_CTL_EVENT_MASK_ADD (1<<2)
+#define SNDRV_CTL_EVENT_MASK_TLV (1<<3)
+#define SNDRV_CTL_EVENT_MASK_REMOVE (~0U)
+
+struct snd_ctl_event {
+ int type;
+ union {
+ struct {
+ unsigned int mask;
+ struct snd_ctl_elem_id id;
+ } elem;
+ unsigned char data8[60];
+ } data;
+};
+
+#define SNDRV_CTL_NAME_NONE ""
+#define SNDRV_CTL_NAME_PLAYBACK "Playback "
+#define SNDRV_CTL_NAME_CAPTURE "Capture "
+
+#define SNDRV_CTL_NAME_IEC958_NONE ""
+#define SNDRV_CTL_NAME_IEC958_SWITCH "Switch"
+#define SNDRV_CTL_NAME_IEC958_VOLUME "Volume"
+#define SNDRV_CTL_NAME_IEC958_DEFAULT "Default"
+#define SNDRV_CTL_NAME_IEC958_MASK "Mask"
+#define SNDRV_CTL_NAME_IEC958_CON_MASK "Con Mask"
+#define SNDRV_CTL_NAME_IEC958_PRO_MASK "Pro Mask"
+#define SNDRV_CTL_NAME_IEC958_PCM_STREAM "PCM Stream"
+#define SNDRV_CTL_NAME_IEC958(expl,direction,what) "IEC958 " expl SNDRV_CTL_NAME_##direction SNDRV_CTL_NAME_IEC958_##what
+
+#endif
+
diff --git a/legacy_hal/audio_hw_hal.cpp b/legacy_hal/audio_hw_hal.cpp
new file mode 100755
index 0000000..e207aa6
--- /dev/null
+++ b/legacy_hal/audio_hw_hal.cpp
@@ -0,0 +1,714 @@
+/*
+ * Copyright (C) 2011 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 "legacy_audio_hw_hal"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <hardware/audio.h>
+
+#include <hardware_legacy/AudioHardwareInterface.h>
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+namespace android_audio_legacy {
+
+extern "C" {
+
+struct legacy_audio_module {
+ struct audio_module module;
+};
+
+struct legacy_audio_device {
+ struct audio_hw_device device;
+
+ struct AudioHardwareInterface *hwif;
+};
+
+struct legacy_stream_out {
+ struct audio_stream_out stream;
+
+ AudioStreamOut *legacy_out;
+};
+
+struct legacy_stream_in {
+ struct audio_stream_in stream;
+
+ AudioStreamIn *legacy_in;
+};
+
+
+enum {
+ HAL_API_REV_1_0,
+ HAL_API_REV_2_0,
+ HAL_API_REV_NUM
+} hal_api_rev;
+
+static uint32_t audio_device_conv_table[][HAL_API_REV_NUM] =
+{
+ /* output devices */
+ { AudioSystem::DEVICE_OUT_EARPIECE, AUDIO_DEVICE_OUT_EARPIECE },
+ { AudioSystem::DEVICE_OUT_SPEAKER, AUDIO_DEVICE_OUT_SPEAKER },
+ { AudioSystem::DEVICE_OUT_WIRED_HEADSET, AUDIO_DEVICE_OUT_WIRED_HEADSET },
+ { AudioSystem::DEVICE_OUT_WIRED_HEADPHONE, AUDIO_DEVICE_OUT_WIRED_HEADPHONE },
+ { AudioSystem::DEVICE_OUT_BLUETOOTH_SCO, AUDIO_DEVICE_OUT_BLUETOOTH_SCO },
+ { AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET, AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET },
+ { AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT, AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT },
+ { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP },
+ { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES },
+ { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER },
+ { AudioSystem::DEVICE_OUT_AUX_DIGITAL, AUDIO_DEVICE_OUT_AUX_DIGITAL },
+ { AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET },
+ { AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET },
+ { AudioSystem::DEVICE_OUT_REMOTE_SUBMIX, AUDIO_DEVICE_OUT_REMOTE_SUBMIX },
+ { AudioSystem::DEVICE_OUT_DEFAULT, AUDIO_DEVICE_OUT_DEFAULT },
+ /* input devices */
+ { AudioSystem::DEVICE_IN_COMMUNICATION, AUDIO_DEVICE_IN_COMMUNICATION },
+ { AudioSystem::DEVICE_IN_AMBIENT, AUDIO_DEVICE_IN_AMBIENT },
+ { AudioSystem::DEVICE_IN_BUILTIN_MIC, AUDIO_DEVICE_IN_BUILTIN_MIC },
+ { AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET, AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET },
+ { AudioSystem::DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_WIRED_HEADSET },
+ { AudioSystem::DEVICE_IN_AUX_DIGITAL, AUDIO_DEVICE_IN_AUX_DIGITAL },
+ { AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET, AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET },
+ { AudioSystem::DEVICE_IN_VOICE_CALL, AUDIO_DEVICE_IN_VOICE_CALL },
+ { AudioSystem::DEVICE_IN_BACK_MIC, AUDIO_DEVICE_IN_BACK_MIC },
+ { AudioSystem::DEVICE_IN_REMOTE_SUBMIX, AUDIO_DEVICE_IN_REMOTE_SUBMIX },
+ { AudioSystem::DEVICE_IN_DEFAULT, AUDIO_DEVICE_IN_DEFAULT },
+};
+
+static uint32_t convert_audio_device(uint32_t from_device, int from_rev, int to_rev)
+{
+ const uint32_t k_num_devices = sizeof(audio_device_conv_table)/sizeof(uint32_t)/HAL_API_REV_NUM;
+ uint32_t to_device = AUDIO_DEVICE_NONE;
+ uint32_t in_bit = 0;
+
+ if (from_rev != HAL_API_REV_1_0) {
+ in_bit = from_device & AUDIO_DEVICE_BIT_IN;
+ from_device &= ~AUDIO_DEVICE_BIT_IN;
+ }
+
+ while (from_device) {
+ uint32_t i = 31 - __builtin_clz(from_device);
+ uint32_t cur_device = (1 << i) | in_bit;
+
+ for (i = 0; i < k_num_devices; i++) {
+ if (audio_device_conv_table[i][from_rev] == cur_device) {
+ to_device |= audio_device_conv_table[i][to_rev];
+ break;
+ }
+ }
+ from_device &= ~cur_device;
+ }
+ return to_device;
+}
+
+
+/** audio_stream_out implementation **/
+static uint32_t out_get_sample_rate(const struct audio_stream *stream)
+{
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->sampleRate();
+}
+
+static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+
+ ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ /* TODO: implement this */
+ return 0;
+}
+
+static size_t out_get_buffer_size(const struct audio_stream *stream)
+{
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->bufferSize();
+}
+
+static audio_channel_mask_t out_get_channels(const struct audio_stream *stream)
+{
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return (audio_channel_mask_t) out->legacy_out->channels();
+}
+
+static audio_format_t out_get_format(const struct audio_stream *stream)
+{
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ // legacy API, don't change return type
+ return (audio_format_t) out->legacy_out->format();
+}
+
+static int out_set_format(struct audio_stream *stream, audio_format_t format)
+{
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+ ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ /* TODO: implement me */
+ return 0;
+}
+
+static int out_standby(struct audio_stream *stream)
+{
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+ return out->legacy_out->standby();
+}
+
+static int out_dump(const struct audio_stream *stream, int fd)
+{
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ Vector<String16> args;
+ return out->legacy_out->dump(fd, args);
+}
+
+static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+ int val;
+ String8 s8 = String8(kvpairs);
+ AudioParameter parms = AudioParameter(String8(kvpairs));
+
+ if (parms.getInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val) == NO_ERROR) {
+ val = convert_audio_device(val, HAL_API_REV_2_0, HAL_API_REV_1_0);
+ parms.remove(String8(AUDIO_PARAMETER_STREAM_ROUTING));
+ parms.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val);
+ s8 = parms.toString();
+ }
+
+ return out->legacy_out->setParameters(s8);
+}
+
+static char * out_get_parameters(const struct audio_stream *stream, const char *keys)
+{
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ String8 s8;
+ int val;
+
+ s8 = out->legacy_out->getParameters(String8(keys));
+
+ AudioParameter parms = AudioParameter(s8);
+ if (parms.getInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val) == NO_ERROR) {
+ val = convert_audio_device(val, HAL_API_REV_1_0, HAL_API_REV_2_0);
+ parms.remove(String8(AUDIO_PARAMETER_STREAM_ROUTING));
+ parms.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val);
+ s8 = parms.toString();
+ }
+
+ return strdup(s8.string());
+}
+
+static uint32_t out_get_latency(const struct audio_stream_out *stream)
+{
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->latency();
+}
+
+static int out_set_volume(struct audio_stream_out *stream, float left,
+ float right)
+{
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+ return out->legacy_out->setVolume(left, right);
+}
+
+static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
+ size_t bytes)
+{
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+ return out->legacy_out->write(buffer, bytes);
+}
+
+static int out_get_render_position(const struct audio_stream_out *stream,
+ uint32_t *dsp_frames)
+{
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->getRenderPosition(dsp_frames);
+}
+
+static int out_get_next_write_timestamp(const struct audio_stream_out *stream,
+ int64_t *timestamp)
+{
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->getNextWriteTimestamp(timestamp);
+}
+
+static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ return 0;
+}
+
+static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ return 0;
+}
+
+/** audio_stream_in implementation **/
+static uint32_t in_get_sample_rate(const struct audio_stream *stream)
+{
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return in->legacy_in->sampleRate();
+}
+
+static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+ struct legacy_stream_in *in =
+ reinterpret_cast<struct legacy_stream_in *>(stream);
+
+ ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ /* TODO: implement this */
+ return 0;
+}
+
+static size_t in_get_buffer_size(const struct audio_stream *stream)
+{
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return in->legacy_in->bufferSize();
+}
+
+static audio_channel_mask_t in_get_channels(const struct audio_stream *stream)
+{
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return (audio_channel_mask_t) in->legacy_in->channels();
+}
+
+static audio_format_t in_get_format(const struct audio_stream *stream)
+{
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ // legacy API, don't change return type
+ return (audio_format_t) in->legacy_in->format();
+}
+
+static int in_set_format(struct audio_stream *stream, audio_format_t format)
+{
+ struct legacy_stream_in *in =
+ reinterpret_cast<struct legacy_stream_in *>(stream);
+ ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ /* TODO: implement me */
+ return 0;
+}
+
+static int in_standby(struct audio_stream *stream)
+{
+ struct legacy_stream_in *in = reinterpret_cast<struct legacy_stream_in *>(stream);
+ return in->legacy_in->standby();
+}
+
+static int in_dump(const struct audio_stream *stream, int fd)
+{
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ Vector<String16> args;
+ return in->legacy_in->dump(fd, args);
+}
+
+static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+ struct legacy_stream_in *in =
+ reinterpret_cast<struct legacy_stream_in *>(stream);
+ int val;
+ AudioParameter parms = AudioParameter(String8(kvpairs));
+ String8 s8 = String8(kvpairs);
+
+ if (parms.getInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val) == NO_ERROR) {
+ val = convert_audio_device(val, HAL_API_REV_2_0, HAL_API_REV_1_0);
+ parms.remove(String8(AUDIO_PARAMETER_STREAM_ROUTING));
+ parms.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val);
+ s8 = parms.toString();
+ }
+
+ return in->legacy_in->setParameters(s8);
+}
+
+static char * in_get_parameters(const struct audio_stream *stream,
+ const char *keys)
+{
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ String8 s8;
+ int val;
+
+ s8 = in->legacy_in->getParameters(String8(keys));
+
+ AudioParameter parms = AudioParameter(s8);
+ if (parms.getInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val) == NO_ERROR) {
+ val = convert_audio_device(val, HAL_API_REV_1_0, HAL_API_REV_2_0);
+ parms.remove(String8(AUDIO_PARAMETER_STREAM_ROUTING));
+ parms.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val);
+ s8 = parms.toString();
+ }
+
+ return strdup(s8.string());
+}
+
+static int in_set_gain(struct audio_stream_in *stream, float gain)
+{
+ struct legacy_stream_in *in =
+ reinterpret_cast<struct legacy_stream_in *>(stream);
+ return in->legacy_in->setGain(gain);
+}
+
+static ssize_t in_read(struct audio_stream_in *stream, void* buffer,
+ size_t bytes)
+{
+ struct legacy_stream_in *in =
+ reinterpret_cast<struct legacy_stream_in *>(stream);
+ return in->legacy_in->read(buffer, bytes);
+}
+
+static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
+{
+ struct legacy_stream_in *in =
+ reinterpret_cast<struct legacy_stream_in *>(stream);
+ return in->legacy_in->getInputFramesLost();
+}
+
+static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return in->legacy_in->addAudioEffect(effect);
+}
+
+static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return in->legacy_in->removeAudioEffect(effect);
+}
+
+/** audio_hw_device implementation **/
+static inline struct legacy_audio_device * to_ladev(struct audio_hw_device *dev)
+{
+ return reinterpret_cast<struct legacy_audio_device *>(dev);
+}
+
+static inline const struct legacy_audio_device * to_cladev(const struct audio_hw_device *dev)
+{
+ return reinterpret_cast<const struct legacy_audio_device *>(dev);
+}
+
+static int adev_init_check(const struct audio_hw_device *dev)
+{
+ const struct legacy_audio_device *ladev = to_cladev(dev);
+
+ return ladev->hwif->initCheck();
+}
+
+static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
+{
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->setVoiceVolume(volume);
+}
+
+static int adev_set_master_volume(struct audio_hw_device *dev, float volume)
+{
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->setMasterVolume(volume);
+}
+
+static int adev_get_master_volume(struct audio_hw_device *dev, float* volume)
+{
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->getMasterVolume(volume);
+}
+
+static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
+{
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ // as this is the legacy API, don't change it to use audio_mode_t instead of int
+ return ladev->hwif->setMode((int) mode);
+}
+
+static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
+{
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->setMicMute(state);
+}
+
+static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
+{
+ const struct legacy_audio_device *ladev = to_cladev(dev);
+ return ladev->hwif->getMicMute(state);
+}
+
+static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
+{
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->setParameters(String8(kvpairs));
+}
+
+static char * adev_get_parameters(const struct audio_hw_device *dev,
+ const char *keys)
+{
+ const struct legacy_audio_device *ladev = to_cladev(dev);
+ String8 s8;
+
+ s8 = ladev->hwif->getParameters(String8(keys));
+ return strdup(s8.string());
+}
+
+static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
+ const struct audio_config *config)
+{
+ const struct legacy_audio_device *ladev = to_cladev(dev);
+ return ladev->hwif->getInputBufferSize(config->sample_rate, (int) config->format,
+ audio_channel_count_from_in_mask(config->channel_mask));
+}
+
+static int adev_open_output_stream(struct audio_hw_device *dev,
+ audio_io_handle_t handle,
+ audio_devices_t devices,
+ audio_output_flags_t flags,
+ struct audio_config *config,
+ struct audio_stream_out **stream_out,
+ const char *address __unused)
+{
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ status_t status;
+ struct legacy_stream_out *out;
+ int ret;
+
+ out = (struct legacy_stream_out *)calloc(1, sizeof(*out));
+ if (!out)
+ return -ENOMEM;
+
+ devices = convert_audio_device(devices, HAL_API_REV_2_0, HAL_API_REV_1_0);
+
+ out->legacy_out = ladev->hwif->openOutputStreamWithFlags(devices, flags,
+ (int *) &config->format,
+ &config->channel_mask,
+ &config->sample_rate, &status);
+ if (!out->legacy_out) {
+ ret = status;
+ goto err_open;
+ }
+
+ out->stream.common.get_sample_rate = out_get_sample_rate;
+ out->stream.common.set_sample_rate = out_set_sample_rate;
+ out->stream.common.get_buffer_size = out_get_buffer_size;
+ out->stream.common.get_channels = out_get_channels;
+ out->stream.common.get_format = out_get_format;
+ out->stream.common.set_format = out_set_format;
+ out->stream.common.standby = out_standby;
+ out->stream.common.dump = out_dump;
+ out->stream.common.set_parameters = out_set_parameters;
+ out->stream.common.get_parameters = out_get_parameters;
+ out->stream.common.add_audio_effect = out_add_audio_effect;
+ out->stream.common.remove_audio_effect = out_remove_audio_effect;
+ out->stream.get_latency = out_get_latency;
+ out->stream.set_volume = out_set_volume;
+ out->stream.write = out_write;
+ out->stream.get_render_position = out_get_render_position;
+ out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
+
+ *stream_out = &out->stream;
+ return 0;
+
+err_open:
+ free(out);
+ *stream_out = NULL;
+ return ret;
+}
+
+static void adev_close_output_stream(struct audio_hw_device *dev,
+ struct audio_stream_out* stream)
+{
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ struct legacy_stream_out *out = reinterpret_cast<struct legacy_stream_out *>(stream);
+
+ ladev->hwif->closeOutputStream(out->legacy_out);
+ free(out);
+}
+
+/** This method creates and opens the audio hardware input stream */
+static int adev_open_input_stream(struct audio_hw_device *dev,
+ audio_io_handle_t handle,
+ audio_devices_t devices,
+ struct audio_config *config,
+ struct audio_stream_in **stream_in,
+ audio_input_flags_t flags __unused,
+ const char *address __unused,
+ audio_source_t source __unused)
+{
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ status_t status;
+ struct legacy_stream_in *in;
+ int ret;
+
+ in = (struct legacy_stream_in *)calloc(1, sizeof(*in));
+ if (!in)
+ return -ENOMEM;
+
+ devices = convert_audio_device(devices, HAL_API_REV_2_0, HAL_API_REV_1_0);
+
+ in->legacy_in = ladev->hwif->openInputStream(devices, (int *) &config->format,
+ &config->channel_mask, &config->sample_rate,
+ &status, (AudioSystem::audio_in_acoustics)0);
+ if (!in->legacy_in) {
+ ret = status;
+ goto err_open;
+ }
+
+ in->stream.common.get_sample_rate = in_get_sample_rate;
+ in->stream.common.set_sample_rate = in_set_sample_rate;
+ in->stream.common.get_buffer_size = in_get_buffer_size;
+ in->stream.common.get_channels = in_get_channels;
+ in->stream.common.get_format = in_get_format;
+ in->stream.common.set_format = in_set_format;
+ in->stream.common.standby = in_standby;
+ in->stream.common.dump = in_dump;
+ in->stream.common.set_parameters = in_set_parameters;
+ in->stream.common.get_parameters = in_get_parameters;
+ in->stream.common.add_audio_effect = in_add_audio_effect;
+ in->stream.common.remove_audio_effect = in_remove_audio_effect;
+ in->stream.set_gain = in_set_gain;
+ in->stream.read = in_read;
+ in->stream.get_input_frames_lost = in_get_input_frames_lost;
+
+ *stream_in = &in->stream;
+ return 0;
+
+err_open:
+ free(in);
+ *stream_in = NULL;
+ return ret;
+}
+
+static void adev_close_input_stream(struct audio_hw_device *dev,
+ struct audio_stream_in *stream)
+{
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ struct legacy_stream_in *in =
+ reinterpret_cast<struct legacy_stream_in *>(stream);
+
+ ladev->hwif->closeInputStream(in->legacy_in);
+ free(in);
+}
+
+static int adev_dump(const struct audio_hw_device *dev, int fd)
+{
+ const struct legacy_audio_device *ladev = to_cladev(dev);
+ Vector<String16> args;
+
+ return ladev->hwif->dumpState(fd, args);
+}
+
+static int legacy_adev_close(hw_device_t* device)
+{
+ struct audio_hw_device *hwdev =
+ reinterpret_cast<struct audio_hw_device *>(device);
+ struct legacy_audio_device *ladev = to_ladev(hwdev);
+
+ if (!ladev)
+ return 0;
+
+ if (ladev->hwif)
+ delete ladev->hwif;
+
+ free(ladev);
+ return 0;
+}
+
+static int legacy_adev_open(const hw_module_t* module, const char* name,
+ hw_device_t** device)
+{
+ struct legacy_audio_device *ladev;
+ int ret;
+
+ if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
+ return -EINVAL;
+
+ ladev = (struct legacy_audio_device *)calloc(1, sizeof(*ladev));
+ if (!ladev)
+ return -ENOMEM;
+
+ ladev->device.common.tag = HARDWARE_DEVICE_TAG;
+ ladev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
+ ladev->device.common.module = const_cast<hw_module_t*>(module);
+ ladev->device.common.close = legacy_adev_close;
+
+ ladev->device.init_check = adev_init_check;
+ ladev->device.set_voice_volume = adev_set_voice_volume;
+ ladev->device.set_master_volume = adev_set_master_volume;
+ ladev->device.get_master_volume = adev_get_master_volume;
+ ladev->device.set_mode = adev_set_mode;
+ ladev->device.set_mic_mute = adev_set_mic_mute;
+ ladev->device.get_mic_mute = adev_get_mic_mute;
+ ladev->device.set_parameters = adev_set_parameters;
+ ladev->device.get_parameters = adev_get_parameters;
+ ladev->device.get_input_buffer_size = adev_get_input_buffer_size;
+ ladev->device.open_output_stream = adev_open_output_stream;
+ ladev->device.close_output_stream = adev_close_output_stream;
+ ladev->device.open_input_stream = adev_open_input_stream;
+ ladev->device.close_input_stream = adev_close_input_stream;
+ ladev->device.dump = adev_dump;
+
+ ladev->hwif = createAudioHardware();
+ if (!ladev->hwif) {
+ ret = -EIO;
+ goto err_create_audio_hw;
+ }
+
+ *device = &ladev->device.common;
+
+ return 0;
+
+err_create_audio_hw:
+ free(ladev);
+ return ret;
+}
+
+static struct hw_module_methods_t legacy_audio_module_methods = {
+ open: legacy_adev_open
+};
+
+struct legacy_audio_module HAL_MODULE_INFO_SYM = {
+ module: {
+ common: {
+ tag: HARDWARE_MODULE_TAG,
+ module_api_version: AUDIO_MODULE_API_VERSION_0_1,
+ hal_api_version: HARDWARE_HAL_API_VERSION,
+ id: AUDIO_HARDWARE_MODULE_ID,
+ name: "LEGACY Audio HW HAL",
+ author: "The Android Open Source Project",
+ methods: &legacy_audio_module_methods,
+ dso : NULL,
+ reserved : {0},
+ },
+ },
+};
+
+}; // extern "C"
+
+}; // namespace android_audio_legacy
diff --git a/legacy_hal/audio_policy_hal.cpp b/legacy_hal/audio_policy_hal.cpp
new file mode 100755
index 0000000..87c4131
--- /dev/null
+++ b/legacy_hal/audio_policy_hal.cpp
@@ -0,0 +1,477 @@
+/*
+ * Copyright (C) 2011 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 "legacy_audio_policy_hal"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <system/audio_policy.h>
+#include <hardware/audio_policy.h>
+
+#include <hardware_legacy/AudioPolicyInterface.h>
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+#include "AudioPolicyCompatClient.h"
+
+namespace android_audio_legacy {
+
+extern "C" {
+
+struct legacy_ap_module {
+ struct audio_policy_module module;
+};
+
+struct legacy_ap_device {
+ struct audio_policy_device device;
+};
+
+struct legacy_audio_policy {
+ struct audio_policy policy;
+
+ void *service;
+ struct audio_policy_service_ops *aps_ops;
+ AudioPolicyCompatClient *service_client;
+ AudioPolicyInterface *apm;
+};
+
+static inline struct legacy_audio_policy * to_lap(struct audio_policy *pol)
+{
+ return reinterpret_cast<struct legacy_audio_policy *>(pol);
+}
+
+static inline const struct legacy_audio_policy * to_clap(const struct audio_policy *pol)
+{
+ return reinterpret_cast<const struct legacy_audio_policy *>(pol);
+}
+
+
+static int ap_set_device_connection_state(struct audio_policy *pol,
+ audio_devices_t device,
+ audio_policy_dev_state_t state,
+ const char *device_address)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->setDeviceConnectionState(
+ (AudioSystem::audio_devices)device,
+ (AudioSystem::device_connection_state)state,
+ device_address);
+}
+
+static audio_policy_dev_state_t ap_get_device_connection_state(
+ const struct audio_policy *pol,
+ audio_devices_t device,
+ const char *device_address)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ return (audio_policy_dev_state_t)lap->apm->getDeviceConnectionState(
+ (AudioSystem::audio_devices)device,
+ device_address);
+}
+
+static void ap_set_phone_state(struct audio_policy *pol, audio_mode_t state)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ // as this is the legacy API, don't change it to use audio_mode_t instead of int
+ lap->apm->setPhoneState((int) state);
+}
+
+ /* indicate a change in ringer mode */
+static void ap_set_ringer_mode(struct audio_policy *pol, uint32_t mode,
+ uint32_t mask)
+{
+ // deprecated, never called
+}
+
+ /* force using a specific device category for the specified usage */
+static void ap_set_force_use(struct audio_policy *pol,
+ audio_policy_force_use_t usage,
+ audio_policy_forced_cfg_t config)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ lap->apm->setForceUse((AudioSystem::force_use)usage,
+ (AudioSystem::forced_config)config);
+}
+
+ /* retreive current device category forced for a given usage */
+static audio_policy_forced_cfg_t ap_get_force_use(
+ const struct audio_policy *pol,
+ audio_policy_force_use_t usage)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ return (audio_policy_forced_cfg_t)lap->apm->getForceUse(
+ (AudioSystem::force_use)usage);
+}
+
+/* if can_mute is true, then audio streams that are marked ENFORCED_AUDIBLE
+ * can still be muted. */
+static void ap_set_can_mute_enforced_audible(struct audio_policy *pol,
+ bool can_mute)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ lap->apm->setSystemProperty("ro.camera.sound.forced", can_mute ? "0" : "1");
+}
+
+static int ap_init_check(const struct audio_policy *pol)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ return lap->apm->initCheck();
+}
+
+static audio_io_handle_t ap_get_output(struct audio_policy *pol,
+ audio_stream_type_t stream,
+ uint32_t sampling_rate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_output_flags_t flags,
+ const audio_offload_info_t *offloadInfo)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+
+ ALOGV("%s: tid %d", __func__, gettid());
+ return lap->apm->getOutput((AudioSystem::stream_type)stream,
+ sampling_rate, format, channelMask,
+ (AudioSystem::output_flags)flags,
+ offloadInfo);
+}
+
+static int ap_start_output(struct audio_policy *pol, audio_io_handle_t output,
+ audio_stream_type_t stream, int session)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->startOutput(output, (AudioSystem::stream_type)stream,
+ session);
+}
+
+static int ap_stop_output(struct audio_policy *pol, audio_io_handle_t output,
+ audio_stream_type_t stream, int session)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->stopOutput(output, (AudioSystem::stream_type)stream,
+ session);
+}
+
+static void ap_release_output(struct audio_policy *pol,
+ audio_io_handle_t output)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ lap->apm->releaseOutput(output);
+}
+
+static audio_io_handle_t ap_get_input(struct audio_policy *pol, audio_source_t inputSource,
+ uint32_t sampling_rate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_in_acoustics_t acoustics)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->getInput((int) inputSource, sampling_rate, format, channelMask,
+ (AudioSystem::audio_in_acoustics)acoustics);
+}
+
+static int ap_start_input(struct audio_policy *pol, audio_io_handle_t input)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->startInput(input);
+}
+
+static int ap_stop_input(struct audio_policy *pol, audio_io_handle_t input)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->stopInput(input);
+}
+
+static void ap_release_input(struct audio_policy *pol, audio_io_handle_t input)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ lap->apm->releaseInput(input);
+}
+
+static void ap_init_stream_volume(struct audio_policy *pol,
+ audio_stream_type_t stream, int index_min,
+ int index_max)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ lap->apm->initStreamVolume((AudioSystem::stream_type)stream, index_min,
+ index_max);
+}
+
+static int ap_set_stream_volume_index(struct audio_policy *pol,
+ audio_stream_type_t stream,
+ int index)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->setStreamVolumeIndex((AudioSystem::stream_type)stream,
+ index,
+ AUDIO_DEVICE_OUT_DEFAULT);
+}
+
+static int ap_get_stream_volume_index(const struct audio_policy *pol,
+ audio_stream_type_t stream,
+ int *index)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ return lap->apm->getStreamVolumeIndex((AudioSystem::stream_type)stream,
+ index,
+ AUDIO_DEVICE_OUT_DEFAULT);
+}
+
+static int ap_set_stream_volume_index_for_device(struct audio_policy *pol,
+ audio_stream_type_t stream,
+ int index,
+ audio_devices_t device)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->setStreamVolumeIndex((AudioSystem::stream_type)stream,
+ index,
+ device);
+}
+
+static int ap_get_stream_volume_index_for_device(const struct audio_policy *pol,
+ audio_stream_type_t stream,
+ int *index,
+ audio_devices_t device)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ return lap->apm->getStreamVolumeIndex((AudioSystem::stream_type)stream,
+ index,
+ device);
+}
+
+static uint32_t ap_get_strategy_for_stream(const struct audio_policy *pol,
+ audio_stream_type_t stream)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ return lap->apm->getStrategyForStream((AudioSystem::stream_type)stream);
+}
+
+static audio_devices_t ap_get_devices_for_stream(const struct audio_policy *pol,
+ audio_stream_type_t stream)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ return lap->apm->getDevicesForStream((AudioSystem::stream_type)stream);
+}
+
+static audio_io_handle_t ap_get_output_for_effect(struct audio_policy *pol,
+ const struct effect_descriptor_s *desc)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->getOutputForEffect(desc);
+}
+
+static int ap_register_effect(struct audio_policy *pol,
+ const struct effect_descriptor_s *desc,
+ audio_io_handle_t io,
+ uint32_t strategy,
+ int session,
+ int id)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->registerEffect(desc, io, strategy, session, id);
+}
+
+static int ap_unregister_effect(struct audio_policy *pol, int id)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->unregisterEffect(id);
+}
+
+static int ap_set_effect_enabled(struct audio_policy *pol, int id, bool enabled)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->setEffectEnabled(id, enabled);
+}
+
+static bool ap_is_stream_active(const struct audio_policy *pol, audio_stream_type_t stream,
+ uint32_t in_past_ms)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ return lap->apm->isStreamActive((int) stream, in_past_ms);
+}
+
+static bool ap_is_stream_active_remotely(const struct audio_policy *pol, audio_stream_type_t stream,
+ uint32_t in_past_ms)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ return lap->apm->isStreamActiveRemotely((int) stream, in_past_ms);
+}
+
+static bool ap_is_source_active(const struct audio_policy *pol, audio_source_t source)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ return lap->apm->isSourceActive(source);
+}
+
+static int ap_dump(const struct audio_policy *pol, int fd)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ return lap->apm->dump(fd);
+}
+
+static bool ap_is_offload_supported(const struct audio_policy *pol,
+ const audio_offload_info_t *info)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ return lap->apm->isOffloadSupported(*info);
+}
+
+static int create_legacy_ap(const struct audio_policy_device *device,
+ struct audio_policy_service_ops *aps_ops,
+ void *service,
+ struct audio_policy **ap)
+{
+ struct legacy_audio_policy *lap;
+ int ret;
+
+ if (!service || !aps_ops)
+ return -EINVAL;
+
+ lap = (struct legacy_audio_policy *)calloc(1, sizeof(*lap));
+ if (!lap)
+ return -ENOMEM;
+
+ lap->policy.set_device_connection_state = ap_set_device_connection_state;
+ lap->policy.get_device_connection_state = ap_get_device_connection_state;
+ lap->policy.set_phone_state = ap_set_phone_state;
+ lap->policy.set_ringer_mode = ap_set_ringer_mode;
+ lap->policy.set_force_use = ap_set_force_use;
+ lap->policy.get_force_use = ap_get_force_use;
+ lap->policy.set_can_mute_enforced_audible =
+ ap_set_can_mute_enforced_audible;
+ lap->policy.init_check = ap_init_check;
+ lap->policy.get_output = ap_get_output;
+ lap->policy.start_output = ap_start_output;
+ lap->policy.stop_output = ap_stop_output;
+ lap->policy.release_output = ap_release_output;
+ lap->policy.get_input = ap_get_input;
+ lap->policy.start_input = ap_start_input;
+ lap->policy.stop_input = ap_stop_input;
+ lap->policy.release_input = ap_release_input;
+ lap->policy.init_stream_volume = ap_init_stream_volume;
+ lap->policy.set_stream_volume_index = ap_set_stream_volume_index;
+ lap->policy.get_stream_volume_index = ap_get_stream_volume_index;
+ lap->policy.set_stream_volume_index_for_device = ap_set_stream_volume_index_for_device;
+ lap->policy.get_stream_volume_index_for_device = ap_get_stream_volume_index_for_device;
+ lap->policy.get_strategy_for_stream = ap_get_strategy_for_stream;
+ lap->policy.get_devices_for_stream = ap_get_devices_for_stream;
+ lap->policy.get_output_for_effect = ap_get_output_for_effect;
+ lap->policy.register_effect = ap_register_effect;
+ lap->policy.unregister_effect = ap_unregister_effect;
+ lap->policy.set_effect_enabled = ap_set_effect_enabled;
+ lap->policy.is_stream_active = ap_is_stream_active;
+ lap->policy.is_stream_active_remotely = ap_is_stream_active_remotely;
+ lap->policy.is_source_active = ap_is_source_active;
+ lap->policy.dump = ap_dump;
+ lap->policy.is_offload_supported = ap_is_offload_supported;
+
+ lap->service = service;
+ lap->aps_ops = aps_ops;
+ lap->service_client =
+ new AudioPolicyCompatClient(aps_ops, service);
+ if (!lap->service_client) {
+ ret = -ENOMEM;
+ goto err_new_compat_client;
+ }
+
+ lap->apm = createAudioPolicyManager(lap->service_client);
+ if (!lap->apm) {
+ ret = -ENOMEM;
+ goto err_create_apm;
+ }
+
+ *ap = &lap->policy;
+ return 0;
+
+err_create_apm:
+ delete lap->service_client;
+err_new_compat_client:
+ free(lap);
+ *ap = NULL;
+ return ret;
+}
+
+static int destroy_legacy_ap(const struct audio_policy_device *ap_dev,
+ struct audio_policy *ap)
+{
+ struct legacy_audio_policy *lap = to_lap(ap);
+
+ if (!lap)
+ return 0;
+
+ if (lap->apm)
+ destroyAudioPolicyManager(lap->apm);
+ if (lap->service_client)
+ delete lap->service_client;
+ free(lap);
+ return 0;
+}
+
+static int legacy_ap_dev_close(hw_device_t* device)
+{
+ if (device)
+ free(device);
+ return 0;
+}
+
+static int legacy_ap_dev_open(const hw_module_t* module, const char* name,
+ hw_device_t** device)
+{
+ struct legacy_ap_device *dev;
+
+ if (strcmp(name, AUDIO_POLICY_INTERFACE) != 0)
+ return -EINVAL;
+
+ dev = (struct legacy_ap_device *)calloc(1, sizeof(*dev));
+ if (!dev)
+ return -ENOMEM;
+
+ dev->device.common.tag = HARDWARE_DEVICE_TAG;
+ dev->device.common.version = 0;
+ dev->device.common.module = const_cast<hw_module_t*>(module);
+ dev->device.common.close = legacy_ap_dev_close;
+ dev->device.create_audio_policy = create_legacy_ap;
+ dev->device.destroy_audio_policy = destroy_legacy_ap;
+
+ *device = &dev->device.common;
+
+ return 0;
+}
+
+static struct hw_module_methods_t legacy_ap_module_methods = {
+ .open = legacy_ap_dev_open
+};
+
+struct legacy_ap_module HAL_MODULE_INFO_SYM = {
+ .module = {
+ .common = {
+ .tag = HARDWARE_MODULE_TAG,
+ .version_major = 1,
+ .version_minor = 0,
+ .id = AUDIO_POLICY_HARDWARE_MODULE_ID,
+ .name = "LEGACY Audio Policy HAL",
+ .author = "The Android Open Source Project",
+ .methods = &legacy_ap_module_methods,
+ .dso = NULL,
+ .reserved = {0},
+ },
+ },
+};
+
+}; // extern "C"
+
+}; // namespace android_audio_legacy
diff --git a/legacy_hal/codec_config/config.h b/legacy_hal/codec_config/config.h
new file mode 100755
index 0000000..84c3707
--- /dev/null
+++ b/legacy_hal/codec_config/config.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2015 Rockchip Electronics Co., Ltd.
+*/
+
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+struct config_control
+{
+ const char *ctl_name; //name of control.
+ const char *str_val; //value of control, which type is stream.
+ const int int_val[2]; //left and right value of control, which type are int.
+};
+
+struct config_route
+{
+ const int sound_card;
+ const int devices;
+ const struct config_control *controls;
+ const unsigned controls_count;
+};
+
+struct config_route_table
+{
+ const struct config_route speaker_normal;
+ const struct config_route speaker_incall;
+ const struct config_route speaker_ringtone;
+ const struct config_route speaker_voip;
+
+ const struct config_route earpiece_normal;
+ const struct config_route earpiece_incall;
+ const struct config_route earpiece_ringtone;
+ const struct config_route earpiece_voip;
+
+ const struct config_route headphone_normal;
+ const struct config_route headphone_incall;
+ const struct config_route headphone_ringtone;
+ const struct config_route speaker_headphone_normal;
+ const struct config_route speaker_headphone_ringtone;
+ const struct config_route headphone_voip;
+
+ const struct config_route headset_normal;
+ const struct config_route headset_incall;
+ const struct config_route headset_ringtone;
+ const struct config_route headset_voip;
+
+ const struct config_route bluetooth_normal;
+ const struct config_route bluetooth_incall;
+ const struct config_route bluetooth_voip;
+
+ const struct config_route main_mic_capture;
+ const struct config_route hands_free_mic_capture;
+ const struct config_route bluetooth_sco_mic_capture;
+
+ const struct config_route playback_off;
+ const struct config_route capture_off;
+ const struct config_route incall_off;
+ const struct config_route voip_off;
+
+ const struct config_route hdmi_normal;
+
+ const struct config_route usb_normal;
+ const struct config_route usb_capture;
+};
+
+#define on 1
+#define off 0
+
+#define DEVICES_0 0
+#define DEVICES_0_1 1
+#define DEVICES_0_2 2
+#define DEVICES_0_1_2 3
+
+#endif //_CONFIG_H_
diff --git a/legacy_hal/codec_config/config_list.h b/legacy_hal/codec_config/config_list.h
new file mode 100755
index 0000000..98381fe
--- /dev/null
+++ b/legacy_hal/codec_config/config_list.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 Rockchip Electronics Co., Ltd.
+*/
+
+#ifndef _CONFIG_LIST_H_
+#define _CONFIG_LIST_H_
+
+#include "config.h"
+#include "default_config.h"
+#include "rk616_config.h"
+#include "rt3261_config.h"
+#include "rt5616_config.h"
+#include "rt3224_config.h"
+#include "wm8960_config.h"
+
+struct alsa_sound_card_config
+{
+ const char *sound_card_name;
+ const struct config_route_table *route_table;
+};
+
+/*
+* List of sound card name and config table.
+* Audio will get config_route_table and set route
+* according to the name of sound card 0 and sound_card_name.
+*/
+struct alsa_sound_card_config sound_card_config_list[] = {
+ {
+ .sound_card_name = "RKRK616",
+ .route_table = &rk616_config_table,
+ },
+ {
+ .sound_card_name = "RK29RT3224",
+ .route_table = &rt3224_config_table,
+ },
+ {
+ .sound_card_name = "RK29RT3261",
+ .route_table = &rt3261_config_table,
+ },
+ {
+ .sound_card_name = "RK29WM8960",
+ .route_table = &wm8960_config_table,
+ },
+ {
+ .sound_card_name = "RKRT3224",
+ .route_table = &rt3224_config_table,
+ },
+ {
+ .sound_card_name = "RKRT3261",
+ .route_table = &rt3261_config_table,
+ },
+ {
+ .sound_card_name = "RKWM8960",
+ .route_table = &wm8960_config_table,
+ },
+ {
+ .sound_card_name = "RKRT5616",
+ .route_table = &rt5616_config_table,
+ },
+};
+
+#endif //_CONFIG_LIST_H_
diff --git a/legacy_hal/codec_config/default_config.h b/legacy_hal/codec_config/default_config.h
new file mode 100755
index 0000000..dd15990
--- /dev/null
+++ b/legacy_hal/codec_config/default_config.h
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2015 Rockchip Electronics Co., Ltd.
+*/
+
+#ifndef _DEFAULT_CONFIG_H_
+#define _DEFAULT_CONFIG_H_
+
+#include "config.h"
+
+const struct config_control default_speaker_normal_controls[] = {
+ {
+ .ctl_name = "Playback Path",
+ .str_val = "SPK",
+ },
+};
+
+const struct config_control default_speaker_incall_controls[] = {
+ {
+ .ctl_name = "Playback Path",
+ .str_val = "SPK",
+ },
+ {
+ .ctl_name = "Voice Call Path",
+ .str_val = "SPK",
+ },
+};
+
+const struct config_control default_speaker_ringtone_controls[] = {
+ {
+ .ctl_name = "Playback Path",
+ .str_val = "RING_SPK",
+ },
+};
+
+const struct config_control default_speaker_voip_controls[] = {
+ {
+ .ctl_name = "Playback Path",
+ .str_val = "SPK",
+ },
+ {
+ .ctl_name = "Voip Path",
+ .str_val = "SPK",
+ },
+};
+
+const struct config_control default_earpiece_normal_controls[] = {
+ {
+ .ctl_name = "Playback Path",
+ .str_val = "RCV",
+ },
+};
+
+const struct config_control default_earpiece_incall_controls[] = {
+ {
+ .ctl_name = "Playback Path",
+ .str_val = "SPK",
+ },
+ {
+ .ctl_name = "Voice Call Path",
+ .str_val = "RCV",
+ },
+};
+
+const struct config_control default_earpiece_ringtone_controls[] = {
+ {
+ .ctl_name = "Playback Path",
+ .str_val = "RCV",
+ },
+};
+
+const struct config_control default_earpiece_voip_controls[] = {
+ {
+ .ctl_name = "Playback Path",
+ .str_val = "RCV",
+ },
+ {
+ .ctl_name = "Voip Path",
+ .str_val = "RCV",
+ },
+};
+
+const struct config_control default_headphone_normal_controls[] = {
+ {
+ .ctl_name = "Playback Path",
+ .str_val = "HP_NO_MIC",
+ },
+};
+
+const struct config_control default_headphone_incall_controls[] = {
+ {
+ .ctl_name = "Playback Path",
+ .str_val = "HP_NO_MIC",
+ },
+ {
+ .ctl_name = "Voice Call Path",
+ .str_val = "HP_NO_MIC",
+ },
+};
+
+const struct config_control default_headphone_ringtone_controls[] = {
+ {
+ .ctl_name = "Playback Path",
+ .str_val = "RING_HP_NO_MIC",
+ },
+};
+
+const struct config_control default_speaker_headphone_normal_controls[] = {
+ {
+ .ctl_name = "Playback Path",
+ .str_val = "SPK_HP",
+ },
+};
+
+const struct config_control default_speaker_headphone_ringtone_controls[] = {
+ {
+ .ctl_name = "Playback Path",
+ .str_val = "RING_SPK_HP",
+ },
+};
+
+const struct config_control default_headphone_voip_controls[] = {
+ {
+ .ctl_name = "Playback Path",
+ .str_val = "HP_NO_MIC",
+ },
+ {
+ .ctl_name = "Voip Path",
+ .str_val = "HP_NO_MIC",
+ },
+};
+
+const struct config_control default_headset_normal_controls[] = {
+ {
+ .ctl_name = "Playback Path",
+ .str_val = "HP",
+ },
+};
+
+const struct config_control default_headset_incall_controls[] = {
+ {
+ .ctl_name = "Playback Path",
+ .str_val = "HP",
+ },
+ {
+ .ctl_name = "Voice Call Path",
+ .str_val = "HP",
+ },
+};
+
+const struct config_control default_headset_ringtone_controls[] = {
+ {
+ .ctl_name = "Playback Path",
+ .str_val = "RING_HP",
+ },
+};
+
+const struct config_control default_headset_voip_controls[] = {
+ {
+ .ctl_name = "Playback Path",
+ .str_val = "HP",
+ },
+ {
+ .ctl_name = "Voip Path",
+ .str_val = "HP",
+ },
+};
+
+const struct config_control default_bluetooth_normal_controls[] = {
+ {
+ .ctl_name = "Playback Path",
+ .str_val = "BT",
+ },
+};
+
+const struct config_control default_bluetooth_incall_controls[] = {
+ {
+ .ctl_name = "Voice Call Path",
+ .str_val = "BT",
+ },
+};
+
+const struct config_control default_bluetooth_voip_controls[] = {
+ {
+ .ctl_name = "Voip Path",
+ .str_val = "BT",
+ },
+};
+
+const struct config_control default_main_mic_capture_controls[] = {
+ {
+ .ctl_name = "Capture MIC Path",
+ .str_val = "Main Mic",
+ },
+};
+
+const struct config_control default_hands_free_mic_capture_controls[] = {
+ {
+ .ctl_name = "Capture MIC Path",
+ .str_val = "Hands Free Mic",
+ },
+};
+
+const struct config_control default_bluetooth_sco_mic_capture_controls[] = {
+ {
+ .ctl_name = "Capture MIC Path",
+ .str_val = "BT Sco Mic",
+ },
+};
+
+const struct config_control default_playback_off_controls[] = {
+ {
+ .ctl_name = "Playback Path",
+ .str_val = "OFF",
+ },
+};
+
+const struct config_control default_capture_off_controls[] = {
+ {
+ .ctl_name = "Capture MIC Path",
+ .str_val = "MIC OFF",
+ },
+};
+
+const struct config_control default_incall_off_controls[] = {
+ {
+ .ctl_name = "Voice Call Path",
+ .str_val = "OFF",
+ },
+};
+
+const struct config_control default_voip_off_controls[] = {
+ {
+ .ctl_name = "Voip Path",
+ .str_val = "OFF",
+ },
+};
+
+const struct config_route_table default_config_table = {
+ //speaker
+ .speaker_normal = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = default_speaker_normal_controls,
+ .controls_count = sizeof(default_speaker_normal_controls) / sizeof(struct config_control),
+ },
+ .speaker_incall = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = default_speaker_incall_controls,
+ .controls_count = sizeof(default_speaker_incall_controls) / sizeof(struct config_control),
+ },
+ .speaker_ringtone = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = default_speaker_ringtone_controls,
+ .controls_count = sizeof(default_speaker_ringtone_controls) / sizeof(struct config_control),
+ },
+ .speaker_voip = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = default_speaker_voip_controls,
+ .controls_count = sizeof(default_speaker_voip_controls) / sizeof(struct config_control),
+ },
+
+ //earpiece
+ .earpiece_normal = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = default_earpiece_normal_controls,
+ .controls_count = sizeof(default_earpiece_normal_controls) / sizeof(struct config_control),
+ },
+ .earpiece_incall = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = default_earpiece_incall_controls,
+ .controls_count = sizeof(default_earpiece_incall_controls) / sizeof(struct config_control),
+ },
+ .earpiece_ringtone = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = default_earpiece_ringtone_controls,
+ .controls_count = sizeof(default_earpiece_ringtone_controls) / sizeof(struct config_control),
+ },
+ .earpiece_voip = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = default_earpiece_voip_controls,
+ .controls_count = sizeof(default_earpiece_voip_controls) / sizeof(struct config_control),
+ },
+
+ //headphone
+ .headphone_normal = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = default_headphone_normal_controls,
+ .controls_count = sizeof(default_headphone_normal_controls) / sizeof(struct config_control),
+ },
+ .headphone_incall = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = default_headphone_incall_controls,
+ .controls_count = sizeof(default_headphone_incall_controls) / sizeof(struct config_control),
+ },
+ .headphone_ringtone = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = default_headphone_ringtone_controls,
+ .controls_count = sizeof(default_headphone_ringtone_controls) / sizeof(struct config_control),
+ },
+ .speaker_headphone_normal = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = default_speaker_headphone_normal_controls,
+ .controls_count = sizeof(default_speaker_headphone_normal_controls) / sizeof(struct config_control),
+ },
+ .speaker_headphone_ringtone = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = default_speaker_headphone_ringtone_controls,
+ .controls_count = sizeof(default_speaker_headphone_ringtone_controls) / sizeof(struct config_control),
+ },
+ .headphone_voip = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = default_headphone_voip_controls,
+ .controls_count = sizeof(default_headphone_voip_controls) / sizeof(struct config_control),
+ },
+
+ //headset
+ .headset_normal = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = default_headset_normal_controls,
+ .controls_count = sizeof(default_headset_normal_controls) / sizeof(struct config_control),
+ },
+ .headset_incall = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = default_headset_incall_controls,
+ .controls_count = sizeof(default_headset_incall_controls) / sizeof(struct config_control),
+ },
+ .headset_ringtone = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = default_headset_ringtone_controls,
+ .controls_count = sizeof(default_headset_ringtone_controls) / sizeof(struct config_control),
+ },
+ .headset_voip = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = default_headset_voip_controls,
+ .controls_count = sizeof(default_headset_voip_controls) / sizeof(struct config_control),
+ },
+
+ //bluetooth
+ .bluetooth_normal = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = default_bluetooth_normal_controls,
+ .controls_count = sizeof(default_bluetooth_normal_controls) / sizeof(struct config_control),
+ },
+ .bluetooth_incall = {
+ .sound_card = 0,
+ .devices = DEVICES_0_1,
+ .controls = default_bluetooth_incall_controls,
+ .controls_count = sizeof(default_bluetooth_incall_controls) / sizeof(struct config_control),
+ },
+ .bluetooth_voip = {
+ .sound_card = 0,
+ .devices = DEVICES_0_1,
+ .controls = default_bluetooth_voip_controls,
+ .controls_count = sizeof(default_bluetooth_voip_controls) / sizeof(struct config_control),
+ },
+
+ //capture
+ .main_mic_capture = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = default_main_mic_capture_controls,
+ .controls_count = sizeof(default_main_mic_capture_controls) / sizeof(struct config_control),
+ },
+ .hands_free_mic_capture = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = default_hands_free_mic_capture_controls,
+ .controls_count = sizeof(default_hands_free_mic_capture_controls) / sizeof(struct config_control),
+ },
+ .bluetooth_sco_mic_capture = {
+ .sound_card = 0,
+ .devices = DEVICES_0_1,
+ .controls = default_bluetooth_sco_mic_capture_controls,
+ .controls_count = sizeof(default_bluetooth_sco_mic_capture_controls) / sizeof(struct config_control),
+ },
+
+ //off
+ .playback_off = {
+ .controls = default_playback_off_controls,
+ .controls_count = sizeof(default_playback_off_controls) / sizeof(struct config_control),
+ },
+ .capture_off = {
+ .controls = default_capture_off_controls,
+ .controls_count = sizeof(default_capture_off_controls) / sizeof(struct config_control),
+ },
+ .incall_off = {
+ .controls = default_incall_off_controls,
+ .controls_count = sizeof(default_incall_off_controls) / sizeof(struct config_control),
+ },
+ .voip_off = {
+ .controls = default_voip_off_controls,
+ .controls_count = sizeof(default_voip_off_controls) / sizeof(struct config_control),
+ },
+
+ //hdmi
+ .hdmi_normal = {
+ .sound_card = 1,
+ .devices = DEVICES_0,
+ .controls_count = 0,
+ },
+
+ //usb audio
+ .usb_normal = {
+ .sound_card = 2,
+ .devices = DEVICES_0,
+ .controls_count = 0,
+ },
+ .usb_capture = {
+ .sound_card = 2,
+ .devices = DEVICES_0,
+ .controls_count = 0,
+ },
+};
+
+
+#endif //_DEFAULT_CONFIG_H_
diff --git a/legacy_hal/codec_config/rk616_config.h b/legacy_hal/codec_config/rk616_config.h
new file mode 100755
index 0000000..b377d41
--- /dev/null
+++ b/legacy_hal/codec_config/rk616_config.h
@@ -0,0 +1,1600 @@
+/*
+ * Copyright (C) 2015 Rockchip Electronics Co., Ltd.
+*/
+
+#ifndef _RK616_CONFIG_H_
+#define _RK616_CONFIG_H_
+
+#include "config.h"
+
+const struct config_control rk616_speaker_normal_controls[] = {
+ {
+ .ctl_name = "SPK GPIO Control",
+ .str_val = "High",
+ },
+ {
+ .ctl_name = "HP GPIO Control",
+ .str_val = "Low",
+ },
+ {
+ .ctl_name = "RCV GPIO Control",
+ .str_val = "Low",
+ },
+
+ {
+ .ctl_name = "Headphone Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "Headphone Jack Switch",
+ .int_val = {off},
+ },
+
+ {
+ .ctl_name = "HPR Mux",
+ .str_val = "HPMIXR",
+ },
+ {
+ .ctl_name = "HPL Mux",
+ .str_val = "HPMIXL",
+ },
+ {
+ .ctl_name = "HPMIXL DACL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPMIXR DACR Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Speaker Playback Volume",
+ .int_val = {22, 22},
+ },
+ {
+ .ctl_name = "Ext Spk Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {on, on},
+ },
+};
+
+const struct config_control rk616_speaker_incall_controls[] = {
+ {
+ .ctl_name = "SPK GPIO Control",
+ .str_val = "High",
+ },
+ {
+ .ctl_name = "HP GPIO Control",
+ .str_val = "Low",
+ },
+ {
+ .ctl_name = "RCV GPIO Control",
+ .str_val = "Low",
+ },
+
+ //mic1-->line1/2
+ {
+ .ctl_name = "Mic Jack Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mic Mux",
+ .str_val = "BSTL",
+ },
+ {
+ .ctl_name = "MIXINL MUXMIC Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Micbias1 Voltage",
+ .int_val = {7},
+ },
+ {
+ .ctl_name = "BST_L Mode",
+ .int_val = {0},
+ },
+ {
+ .ctl_name = "Main Mic Capture Volume",
+ .int_val = {1},
+ },
+ {
+ .ctl_name = "Main Mic Capture Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "MUXMIC to MIXINL Volume",
+ .int_val = {7},
+ },
+ {
+ .ctl_name = "MIXINL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "PGAL Capture Volume",
+ .int_val = {29},
+ },
+ {
+ .ctl_name = "PGAL Capture Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "LINEMIX PGAL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "LINEOUT1 Playback Volume",
+ .int_val = {31},
+ },
+ {
+ .ctl_name = "LINEOUT2 Playback Volume",
+ .int_val = {31},
+ },
+ {
+ .ctl_name = "LINEOUT1 Playback Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "LINEOUT2 Playback Switch",
+ .int_val = {on},
+ },
+ //IN1N/P ---> SPK
+ {
+ .ctl_name = "HPMix Mux",
+ .str_val = "DIFFIN",
+ },
+ {
+ .ctl_name = "HPMIXR HPMix Mux Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPR Mux",
+ .str_val = "HPMIXR",
+ },
+ {
+ .ctl_name = "HPMIXL HPMix Mux Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPL Mux",
+ .str_val = "HPMIXL",
+ },
+ {
+ .ctl_name = "Ext Spk Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "DIFFIN Mode",
+ .int_val = {0},
+ },
+ {
+ .ctl_name = "DIFFIN Capture Volume",
+ .int_val = {1},
+ },
+ {
+ .ctl_name = "DIFFIN Capture Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPMIX MUX to HPMIXL Volume",
+ .int_val = {7},
+ },
+ {
+ .ctl_name = "HPMIX MUX to HPMIXR Volume",
+ .int_val = {7},
+ },
+ {
+ .ctl_name = "Speaker Playback Volume",
+ .int_val = {31, 31},
+ },
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {on, on},
+ },
+};
+
+const struct config_control rk616_speaker_ringtone_controls[] = {
+ {
+ .ctl_name = "SPK GPIO Control",
+ .str_val = "High",
+ },
+ {
+ .ctl_name = "HP GPIO Control",
+ .str_val = "Low",
+ },
+ {
+ .ctl_name = "RCV GPIO Control",
+ .str_val = "Low",
+ },
+
+ {
+ .ctl_name = "Headphone Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "Headphone Jack Switch",
+ .int_val = {off},
+ },
+
+ {
+ .ctl_name = "HPR Mux",
+ .str_val = "HPMIXR",
+ },
+ {
+ .ctl_name = "HPL Mux",
+ .str_val = "HPMIXL",
+ },
+ {
+ .ctl_name = "HPMIXL DACL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPMIXR DACR Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Speaker Playback Volume",
+ .int_val = {31, 31},
+ },
+ {
+ .ctl_name = "Ext Spk Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {on, on},
+ },
+};
+
+const struct config_control rk616_speaker_voip_controls[] = {
+
+};
+
+const struct config_control rk616_earpiece_normal_controls[] = {
+ {
+ .ctl_name = "SPK GPIO Control",
+ .str_val = "High",
+ },
+ {
+ .ctl_name = "HP GPIO Control",
+ .str_val = "Low",
+ },
+ {
+ .ctl_name = "RCV GPIO Control",
+ .str_val = "Low",
+ },
+
+ {
+ .ctl_name = "Headphone Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "Headphone Jack Switch",
+ .int_val = {off},
+ },
+
+ {
+ .ctl_name = "HPR Mux",
+ .str_val = "HPMIXR",
+ },
+ {
+ .ctl_name = "HPL Mux",
+ .str_val = "HPMIXL",
+ },
+ {
+ .ctl_name = "HPMIXL DACL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPMIXR DACR Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Speaker Playback Volume",
+ .int_val = {22, 22},
+ },
+ {
+ .ctl_name = "Ext Spk Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {on, on},
+ },
+};
+
+const struct config_control rk616_earpiece_incall_controls[] = {
+ {
+ .ctl_name = "SPK GPIO Control",
+ .str_val = "High",
+ },
+ {
+ .ctl_name = "HP GPIO Control",
+ .str_val = "Low",
+ },
+ {
+ .ctl_name = "RCV GPIO Control",
+ .str_val = "Low",
+ },
+
+ //mic1-->line1/2
+ {
+ .ctl_name = "Mic Jack Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mic Mux",
+ .str_val = "BSTL",
+ },
+ {
+ .ctl_name = "MIXINL MUXMIC Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Micbias1 Voltage",
+ .int_val = {7},
+ },
+ {
+ .ctl_name = "BST_L Mode",
+ .int_val = {0},
+ },
+ {
+ .ctl_name = "Main Mic Capture Volume",
+ .int_val = {1},
+ },
+ {
+ .ctl_name = "Main Mic Capture Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "MUXMIC to MIXINL Volume",
+ .int_val = {7},
+ },
+ {
+ .ctl_name = "MIXINL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "PGAL Capture Volume",
+ .int_val = {29},
+ },
+ {
+ .ctl_name = "PGAL Capture Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "LINEMIX PGAL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "LINEOUT1 Playback Volume",
+ .int_val = {31},
+ },
+ {
+ .ctl_name = "LINEOUT2 Playback Volume",
+ .int_val = {31},
+ },
+ {
+ .ctl_name = "LINEOUT1 Playback Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "LINEOUT2 Playback Switch",
+ .int_val = {on},
+ },
+ //IN1N/P ---> SPK
+ {
+ .ctl_name = "HPMix Mux",
+ .str_val = "DIFFIN",
+ },
+ {
+ .ctl_name = "HPMIXR HPMix Mux Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPR Mux",
+ .str_val = "HPMIXR",
+ },
+ {
+ .ctl_name = "HPMIXL HPMix Mux Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPL Mux",
+ .str_val = "HPMIXL",
+ },
+ {
+ .ctl_name = "Ext Spk Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "DIFFIN Mode",
+ .int_val = {0},
+ },
+ {
+ .ctl_name = "DIFFIN Capture Volume",
+ .int_val = {1},
+ },
+ {
+ .ctl_name = "DIFFIN Capture Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPMIX MUX to HPMIXL Volume",
+ .int_val = {7},
+ },
+ {
+ .ctl_name = "HPMIX MUX to HPMIXR Volume",
+ .int_val = {7},
+ },
+ {
+ .ctl_name = "Speaker Playback Volume",
+ .int_val = {31, 31},
+ },
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {on, on},
+ },
+};
+
+const struct config_control rk616_earpiece_ringtone_controls[] = {
+ {
+ .ctl_name = "SPK GPIO Control",
+ .str_val = "High",
+ },
+ {
+ .ctl_name = "HP GPIO Control",
+ .str_val = "Low",
+ },
+ {
+ .ctl_name = "RCV GPIO Control",
+ .str_val = "Low",
+ },
+
+ {
+ .ctl_name = "Headphone Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "Headphone Jack Switch",
+ .int_val = {off},
+ },
+
+ {
+ .ctl_name = "HPR Mux",
+ .str_val = "HPMIXR",
+ },
+ {
+ .ctl_name = "HPL Mux",
+ .str_val = "HPMIXL",
+ },
+ {
+ .ctl_name = "HPMIXL DACL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPMIXR DACR Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Speaker Playback Volume",
+ .int_val = {31, 31},
+ },
+ {
+ .ctl_name = "Ext Spk Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {on, on},
+ },
+};
+
+const struct config_control rk616_earpiece_voip_controls[] = {
+
+};
+
+const struct config_control rk616_headphone_normal_controls[] = {
+ {
+ .ctl_name = "SPK GPIO Control",
+ .str_val = "Low",
+ },
+ {
+ .ctl_name = "HP GPIO Control",
+ .str_val = "High",
+ },
+ {
+ .ctl_name = "RCV GPIO Control",
+ .str_val = "Low",
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "Ext Spk Switch",
+ .int_val = {off},
+ },
+
+ {
+ .ctl_name = "HPMIXL DACL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPMIXL DACL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPR Mux",
+ .str_val = "HPMIXR",
+ },
+ {
+ .ctl_name = "HPL Mux",
+ .str_val = "HPMIXL",
+ },
+ {
+ .ctl_name = "Headphone Playback Volume",
+ .int_val = {31, 31},
+ },
+ {
+ .ctl_name = "Headphone Jack Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Headphone Playback Switch",
+ .int_val = {on, on},
+ },
+};
+
+const struct config_control rk616_headphone_incall_controls[] = {
+ {
+ .ctl_name = "SPK GPIO Control",
+ .str_val = "Low",
+ },
+ {
+ .ctl_name = "HP GPIO Control",
+ .str_val = "High",
+ },
+ {
+ .ctl_name = "RCV GPIO Control",
+ .str_val = "Low",
+ },
+
+ //mic1-->line1/2
+ {
+ .ctl_name = "Mic Jack Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mic Mux",
+ .str_val = "BSTL",
+ },
+ {
+ .ctl_name = "MIXINL MUXMIC Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Micbias1 Voltage",
+ .int_val = {7},
+ },
+ {
+ .ctl_name = "BST_L Mode",
+ .int_val = {0},
+ },
+ {
+ .ctl_name = "Main Mic Capture Volume",
+ .int_val = {1},
+ },
+ {
+ .ctl_name = "Main Mic Capture Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "MUXMIC to MIXINL Volume",
+ .int_val = {7},
+ },
+ {
+ .ctl_name = "MIXINL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "PGAL Capture Volume",
+ .int_val = {29},
+ },
+ {
+ .ctl_name = "PGAL Capture Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "LINEMIX PGAL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "LINEOUT1 Playback Volume",
+ .int_val = {31},
+ },
+ {
+ .ctl_name = "LINEOUT2 Playback Volume",
+ .int_val = {31},
+ },
+ {
+ .ctl_name = "LINEOUT1 Playback Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "LINEOUT2 Playback Switch",
+ .int_val = {on},
+ },
+ //IN1N/P ---> HP
+ {
+ .ctl_name = "HPMix Mux",
+ .str_val = "DIFFIN",
+ },
+ {
+ .ctl_name = "HPMIXR HPMix Mux Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPR Mux",
+ .str_val = "HPMIXR",
+ },
+ {
+ .ctl_name = "HPMIXL HPMix Mux Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPL Mux",
+ .str_val = "HPMIXL",
+ },
+ {
+ .ctl_name = "Headphone Jack Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "DIFFIN Mode",
+ .int_val = {0},
+ },
+ {
+ .ctl_name = "DIFFIN Capture Volume",
+ .int_val = {1},
+ },
+ {
+ .ctl_name = "DIFFIN Capture Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPMIX MUX to HPMIXL Volume",
+ .int_val = {7},
+ },
+ {
+ .ctl_name = "HPMIX MUX to HPMIXR Volume",
+ .int_val = {7},
+ },
+ {
+ .ctl_name = "Headphone Playback Volume",
+ .int_val = {31, 31},
+ },
+ {
+ .ctl_name = "Headphone Playback Switch",
+ .int_val = {on, on},
+ },
+};
+
+const struct config_control rk616_headphone_ringtone_controls[] = {
+ {
+ .ctl_name = "SPK GPIO Control",
+ .str_val = "Low",
+ },
+ {
+ .ctl_name = "HP GPIO Control",
+ .str_val = "High",
+ },
+ {
+ .ctl_name = "RCV GPIO Control",
+ .str_val = "Low",
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "Ext Spk Switch",
+ .int_val = {off},
+ },
+
+ {
+ .ctl_name = "HPMIXL DACL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPMIXR DACR Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPR Mux",
+ .str_val = "HPMIXR",
+ },
+ {
+ .ctl_name = "HPL Mux",
+ .str_val = "HPMIXL",
+ },
+ {
+ .ctl_name = "Headphone Playback Volume",
+ .int_val = {31, 31},
+ },
+ {
+ .ctl_name = "Headphone Jack Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Headphone Playback Switch",
+ .int_val = {on, on},
+ },
+};
+
+const struct config_control rk616_speaker_headphone_normal_controls[] = {
+ {
+ .ctl_name = "SPK GPIO Control",
+ .str_val = "High",
+ },
+ {
+ .ctl_name = "HP GPIO Control",
+ .str_val = "High",
+ },
+ {
+ .ctl_name = "RCV GPIO Control",
+ .str_val = "Low",
+ },
+
+ {
+ .ctl_name = "HPMIXL DACL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPMIXR DACR Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPR Mux",
+ .str_val = "HPMIXR",
+ },
+ {
+ .ctl_name = "HPL Mux",
+ .str_val = "HPMIXL",
+ },
+ {
+ .ctl_name = "Headphone Playback Volume",
+ .int_val = {31, 31},
+ },
+ {
+ .ctl_name = "Headphone Jack Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Headphone Playback Switch",
+ .int_val = {on, on},
+ },
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {on, on},
+ },
+ {
+ .ctl_name = "Ext Spk Switch",
+ .int_val = {on},
+ },
+};
+
+const struct config_control rk616_speaker_headphone_ringtone_controls[] = {
+ {
+ .ctl_name = "SPK GPIO Control",
+ .str_val = "High",
+ },
+ {
+ .ctl_name = "HP GPIO Control",
+ .str_val = "High",
+ },
+ {
+ .ctl_name = "RCV GPIO Control",
+ .str_val = "Low",
+ },
+
+ {
+ .ctl_name = "HPMIXL DACL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPMIXR DACR Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPR Mux",
+ .str_val = "HPMIXR",
+ },
+ {
+ .ctl_name = "HPL Mux",
+ .str_val = "HPMIXL",
+ },
+ {
+ .ctl_name = "Headphone Playback Volume",
+ .int_val = {31, 31},
+ },
+ {
+ .ctl_name = "Headphone Jack Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Headphone Playback Switch",
+ .int_val = {on, on},
+ },
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {on, on},
+ },
+ {
+ .ctl_name = "Ext Spk Switch",
+ .int_val = {on},
+ },
+};
+
+const struct config_control rk616_headphone_voip_controls[] = {
+
+};
+
+const struct config_control rk616_headset_normal_controls[] = {
+ {
+ .ctl_name = "SPK GPIO Control",
+ .str_val = "Low",
+ },
+ {
+ .ctl_name = "HP GPIO Control",
+ .str_val = "High",
+ },
+ {
+ .ctl_name = "RCV GPIO Control",
+ .str_val = "Low",
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "Ext Spk Switch",
+ .int_val = {off},
+ },
+
+ {
+ .ctl_name = "HPMIXL DACL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPMIXR DACR Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPR Mux",
+ .str_val = "HPMIXR",
+ },
+ {
+ .ctl_name = "HPL Mux",
+ .str_val = "HPMIXL",
+ },
+ {
+ .ctl_name = "Headphone Playback Volume",
+ .int_val = {31, 31},
+ },
+ {
+ .ctl_name = "Headphone Jack Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Headphone Playback Switch",
+ .int_val = {on, on},
+ },
+};
+
+const struct config_control rk616_headset_incall_controls[] = {
+ {
+ .ctl_name = "SPK GPIO Control",
+ .str_val = "Low",
+ },
+ {
+ .ctl_name = "HP GPIO Control",
+ .str_val = "High",
+ },
+ {
+ .ctl_name = "RCV GPIO Control",
+ .str_val = "Low",
+ },
+
+ //mic2-->line1/2
+ {
+ .ctl_name = "Mic Jack Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mic Mux",
+ .str_val = "BSTR",
+ },
+ {
+ .ctl_name = "MIXINL MUXMIC Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Micbias2 Voltage",
+ .int_val = {0},
+ },
+ {
+ .ctl_name = "BST_R Mode",
+ .int_val = {1},
+ },
+ {
+ .ctl_name = "Headset Mic Capture Volume",
+ .int_val = {1},
+ },
+ {
+ .ctl_name = "Headset Mic Capture Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "MUXMIC to MIXINL Volume",
+ .int_val = {7},
+ },
+ {
+ .ctl_name = "MIXINL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "PGAL Capture Volume",
+ .int_val = {29},
+ },
+ {
+ .ctl_name = "PGAL Capture Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "LINEMIX PGAL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "LINEOUT1 Playback Volume",
+ .int_val = {31},
+ },
+ {
+ .ctl_name = "LINEOUT2 Playback Volume",
+ .int_val = {31},
+ },
+ {
+ .ctl_name = "LINEOUT1 Playback Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "LINEOUT2 Playback Switch",
+ .int_val = {on},
+ },
+ //IN1N/P ---> HP
+ {
+ .ctl_name = "HPMix Mux",
+ .str_val = "DIFFIN",
+ },
+ {
+ .ctl_name = "HPMIXR HPMix Mux Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPR Mux",
+ .str_val = "HPMIXR",
+ },
+ {
+ .ctl_name = "HPMIXL HPMix Mux Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPL Mux",
+ .str_val = "HPMIXL",
+ },
+ {
+ .ctl_name = "Headphone Jack Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "DIFFIN Mode",
+ .int_val = {0},
+ },
+ {
+ .ctl_name = "DIFFIN Capture Volume",
+ .int_val = {1},
+ },
+ {
+ .ctl_name = "DIFFIN Capture Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPMIX MUX to HPMIXL Volume",
+ .int_val = {7},
+ },
+ {
+ .ctl_name = "HPMIX MUX to HPMIXR Volume",
+ .int_val = {7},
+ },
+ {
+ .ctl_name = "Headphone Playback Volume",
+ .int_val = {31, 31},
+ },
+ {
+ .ctl_name = "Headphone Playback Switch",
+ .int_val = {on, on},
+ },
+};
+
+const struct config_control rk616_headset_ringtone_controls[] = {
+ {
+ .ctl_name = "SPK GPIO Control",
+ .str_val = "Low",
+ },
+ {
+ .ctl_name = "HP GPIO Control",
+ .str_val = "High",
+ },
+ {
+ .ctl_name = "RCV GPIO Control",
+ .str_val = "Low",
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "Ext Spk Switch",
+ .int_val = {off},
+ },
+
+ {
+ .ctl_name = "HPMIXL DACL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPMIXR DACR Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPR Mux",
+ .str_val = "HPMIXR",
+ },
+ {
+ .ctl_name = "HPL Mux",
+ .str_val = "HPMIXL",
+ },
+ {
+ .ctl_name = "Headphone Playback Volume",
+ .int_val = {31, 31},
+ },
+ {
+ .ctl_name = "Headphone Jack Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Headphone Playback Switch",
+ .int_val = {on, on},
+ },
+};
+
+const struct config_control rk616_headset_voip_controls[] = {
+
+};
+
+const struct config_control rk616_bluetooth_normal_controls[] = {
+
+};
+
+const struct config_control rk616_bluetooth_incall_controls[] = {
+ //DACL --> line1/2
+ {
+ .ctl_name = "LINEMIX DACL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "LINEOUT1 Playback Volume",
+ .int_val = {31},
+ },
+ {
+ .ctl_name = "LINEOUT2 Playback Volume",
+ .int_val = {31},
+ },
+ {
+ .ctl_name = "LINEOUT1 Playback Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "LINEOUT2 Playback Switch",
+ .int_val = {on},
+ },
+ //IN1N/P-->ADCL
+ {
+ .ctl_name = "MIXINL IN1P Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "MIXINL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "IN1P to MIXINL Volume",
+ .int_val = {7},
+ },
+ {
+ .ctl_name = "PGAL Capture Volume",
+ .int_val = {31},
+ },
+ {
+ .ctl_name = "PGAL Capture Switch",
+ .int_val = {on},
+ },
+};
+
+const struct config_control rk616_bluetooth_voip_controls[] = {
+
+};
+
+const struct config_control rk616_main_mic_capture_controls[] = {
+ {
+ .ctl_name = "Headset Mic Capture Switch",
+ .int_val = {off},
+ },
+
+ {
+ .ctl_name = "Main Mic Capture Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mic Mux",
+ .str_val = "BSTL",
+ },
+ {
+ .ctl_name = "MUXMIC to MIXINL Volume",
+ .int_val = {7},
+ },
+ {
+ .ctl_name = "MIXINL MUXMIC Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "MIXINL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Main Mic Capture Volume",
+ .int_val = {1},
+ },
+ {
+ .ctl_name = "BST_L Mode",
+ .int_val = {0},
+ },
+ {
+ .ctl_name = "Micbias1 Voltage",
+ .int_val = {7},
+ },
+ {
+ .ctl_name = "PGAL Capture Volume",
+ .int_val = {31},
+ },
+ {
+ .ctl_name = "Mic Jack Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "PGAL Capture Switch",
+ .int_val = {on},
+ },
+};
+
+const struct config_control rk616_hands_free_mic_capture_controls[] = {
+ {
+ .ctl_name = "Mic Jack Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Main Mic Capture Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Micbias1 Voltage",
+ .int_val = {0},
+ },
+
+ {
+ .ctl_name = "Headset Mic Capture Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mic Mux",
+ .str_val = "BSTR",
+ },
+ {
+ .ctl_name = "MUXMIC to MIXINL Volume",
+ .int_val = {7},
+ },
+ {
+ .ctl_name = "MIXINL MUXMIC Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "MIXINL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Headset Mic Capture Volume",
+ .int_val = {1},
+ },
+ {
+ .ctl_name = "BST_R Mode",
+ .int_val = {1},
+ },
+ {
+ .ctl_name = "Micbias2 Voltage",
+ .int_val = {7},
+ },
+ {
+ .ctl_name = "PGAL Capture Volume",
+ .int_val = {25},
+ },
+ {
+ .ctl_name = "Headset Jack Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "PGAL Capture Switch",
+ .int_val = {on},
+ },
+};
+
+const struct config_control rk616_bluetooth_sco_mic_capture_controls[] = {
+
+};
+
+const struct config_control rk616_playback_off_controls[] = {
+ {
+ .ctl_name = "SPK GPIO Control",
+ .str_val = "Low",
+ },
+ {
+ .ctl_name = "HP GPIO Control",
+ .str_val = "Low",
+ },
+ {
+ .ctl_name = "RCV GPIO Control",
+ .str_val = "Low",
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "Ext Spk Switch",
+ .int_val = {off},
+ },
+
+ {
+ .ctl_name = "HPMIXL DACL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "HPMIXL DACL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Headphone Jack Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Headphone Playback Switch",
+ .int_val = {off, off},
+ },
+};
+
+const struct config_control rk616_capture_off_controls[] = {
+ {
+ .ctl_name = "Mic Jack Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Main Mic Capture Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Headset Mic Capture Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "MIXINL MUXMIC Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "MIXINL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Headset Jack Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "PGAL Capture Switch",
+ .int_val = {off},
+ },
+};
+
+const struct config_control rk616_incall_off_controls[] = {
+ {
+ .ctl_name = "SPK GPIO Control",
+ .str_val = "Low",
+ },
+ {
+ .ctl_name = "HP GPIO Control",
+ .str_val = "Low",
+ },
+ {
+ .ctl_name = "RCV GPIO Control",
+ .str_val = "Low",
+ },
+
+ //close mic1-->line1/2
+ {
+ .ctl_name = "Mic Jack Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "MIXINL MUXMIC Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Main Mic Capture Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "MIXINL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "PGAL Capture Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LINEMIX PGAL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LINEOUT1 Playback Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LINEOUT2 Playback Switch",
+ .int_val = {off},
+ },
+ //clsoe IN1N/P ---> SPK
+ {
+ .ctl_name = "HPMIXR HPMix Mux Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "HPMIXL HPMix Mux Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Ext Spk Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "DIFFIN Capture Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+};
+
+const struct config_control rk616_voip_off_controls[] = {
+
+};
+
+const struct config_route_table rk616_config_table = {
+ //speaker
+ .speaker_normal = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_speaker_normal_controls,
+ .controls_count = sizeof(rk616_speaker_normal_controls) / sizeof(struct config_control),
+ },
+ .speaker_incall = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_speaker_incall_controls,
+ .controls_count = sizeof(rk616_speaker_incall_controls) / sizeof(struct config_control),
+ },
+ .speaker_ringtone = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_speaker_ringtone_controls,
+ .controls_count = sizeof(rk616_speaker_ringtone_controls) / sizeof(struct config_control),
+ },
+ .speaker_voip = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_speaker_voip_controls,
+ .controls_count = sizeof(rk616_speaker_voip_controls) / sizeof(struct config_control),
+ },
+
+ //earpiece
+ .earpiece_normal = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_earpiece_normal_controls,
+ .controls_count = sizeof(rk616_earpiece_normal_controls) / sizeof(struct config_control),
+ },
+ .earpiece_incall = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_earpiece_incall_controls,
+ .controls_count = sizeof(rk616_earpiece_incall_controls) / sizeof(struct config_control),
+ },
+ .earpiece_ringtone = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_earpiece_ringtone_controls,
+ .controls_count = sizeof(rk616_earpiece_ringtone_controls) / sizeof(struct config_control),
+ },
+ .earpiece_voip = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_earpiece_voip_controls,
+ .controls_count = sizeof(rk616_earpiece_voip_controls) / sizeof(struct config_control),
+ },
+
+ //headphone
+ .headphone_normal = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_headphone_normal_controls,
+ .controls_count = sizeof(rk616_headphone_normal_controls) / sizeof(struct config_control),
+ },
+ .headphone_incall = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_headphone_incall_controls,
+ .controls_count = sizeof(rk616_headphone_incall_controls) / sizeof(struct config_control),
+ },
+ .headphone_ringtone = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_headphone_ringtone_controls,
+ .controls_count = sizeof(rk616_headphone_ringtone_controls) / sizeof(struct config_control),
+ },
+ .speaker_headphone_normal = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_speaker_headphone_normal_controls,
+ .controls_count = sizeof(rk616_speaker_headphone_normal_controls) / sizeof(struct config_control),
+ },
+ .speaker_headphone_ringtone = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_speaker_headphone_ringtone_controls,
+ .controls_count = sizeof(rk616_speaker_headphone_ringtone_controls) / sizeof(struct config_control),
+ },
+ .headphone_voip = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_headphone_voip_controls,
+ .controls_count = sizeof(rk616_headphone_voip_controls) / sizeof(struct config_control),
+ },
+
+ //headset
+ .headset_normal = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_headset_normal_controls,
+ .controls_count = sizeof(rk616_headset_normal_controls) / sizeof(struct config_control),
+ },
+ .headset_incall = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_headset_incall_controls,
+ .controls_count = sizeof(rk616_headset_incall_controls) / sizeof(struct config_control),
+ },
+ .headset_ringtone = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_headset_ringtone_controls,
+ .controls_count = sizeof(rk616_headset_ringtone_controls) / sizeof(struct config_control),
+ },
+ .headset_voip = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_headset_voip_controls,
+ .controls_count = sizeof(rk616_headset_voip_controls) / sizeof(struct config_control),
+ },
+
+ //bluetooth
+ .bluetooth_normal = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_bluetooth_normal_controls,
+ .controls_count = sizeof(rk616_bluetooth_normal_controls) / sizeof(struct config_control),
+ },
+ .bluetooth_incall = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_bluetooth_incall_controls,
+ .controls_count = sizeof(rk616_bluetooth_incall_controls) / sizeof(struct config_control),
+ },
+ .bluetooth_voip = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_bluetooth_voip_controls,
+ .controls_count = sizeof(rk616_bluetooth_voip_controls) / sizeof(struct config_control),
+ },
+
+ //capture
+ .main_mic_capture = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_main_mic_capture_controls,
+ .controls_count = sizeof(rk616_main_mic_capture_controls) / sizeof(struct config_control),
+ },
+ .hands_free_mic_capture = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_hands_free_mic_capture_controls,
+ .controls_count = sizeof(rk616_hands_free_mic_capture_controls) / sizeof(struct config_control),
+ },
+ .bluetooth_sco_mic_capture = {
+ .sound_card = 0,
+ .devices = DEVICES_0,
+ .controls = rk616_bluetooth_sco_mic_capture_controls,
+ .controls_count = sizeof(rk616_bluetooth_sco_mic_capture_controls) / sizeof(struct config_control),
+ },
+
+ //off
+ .playback_off = {
+ .controls = rk616_playback_off_controls,
+ .controls_count = sizeof(rk616_playback_off_controls) / sizeof(struct config_control),
+ },
+ .capture_off = {
+ .controls = rk616_capture_off_controls,
+ .controls_count = sizeof(rk616_capture_off_controls) / sizeof(struct config_control),
+ },
+ .incall_off = {
+ .controls = rk616_incall_off_controls,
+ .controls_count = sizeof(rk616_incall_off_controls) / sizeof(struct config_control),
+ },
+ .voip_off = {
+ .controls = rk616_voip_off_controls,
+ .controls_count = sizeof(rk616_voip_off_controls) / sizeof(struct config_control),
+ },
+
+ //hdmi
+ .hdmi_normal = {
+ .sound_card = 1,
+ .devices = DEVICES_0,
+ .controls_count = 0,
+ },
+
+ //usb audio
+ .usb_normal = {
+ .sound_card = 2,
+ .devices = DEVICES_0,
+ .controls_count = 0,
+ },
+ .usb_capture = {
+ .sound_card = 2,
+ .devices = DEVICES_0,
+ .controls_count = 0,
+ },
+};
+
+#endif //_RK616_CONFIG_H_
diff --git a/legacy_hal/codec_config/rt3224_config.h b/legacy_hal/codec_config/rt3224_config.h
new file mode 100755
index 0000000..17f1a20
--- /dev/null
+++ b/legacy_hal/codec_config/rt3224_config.h
@@ -0,0 +1,3962 @@
+/*
+ * Copyright (C) 2015 Rockchip Electronics Co., Ltd.
+*/
+
+#ifndef _RT3224_CONFIG_H_
+#define _RT3224_CONFIG_H_
+
+#include "config.h"
+
+const struct config_control rt3224_speaker_normal_controls[] = {
+ //disable ASRC
+ {
+ .ctl_name = "ASRC Switch",
+ .str_val = "Disable",
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "OUT Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "Modem Input Switch",
+ .int_val = {0},
+ },
+
+ //OPEN ROUTE
+ {
+ .ctl_name = "DAC L2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "DAC R2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "Mono dacr Mux",
+ .str_val = "TxDC_R",
+ },
+ {
+ .ctl_name = "DACR Select",
+ .str_val = "IF2_DAC",
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mono DAC MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "SPK MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "SPK MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+
+ //dBscale-min=-46.50dB,step=1.50dB,min=0,max=31
+ {
+ .ctl_name = "Speaker Playback Volume",
+ .int_val = {31, 31},
+ },
+ //dBscale-min=-65.625dB,step=0.375dB,min=0,max=175
+ {
+ .ctl_name = "Mono DAC Playback Volume",
+ .int_val = {175, 175},
+ },
+ //min=0,max=10
+ {
+ .ctl_name = "Class D SPK Ratio Control",
+ .int_val = {10},
+ },
+
+ //speaker incall
+ {
+ .ctl_name = "RECMIXL BST2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo ADC MIXL ADC1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "DAC MIXL Stereo ADC Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXL OUT MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXR DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXR OUT MIXR Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC R1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC L1 Switch",
+ .int_val = {off},
+ },
+
+ //headphone && headset normal
+ {
+ .ctl_name = "OUT MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "HPO MIX HPVOL Switch",
+ .int_val = {off},
+ },
+
+ //bt incall
+ {
+ .ctl_name = "DAC MIXL INF1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX OUTVOL L Switch",
+ .int_val = {off},
+ },
+
+ //close other mixer
+ {
+ .ctl_name = "OUT MIXL REC MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXR REC MIXR Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "DAC MIXR Stereo ADC Switch",
+ .int_val = {off},
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {on, on},
+ },
+};
+
+const struct config_control rt3224_speaker_incall_controls[] = {
+ //disable ASRC
+ {
+ .ctl_name = "ASRC Switch",
+ .str_val = "Disable",
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "OUT Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "Modem Input Switch",
+ .int_val = {1},
+ },
+
+ //OPEN ROUTE
+ {
+ .ctl_name = "RECMIXL BST2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Stereo ADC L1 Mux",
+ .str_val = "ADC",
+ },
+ {
+ .ctl_name = "Stereo ADC MIXL ADC1 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "DAC MIXL Stereo ADC Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L1 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "SPK MIXL OUT MIXL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "OUT MIXR DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "SPK MIXR OUT MIXR Switch",
+ .int_val = {on},
+ },
+
+ //min=0,max=8, bypass=0=0db, 30db=3, 52db=8
+ {
+ .ctl_name = "IN2 Boost",
+ .int_val = {0},
+ },
+
+ //dBscale-min=-17.625dB,step=0.375dB,min=0,max=127
+ {
+ .ctl_name = "ADC Capture Volume",
+ .int_val = {55, 55},
+ },
+ //min=0,max=10
+ {
+ .ctl_name = "Class D SPK Ratio Control",
+ .int_val = {10},
+ },
+
+ {
+ .ctl_name = "RECMIXR BST1 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mono ADC R1 Mux",
+ .str_val = "ADCR",
+ },
+ {
+ .ctl_name = "Mono ADC MIXR ADC1 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "IF2 ADC R Mux",
+ .str_val = "Mono ADC MIXR",
+ },
+ {
+ .ctl_name = "Mono dacr Mux",
+ .str_val = "TxDP_R",
+ },
+ {
+ .ctl_name = "DACR Select",
+ .str_val = "IF2_ADC",
+ },
+ {
+ .ctl_name = "Stereo DAC MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC R1 Switch",
+ .int_val = {on},
+ },
+
+ //"Single ended"=0, "Differential"=1
+ {
+ .ctl_name = "IN1 Mode Control",
+ .str_val = "Differential",
+ },
+ //min=0,max=8, bypass=0=0db, 30db=3, 52db=8
+ {
+ .ctl_name = "IN1 Boost",
+ .int_val = {4},
+ },
+ //dBscale-min=-17.625dB,step=0.375dB,min=0,max=127
+ {
+ .ctl_name = "Mono ADC Capture Volume",
+ .int_val = {47, 47},
+ },
+ //dBscale-min=-65.625dB,step=0.375dB,min=0,max=175
+ {
+ .ctl_name = "Mono DAC Playback Volume",
+ .int_val = {175, 175},
+ },
+
+ //OPEN KEY TONE
+ {
+ .ctl_name = "DAC L2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC L1 Switch",
+ .int_val = {on},
+ },
+
+ //speaker normal
+ {
+ .ctl_name = "Mono DAC MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXL DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+
+ //headphone && headset normal
+ {
+ .ctl_name = "OUT MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "HPO MIX HPVOL Switch",
+ .int_val = {off},
+ },
+
+ //headphone && headset incall
+
+ //bt incall
+ {
+ .ctl_name = "DAC MIXL INF1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX OUTVOL L Switch",
+ .int_val = {off},
+ },
+
+ //close other mixer
+ {
+ .ctl_name = "OUT MIXL REC MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXR REC MIXR Switch",
+ .int_val = {off},
+ },
+
+ {
+ .ctl_name = "OUT Playback Switch",
+ .int_val = {on, on},
+ },
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {on, on},
+ },
+};
+
+const struct config_control rt3224_speaker_ringtone_controls[] = {
+ //disable ASRC
+ {
+ .ctl_name = "ASRC Switch",
+ .str_val = "Disable",
+ },
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+
+ //OPEN ROUTE
+ {
+ .ctl_name = "DAC L2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "DAC R2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "Mono dacr Mux",
+ .str_val = "TxDC_R",
+ },
+ {
+ .ctl_name = "DACR Select",
+ .str_val = "IF2_DAC",
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mono DAC MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "SPK MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "SPK MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+
+ //dBscale-min=-46.50dB,step=1.50dB,min=0,max=31
+ {
+ .ctl_name = "Speaker Playback Volume",
+ .int_val = {31, 31},
+ },
+ //dBscale-min=-65.625dB,step=0.375dB,min=0,max=175
+ {
+ .ctl_name = "Mono DAC Playback Volume",
+ .int_val = {175, 175},
+ },
+ //min=0,max=10
+ {
+ .ctl_name = "Class D SPK Ratio Control",
+ .int_val = {10},
+ },
+
+ //speaker incall
+ {
+ .ctl_name = "RECMIXL BST2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo ADC MIXL ADC1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "DAC MIXL Stereo ADC Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXL OUT MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXR DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXR OUT MIXR Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC R1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC L1 Switch",
+ .int_val = {off},
+ },
+
+ //headphone && headset normal
+ {
+ .ctl_name = "OUT MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "HPO MIX HPVOL Switch",
+ .int_val = {off},
+ },
+
+ //bt incall
+ {
+ .ctl_name = "DAC MIXL INF1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX OUTVOL L Switch",
+ .int_val = {off},
+ },
+
+ //close other mixer
+ {
+ .ctl_name = "OUT MIXL REC MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXR REC MIXR Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "DAC MIXR Stereo ADC Switch",
+ .int_val = {off},
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {on, on},
+ },
+};
+
+const struct config_control rt3224_speaker_voip_controls[] = {
+ //disable ASRC
+ {
+ .ctl_name = "ASRC Switch",
+ .str_val = "Disable",
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "OUT Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "Modem Input Switch",
+ .int_val = {0},
+ },
+
+ //OPEN ROUTE
+ {
+ .ctl_name = "DAC L2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "DAC R2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "Mono dacr Mux",
+ .str_val = "TxDC_R",
+ },
+ {
+ .ctl_name = "DACR Select",
+ .str_val = "IF2_DAC",
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mono DAC MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "SPK MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "SPK MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+
+ //dBscale-min=-46.50dB,step=1.50dB,min=0,max=31
+ {
+ .ctl_name = "Speaker Playback Volume",
+ .int_val = {31, 31},
+ },
+ //dBscale-min=-65.625dB,step=0.375dB,min=0,max=175
+ {
+ .ctl_name = "Mono DAC Playback Volume",
+ .int_val = {175, 175},
+ },
+ //min=0,max=10
+ {
+ .ctl_name = "Class D SPK Ratio Control",
+ .int_val = {10},
+ },
+
+ //speaker incall
+ {
+ .ctl_name = "RECMIXL BST2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo ADC MIXL ADC1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "DAC MIXL Stereo ADC Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXL OUT MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXR DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXR OUT MIXR Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC R1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC L1 Switch",
+ .int_val = {off},
+ },
+
+ //headphone && headset normal
+ {
+ .ctl_name = "OUT MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "HPO MIX HPVOL Switch",
+ .int_val = {off},
+ },
+
+ //bt incall
+ {
+ .ctl_name = "DAC MIXL INF1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX OUTVOL L Switch",
+ .int_val = {off},
+ },
+
+ //close other mixer
+ {
+ .ctl_name = "OUT MIXL REC MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXR REC MIXR Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "DAC MIXR Stereo ADC Switch",
+ .int_val = {off},
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {on, on},
+ },
+};
+
+const struct config_control rt3224_earpiece_normal_controls[] = {
+
+};
+
+const struct config_control rt3224_earpiece_incall_controls[] = {
+ //disable ASRC
+ {
+ .ctl_name = "ASRC Switch",
+ .str_val = "Disable",
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "OUT Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "Modem Input Switch",
+ .int_val = {1},
+ },
+
+ //OPEN ROUTE
+ {
+ .ctl_name = "RECMIXL BST2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Stereo ADC L1 Mux",
+ .str_val = "ADC",
+ },
+ {
+ .ctl_name = "Stereo ADC MIXL ADC1 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "DAC MIXL Stereo ADC Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L1 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "SPK MIXL OUT MIXL Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "OUT MIXR DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "SPK MIXR OUT MIXR Switch",
+ .int_val = {on},
+ },
+
+ //min=0,max=8, bypass=0=0db, 30db=3, 52db=8
+ {
+ .ctl_name = "IN2 Boost",
+ .int_val = {0},
+ },
+
+ //dBscale-min=-17.625dB,step=0.375dB,min=0,max=127
+ {
+ .ctl_name = "ADC Capture Volume",
+ .int_val = {55, 55},
+ },
+ //min=0,max=10
+ {
+ .ctl_name = "Class D SPK Ratio Control",
+ .int_val = {10},
+ },
+
+ {
+ .ctl_name = "RECMIXR BST1 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mono ADC R1 Mux",
+ .str_val = "ADCR",
+ },
+ {
+ .ctl_name = "Mono ADC MIXR ADC1 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "IF2 ADC R Mux",
+ .str_val = "Mono ADC MIXR",
+ },
+ {
+ .ctl_name = "Mono dacr Mux",
+ .str_val = "TxDP_R",
+ },
+ {
+ .ctl_name = "DACR Select",
+ .str_val = "IF2_ADC",
+ },
+ {
+ .ctl_name = "Stereo DAC MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC R1 Switch",
+ .int_val = {on},
+ },
+
+ //"Single ended"=0, "Differential"=1
+ {
+ .ctl_name = "IN1 Mode Control",
+ .str_val = "Differential",
+ },
+ //min=0,max=8, bypass=0=0db, 30db=3, 52db=8
+ {
+ .ctl_name = "IN1 Boost",
+ .int_val = {4},
+ },
+ //dBscale-min=-17.625dB,step=0.375dB,min=0,max=127
+ {
+ .ctl_name = "Mono ADC Capture Volume",
+ .int_val = {47, 47},
+ },
+ //dBscale-min=-65.625dB,step=0.375dB,min=0,max=175
+ {
+ .ctl_name = "Mono DAC Playback Volume",
+ .int_val = {175, 175},
+ },
+
+ //OPEN KEY TONE
+ {
+ .ctl_name = "DAC L2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC L1 Switch",
+ .int_val = {on},
+ },
+
+ //speaker normal
+ {
+ .ctl_name = "Mono DAC MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXL DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+
+ //headphone && headset normal
+ {
+ .ctl_name = "OUT MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "HPO MIX HPVOL Switch",
+ .int_val = {off},
+ },
+
+ //headphone && headset incall
+
+ //bt incall
+ {
+ .ctl_name = "DAC MIXL INF1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX OUTVOL L Switch",
+ .int_val = {off},
+ },
+
+ //close other mixer
+ {
+ .ctl_name = "OUT MIXL REC MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXR REC MIXR Switch",
+ .int_val = {off},
+ },
+
+ {
+ .ctl_name = "OUT Playback Switch",
+ .int_val = {on, on},
+ },
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {on, on},
+ },
+};
+
+const struct config_control rt3224_earpiece_ringtone_controls[] = {
+ //disable ASRC
+ {
+ .ctl_name = "ASRC Switch",
+ .str_val = "Disable",
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+
+ //OPEN ROUTE
+ {
+ .ctl_name = "DAC L2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "DAC R2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "Mono dacr Mux",
+ .str_val = "TxDC_R",
+ },
+ {
+ .ctl_name = "DACR Select",
+ .str_val = "IF2_DAC",
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mono DAC MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "SPK MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "SPK MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+
+ //dBscale-min=-46.50dB,step=1.50dB,min=0,max=31
+ {
+ .ctl_name = "Speaker Playback Volume",
+ .int_val = {31, 31},
+ },
+ //dBscale-min=-65.625dB,step=0.375dB,min=0,max=175
+ {
+ .ctl_name = "Mono DAC Playback Volume",
+ .int_val = {175, 175},
+ },
+ //min=0,max=10
+ {
+ .ctl_name = "Class D SPK Ratio Control",
+ .int_val = {10},
+ },
+
+ //speaker incall
+ {
+ .ctl_name = "RECMIXL BST2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo ADC MIXL ADC1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "DAC MIXL Stereo ADC Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXL OUT MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXR DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXR OUT MIXR Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC R1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC L1 Switch",
+ .int_val = {off},
+ },
+
+ //headphone && headset normal
+ {
+ .ctl_name = "OUT MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "HPO MIX HPVOL Switch",
+ .int_val = {off},
+ },
+
+ //bt incall
+ {
+ .ctl_name = "DAC MIXL INF1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX OUTVOL L Switch",
+ .int_val = {off},
+ },
+
+ //close other mixer
+ {
+ .ctl_name = "OUT MIXL REC MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXR REC MIXR Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "DAC MIXR Stereo ADC Switch",
+ .int_val = {off},
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {on, on},
+ },
+};
+
+const struct config_control rt3224_earpiece_voip_controls[] = {
+ //disable ASRC
+ {
+ .ctl_name = "ASRC Switch",
+ .str_val = "Disable",
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "OUT Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "Modem Input Switch",
+ .int_val = {0},
+ },
+
+ //OPEN ROUTE
+ {
+ .ctl_name = "DAC L2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "DAC R2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "Mono dacr Mux",
+ .str_val = "TxDC_R",
+ },
+ {
+ .ctl_name = "DACR Select",
+ .str_val = "IF2_DAC",
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mono DAC MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "SPK MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "SPK MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+
+ //dBscale-min=-46.50dB,step=1.50dB,min=0,max=31
+ {
+ .ctl_name = "Speaker Playback Volume",
+ .int_val = {31, 31},
+ },
+ //dBscale-min=-65.625dB,step=0.375dB,min=0,max=175
+ {
+ .ctl_name = "Mono DAC Playback Volume",
+ .int_val = {175, 175},
+ },
+ //min=0,max=10
+ {
+ .ctl_name = "Class D SPK Ratio Control",
+ .int_val = {10},
+ },
+
+ //speaker incall
+ {
+ .ctl_name = "RECMIXL BST2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo ADC MIXL ADC1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "DAC MIXL Stereo ADC Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXL OUT MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXR DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXR OUT MIXR Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC R1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC L1 Switch",
+ .int_val = {off},
+ },
+
+ //headphone && headset normal
+ {
+ .ctl_name = "OUT MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "HPO MIX HPVOL Switch",
+ .int_val = {off},
+ },
+
+ //bt incall
+ {
+ .ctl_name = "DAC MIXL INF1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX OUTVOL L Switch",
+ .int_val = {off},
+ },
+
+ //close other mixer
+ {
+ .ctl_name = "OUT MIXL REC MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXR REC MIXR Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "DAC MIXR Stereo ADC Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {on, on},
+ },
+};
+
+const struct config_control rt3224_headphone_normal_controls[] = {
+ //disable ASRC
+ {
+ .ctl_name = "ASRC Switch",
+ .str_val = "Disable",
+ },
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+/*
+ {
+ .ctl_name = "HP mute Switch",
+ .int_val = {off},
+ },
+*/
+ {
+ .ctl_name = "OUT Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "Modem Input Switch",
+ .int_val = {0},
+ },
+
+ //OPEN ROUTE
+ {
+ .ctl_name = "DAC L2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "DAC R2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "Mono dacr Mux",
+ .str_val = "TxDC_R",
+ },
+ {
+ .ctl_name = "DACR Select",
+ .str_val = "IF2_DAC",
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mono DAC MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "OUT MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPO MIX HPVOL Switch",
+ .int_val = {on},
+ },
+
+ //dBscale-min=-46.50dB,step=1.50dB,min=0,max=31
+ {
+ .ctl_name = "Headphone Playback Volume",
+ .int_val = {31, 31},
+ },
+ //dBscale-min=-65.625dB,step=0.375dB,min=0,max=175
+ {
+ .ctl_name = "Mono DAC Playback Volume",
+ .int_val = {175, 175},
+ },
+
+ //speaker normal
+ {
+ .ctl_name = "SPK MIXL DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+
+ //speaker incall
+ {
+ .ctl_name = "Stereo ADC MIXL ADC1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "DAC MIXL Stereo ADC Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXL OUT MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXR DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXR OUT MIXR Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC R1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC L1 Switch",
+ .int_val = {off},
+ },
+
+ //bt incall
+ {
+ .ctl_name = "DAC MIXL INF1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX OUTVOL L Switch",
+ .int_val = {off},
+ },
+
+ //close other mixer
+ {
+ .ctl_name = "OUT MIXL REC MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXR REC MIXR Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "DAC MIXR Stereo ADC Switch",
+ .int_val = {off},
+ },
+/*
+ {
+ .ctl_name = "HP mute Switch",
+ .int_val = {on},
+ },
+*/
+};
+
+const struct config_control rt3224_headphone_incall_controls[] = {
+ //disable ASRC
+ {
+ .ctl_name = "ASRC Switch",
+ .str_val = "Disable",
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+/*
+ {
+ .ctl_name = "HP mute Switch",
+ .int_val = {off},
+ },
+*/
+ {
+ .ctl_name = "OUT Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "Modem Input Switch",
+ .int_val = {1},
+ },
+
+ //OPEN ROUTE
+ {
+ .ctl_name = "RECMIXL BST2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Stereo ADC L1 Mux",
+ .str_val = "ADC",
+ },
+ {
+ .ctl_name = "Stereo ADC MIXL ADC1 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "DAC MIXL Stereo ADC Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L1 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "OUT MIXR DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPO MIX HPVOL Switch",
+ .int_val = {on},
+ },
+
+ //min=0,max=8, bypass=0=0db, 30db=3, 52db=8
+ {
+ .ctl_name = "IN2 Boost",
+ .int_val = {0},
+ },
+
+ //dBscale-min=-17.625dB,step=0.375dB,min=0,max=127
+ {
+ .ctl_name = "ADC Capture Volume",
+ .int_val = {55, 55},
+ },
+
+ {
+ .ctl_name = "RECMIXR BST1 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mono ADC R1 Mux",
+ .str_val = "ADCR",
+ },
+ {
+ .ctl_name = "Mono ADC MIXR ADC1 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "IF2 ADC R Mux",
+ .str_val = "Mono ADC MIXR",
+ },
+ {
+ .ctl_name = "Mono dacr Mux",
+ .str_val = "TxDP_R",
+ },
+ {
+ .ctl_name = "DACR Select",
+ .str_val = "IF2_ADC",
+ },
+ {
+ .ctl_name = "Stereo DAC MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC R1 Switch",
+ .int_val = {on},
+ },
+
+ //"Single ended"=0, "Differential"=1
+ {
+ .ctl_name = "IN1 Mode Control",
+ .str_val = "Differential",
+ },
+ //min=0,max=8, bypass=0=0db, 30db=3, 52db=8
+ {
+ .ctl_name = "IN1 Boost",
+ .int_val = {4},
+ },
+ //dBscale-min=-17.625dB,step=0.375dB,min=0,max=127
+ {
+ .ctl_name = "Mono ADC Capture Volume",
+ .int_val = {47, 47},
+ },
+ //dBscale-min=-65.625dB,step=0.375dB,min=0,max=175
+ {
+ .ctl_name = "Mono DAC Playback Volume",
+ .int_val = {175, 175},
+ },
+
+ //OPEN KEY TONE
+ {
+ .ctl_name = "DAC L2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC L1 Switch",
+ .int_val = {on},
+ },
+
+ //speaker normal
+ {
+ .ctl_name = "Mono DAC MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXL DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+
+ //speaker incall
+ {
+ .ctl_name = "SPK MIXL OUT MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXR OUT MIXR Switch",
+ .int_val = {off},
+ },
+
+ //headphone && headset normal
+ {
+ .ctl_name = "OUT MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+
+ //bt incall
+ {
+ .ctl_name = "DAC MIXL INF1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX OUTVOL L Switch",
+ .int_val = {off},
+ },
+
+ //close other mixer
+ {
+ .ctl_name = "OUT MIXL REC MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXR REC MIXR Switch",
+ .int_val = {off},
+ },
+
+ {
+ .ctl_name = "OUT Playback Switch",
+ .int_val = {on, on},
+ },
+/*
+ {
+ .ctl_name = "HP mute Switch",
+ .int_val = {on},
+ },
+*/
+};
+
+const struct config_control rt3224_headphone_ringtone_controls[] = {
+ //disable ASRC
+ {
+ .ctl_name = "ASRC Switch",
+ .str_val = "Disable",
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+/*
+ {
+ .ctl_name = "HP mute Switch",
+ .int_val = {off},
+ },
+*/
+ {
+ .ctl_name = "Modem Input Switch",
+ .int_val = {0},
+ },
+
+ //OPEN ROUTE
+ {
+ .ctl_name = "DAC L2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "DAC R2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "Mono dacr Mux",
+ .str_val = "TxDC_R",
+ },
+ {
+ .ctl_name = "DACR Select",
+ .str_val = "IF2_DAC",
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mono DAC MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "OUT MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPO MIX HPVOL Switch",
+ .int_val = {on},
+ },
+
+ //dBscale-min=-46.50dB,step=1.50dB,min=0,max=31
+ {
+ .ctl_name = "Headphone Playback Volume",
+ .int_val = {31, 31},
+ },
+ //dBscale-min=-65.625dB,step=0.375dB,min=0,max=175
+ {
+ .ctl_name = "Mono DAC Playback Volume",
+ .int_val = {175, 175},
+ },
+
+ //speaker normal
+ {
+ .ctl_name = "SPK MIXL DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+
+ //speaker incall
+ {
+ .ctl_name = "Stereo ADC MIXL ADC1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "DAC MIXL Stereo ADC Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXL OUT MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXR DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXR OUT MIXR Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC R1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC L1 Switch",
+ .int_val = {off},
+ },
+
+ //bt incall
+ {
+ .ctl_name = "DAC MIXL INF1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX OUTVOL L Switch",
+ .int_val = {off},
+ },
+
+ //close other mixer
+ {
+ .ctl_name = "OUT MIXL REC MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXR REC MIXR Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "DAC MIXR Stereo ADC Switch",
+ .int_val = {off},
+ },
+/*
+ {
+ .ctl_name = "HP mute Switch",
+ .int_val = {on},
+ },
+*/
+};
+
+const struct config_control rt3224_speaker_headphone_normal_controls[] = {
+ //disable ASRC
+ {
+ .ctl_name = "ASRC Switch",
+ .str_val = "Disable",
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+/*
+ {
+ .ctl_name = "HP mute Switch",
+ .int_val = {off},
+ },
+*/
+ //OPEN ROUTE
+ {
+ .ctl_name = "DAC L2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "DAC R2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "Mono dacr Mux",
+ .str_val = "TxDC_R",
+ },
+ {
+ .ctl_name = "DACR Select",
+ .str_val = "IF2_DAC",
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mono DAC MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "OUT MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPO MIX HPVOL Switch",
+ .int_val = {on},
+ },
+
+ //dBscale-min=-46.50dB,step=1.50dB,min=0,max=31
+ {
+ .ctl_name = "Headphone Playback Volume",
+ .int_val = {31, 31},
+ },
+ //dBscale-min=-65.625dB,step=0.375dB,min=0,max=175
+ {
+ .ctl_name = "Mono DAC Playback Volume",
+ .int_val = {175, 175},
+ },
+
+ {
+ .ctl_name = "SPK MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "SPK MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+
+ //dBscale-min=-46.50dB,step=1.50dB,min=0,max=31
+ {
+ .ctl_name = "Speaker Playback Volume",
+ .int_val = {31, 31},
+ },
+ //min=0,max=10
+ {
+ .ctl_name = "Class D SPK Ratio Control",
+ .int_val = {10},
+ },
+
+ //speaker incall
+ {
+ .ctl_name = "RECMIXL BST2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo ADC MIXL ADC1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "DAC MIXL Stereo ADC Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXL OUT MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXR DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXR OUT MIXR Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC R1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC L1 Switch",
+ .int_val = {off},
+ },
+
+ //bt incall
+ {
+ .ctl_name = "DAC MIXL INF1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX OUTVOL L Switch",
+ .int_val = {off},
+ },
+
+ //close other mixer
+ {
+ .ctl_name = "OUT MIXL REC MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXR REC MIXR Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "DAC MIXR Stereo ADC Switch",
+ .int_val = {off},
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {on, on},
+ },
+/*
+ {
+ .ctl_name = "HP mute Switch",
+ .int_val = {on},
+ },
+*/
+};
+
+const struct config_control rt3224_speaker_headphone_ringtone_controls[] = {
+ //disable ASRC
+ {
+ .ctl_name = "ASRC Switch",
+ .str_val = "Disable",
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+/*
+ {
+ .ctl_name = "HP mute Switch",
+ .int_val = {off},
+ },
+*/
+ //OPEN ROUTE
+ {
+ .ctl_name = "DAC L2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "DAC R2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "Mono dacr Mux",
+ .str_val = "TxDC_R",
+ },
+ {
+ .ctl_name = "DACR Select",
+ .str_val = "IF2_DAC",
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mono DAC MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "OUT MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPO MIX HPVOL Switch",
+ .int_val = {on},
+ },
+
+ //dBscale-min=-46.50dB,step=1.50dB,min=0,max=31
+ {
+ .ctl_name = "Headphone Playback Volume",
+ .int_val = {31, 31},
+ },
+ //dBscale-min=-65.625dB,step=0.375dB,min=0,max=175
+ {
+ .ctl_name = "Mono DAC Playback Volume",
+ .int_val = {175, 175},
+ },
+
+ {
+ .ctl_name = "SPK MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "SPK MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+
+ //dBscale-min=-46.50dB,step=1.50dB,min=0,max=31
+ {
+ .ctl_name = "Speaker Playback Volume",
+ .int_val = {31, 31},
+ },
+ //min=0,max=10
+ {
+ .ctl_name = "Class D SPK Ratio Control",
+ .int_val = {10},
+ },
+
+ //speaker incall
+ {
+ .ctl_name = "RECMIXL BST2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo ADC MIXL ADC1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "DAC MIXL Stereo ADC Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXL OUT MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXR DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "SPK MIXR OUT MIXR Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXR DAC R2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC R1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L2 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX DAC L1 Switch",
+ .int_val = {off},
+ },
+
+ //bt incall
+ {
+ .ctl_name = "DAC MIXL INF1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "Stereo DAC MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L1 Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "LOUT MIX OUTVOL L Switch",
+ .int_val = {off},
+ },
+
+ //close other mixer
+ {
+ .ctl_name = "OUT MIXL REC MIXL Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "OUT MIXR REC MIXR Switch",
+ .int_val = {off},
+ },
+ {
+ .ctl_name = "DAC MIXR Stereo ADC Switch",
+ .int_val = {off},
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {on, on},
+ },
+/*
+ {
+ .ctl_name = "HP mute Switch",
+ .int_val = {on},
+ },
+*/
+};
+
+const struct config_control rt3224_headphone_voip_controls[] = {
+ //disable ASRC
+ {
+ .ctl_name = "ASRC Switch",
+ .str_val = "Disable",
+ },
+
+ {
+ .ctl_name = "Speaker Playback Switch",
+ .int_val = {off, off},
+ },
+/*
+ {
+ .ctl_name = "HP mute Switch",
+ .int_val = {off},
+ },
+*/
+ {
+ .ctl_name = "OUT Playback Switch",
+ .int_val = {off, off},
+ },
+ {
+ .ctl_name = "Modem Input Switch",
+ .int_val = {0},
+ },
+
+ //OPEN ROUTE
+ {
+ .ctl_name = "DAC L2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "DAC R2 Mux",
+ .str_val = "IF2",
+ },
+ {
+ .ctl_name = "Mono dacr Mux",
+ .str_val = "TxDC_R",
+ },
+ {
+ .ctl_name = "DACR Select",
+ .str_val = "IF2_DAC",
+ },
+ {
+ .ctl_name = "Mono DAC MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "Mono DAC MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "OUT MIXL DAC L2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "OUT MIXR DAC R2 Switch",
+ .int_val = {on},
+ },
+ {
+ .ctl_name = "HPO MIX HPVOL Switch",
+ .int_val = {on},
+ },
+
+ //dBscale-min=-46.50dB,step=1.50dB,min=0,max=31
+ {
+ .ctl_name = "Headphone Playback Volume",
+ .int_val = {31, 31},
+ },
+ //dBscale-min=-65.625dB,step=0.375dB,min=0,ma