Merge "hal: add support for source tracking feature"
diff --git a/Android.mk b/Android.mk
index 36a85f9..6e129a1 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,4 +1,4 @@
-ifneq ($(filter mpq8092 msm8960 msm8226 msm8x26 msm8610 msm8974 msm8x74 apq8084 msm8916 msm8994 msm8992 msm8909 thulium,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter mpq8092 msm8960 msm8226 msm8x26 msm8610 msm8974 msm8x74 apq8084 msm8916 msm8994 msm8992 msm8909 msm8996 msm8952,$(TARGET_BOARD_PLATFORM)),)
MY_LOCAL_PATH := $(call my-dir)
diff --git a/hal/Android.mk b/hal/Android.mk
index 4e1364b..99b6b39 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -8,7 +8,7 @@
AUDIO_PLATFORM := $(TARGET_BOARD_PLATFORM)
-ifneq ($(filter msm8974 msm8226 msm8610 apq8084 msm8994 msm8992 thulium,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter msm8974 msm8226 msm8610 apq8084 msm8994 msm8992 msm8996,$(TARGET_BOARD_PLATFORM)),)
# B-family platform uses msm8974 code base
AUDIO_PLATFORM = msm8974
MULTIPLE_HW_VARIANTS_ENABLED := true
@@ -27,12 +27,12 @@
ifneq ($(filter msm8992,$(TARGET_BOARD_PLATFORM)),)
LOCAL_CFLAGS := -DPLATFORM_MSM8994
endif
-ifneq ($(filter thulium,$(TARGET_BOARD_PLATFORM)),)
- LOCAL_CFLAGS := -DPLATFORM_THULIUM
+ifneq ($(filter msm8996,$(TARGET_BOARD_PLATFORM)),)
+ LOCAL_CFLAGS := -DPLATFORM_MSM8996
endif
endif
-ifneq ($(filter msm8916 msm8909,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter msm8916 msm8909 msm8952,$(TARGET_BOARD_PLATFORM)),)
AUDIO_PLATFORM = msm8916
MULTIPLE_HW_VARIANTS_ENABLED := true
LOCAL_CFLAGS := -DPLATFORM_MSM8916
@@ -52,10 +52,14 @@
LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
-ifneq ($(filter msm8994 msm8992,$(TARGET_BOARD_PLATFORM)),)
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HDMI_EDID)),true)
LOCAL_SRC_FILES += edid.c
endif
+ifeq ($(strip $(AUDIO_USE_LL_AS_PRIMARY_OUTPUT)),true)
+ LOCAL_CFLAGS += -DUSE_LL_AS_PRIMARY_OUTPUT
+endif
+
ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PCM_OFFLOAD)),true)
LOCAL_CFLAGS += -DPCM_OFFLOAD_ENABLED
endif
diff --git a/hal/audio_extn/AudioUtil.c b/hal/audio_extn/AudioUtil.c
deleted file mode 100644
index 45bf55f..0000000
--- a/hal/audio_extn/AudioUtil.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*Copyright (C) 2014 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.
-* This file was modified by DTS, Inc. The portions of the
-* code modified by DTS, Inc are copyrighted and
-* licensed separately, as follows:
-*
-* (C) 2014 DTS, Inc.
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-#define LOG_TAG "AudioUtil"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-#include <stdlib.h>
-
-#include <cutils/properties.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sound/devdep_params.h>
-#include <sound/asound.h>
-#include "AudioUtil.h"
-
-#define ROUTE_PATH "/data/data/dts/route"
-#define DEVICE_NODE "/dev/snd/hwC0D3"
-
-static int32_t mDevices = 0;
-static int32_t mCurrDevice = 0;
-
-void create_route_node(void)
-{
- char prop[PROPERTY_VALUE_MAX] = "true";
- int fd;
- property_get("use.dts_eagle", prop, "0");
- if (!strncmp("true", prop, sizeof("true")) || atoi(prop)) {
- ALOGV("create_route_node");
- if ((fd=open(ROUTE_PATH, O_RDONLY)) < 0) {
- ALOGV("No File exisit");
- } else {
- ALOGV("A file with the same name exist. Remove it before creating it");
- close(fd);
- remove(ROUTE_PATH);
- }
- if ((fd=creat(ROUTE_PATH, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) {
- ALOGE("opening route node failed returned");
- return;
- }
- chmod(ROUTE_PATH, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH);
- ALOGV("opening route node successful");
- close(fd);
- }
-}
-
-void notify_route_node(int active_device, int devices)
-{
- char prop[PROPERTY_VALUE_MAX] = "true";
- char buf[1024];
- int fd;
- if ((mCurrDevice == active_device) &&
- (mDevices == devices)) {
- ALOGV("nothing to update to route node");
- return;
- }
- mDevices = devices;
- mCurrDevice = active_device;
- property_get("use.dts_eagle", prop, "0");
- if (!strncmp("true", prop, sizeof("true")) || atoi(prop)) {
- ALOGV("notify active device : %d all_devices : %d", active_device, devices);
- if ((fd=open(ROUTE_PATH, O_TRUNC|O_WRONLY)) < 0) {
- ALOGV("Write device to route node failed");
- } else {
- ALOGV("Write device to route node successful");
- snprintf(buf, sizeof(buf), "device=%d;all_devices=%d", active_device, devices);
- int n = write(fd, buf, strlen(buf));
- ALOGV("number of bytes written: %d", n);
- close(fd);
- }
- int eaglefd = open(DEVICE_NODE, O_RDWR);
- int32_t params[2] = {active_device, 1 /*is primary device*/};
- if (eaglefd > 0) {
- if(ioctl(eaglefd, DTS_EAGLE_IOCTL_SET_ACTIVE_DEVICE, ¶ms) < 0) {
- ALOGE("DTS_EAGLE (%s): error sending primary device\n", __func__);
- }
- ALOGD("DTS_EAGLE (%s): sent primary device\n", __func__);
- close(eaglefd);
- } else {
- ALOGE("DTS_EAGLE (%s): error opening eagle\n", __func__);
- }
- }
-}
-
-void remove_route_node(void)
-{
- char prop[PROPERTY_VALUE_MAX] = "true";
- int fd;
- property_get("use.dts_eagle", prop, "0");
- if (!strncmp("true", prop, sizeof("true")) || atoi(prop)) {
- ALOGV("remove_route_node");
- if ((fd=open(ROUTE_PATH, O_RDONLY)) < 0) {
- ALOGV("open route node failed");
- } else {
- ALOGV("open route node successful");
- ALOGV("Remove the file");
- close(fd);
- remove(ROUTE_PATH);
- }
- }
-}
diff --git a/hal/audio_extn/AudioUtil.h b/hal/audio_extn/AudioUtil.h
deleted file mode 100644
index 02789cc..0000000
--- a/hal/audio_extn/AudioUtil.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*Copyright (C) 2014 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.
-* This file was modified by DTS, Inc. The portions of the
-* code modified by DTS, Inc are copyrighted and
-* licensed separately, as follows:
-*
-* (C) 2014 DTS, Inc.
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-#ifndef AUDIO_UTIL_H_
-#define AUDIO_UTIL_H_
-
-#ifndef DTS_EAGLE
-#define create_route_node() (0)
-#define notify_route_node(active_device, devices) (0)
-#define remove_route_node() (0)
-#else
-void create_route_node(void);
-void notify_route_node(int active_device, int devices);
-void remove_route_node(void);
-#endif
-
-#endif //AUDIO_UTIL_H_
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index fad793d..688e265 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -343,7 +343,7 @@
int channel_count)
{
struct mixer_ctl *ctl;
- const char *mixer_ctl_name = "Playback Channel Map";
+ const char *mixer_ctl_name = "Playback Device Channel Map";
int set_values[8] = {0};
int ret;
ALOGV("%s channel_count:%d",__func__, channel_count);
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 643c593..71f2285 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -275,7 +275,7 @@
#ifndef DTS_EAGLE
#define audio_extn_dts_eagle_set_parameters(adev, parms) (0)
#define audio_extn_dts_eagle_get_parameters(adev, query, reply) (0)
-#define audio_extn_dts_eagle_fade(adev, fade_in) (0)
+#define audio_extn_dts_eagle_fade(adev, fade_in, out) (0)
#define audio_extn_dts_create_state_notifier_node(stream_out) (0)
#define audio_extn_dts_notify_playback_state(stream_out, has_video, sample_rate, \
channels, is_playing) (0)
@@ -286,7 +286,7 @@
struct str_parms *parms);
int audio_extn_dts_eagle_get_parameters(const struct audio_device *adev,
struct str_parms *query, struct str_parms *reply);
-int audio_extn_dts_eagle_fade(const struct audio_device *adev, bool fade_in);
+int audio_extn_dts_eagle_fade(const struct audio_device *adev, bool fade_in, const struct stream_out *out);
void audio_extn_dts_create_state_notifier_node(int stream_out);
void audio_extn_dts_notify_playback_state(int stream_out, int has_video, int sample_rate,
int channels, int is_playing);
diff --git a/hal/audio_extn/dev_arbi.c b/hal/audio_extn/dev_arbi.c
index d3c01c5..d7ab5ff 100644
--- a/hal/audio_extn/dev_arbi.c
+++ b/hal/audio_extn/dev_arbi.c
@@ -128,7 +128,13 @@
{
static snd_aud_dev_mapping_t snd_aud_dev_map[] = {
{SND_DEVICE_OUT_HANDSET, AUDIO_DEVICE_OUT_EARPIECE},
- {SND_DEVICE_OUT_VOICE_HANDSET, AUDIO_DEVICE_OUT_EARPIECE}
+ {SND_DEVICE_OUT_VOICE_HANDSET, AUDIO_DEVICE_OUT_EARPIECE},
+ {SND_DEVICE_OUT_SPEAKER, AUDIO_DEVICE_OUT_SPEAKER},
+ {SND_DEVICE_OUT_VOICE_SPEAKER, AUDIO_DEVICE_OUT_SPEAKER},
+ {SND_DEVICE_OUT_HEADPHONES, AUDIO_DEVICE_OUT_WIRED_HEADPHONE},
+ {SND_DEVICE_OUT_VOICE_HEADPHONES, AUDIO_DEVICE_OUT_WIRED_HEADPHONE},
+ {SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+ AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_WIRED_HEADPHONE}
};
audio_devices_t aud_device = AUDIO_DEVICE_NONE;
diff --git a/hal/audio_extn/dts_eagle.c b/hal/audio_extn/dts_eagle.c
index b4bbb9f..52d7abb 100644
--- a/hal/audio_extn/dts_eagle.c
+++ b/hal/audio_extn/dts_eagle.c
@@ -36,8 +36,8 @@
#ifdef DTS_EAGLE
#define AUDIO_PARAMETER_KEY_DTS_EAGLE "DTS_EAGLE"
-#define STATE_NOTIFY_FILE "/data/data/dts/stream"
-#define FADE_NOTIFY_FILE "/data/data/dts/fade"
+#define STATE_NOTIFY_FILE "/data/misc/dts/stream"
+#define FADE_NOTIFY_FILE "/data/misc/dts/fade"
#define DTS_EAGLE_KEY "DTS_EAGLE"
#define DEVICE_NODE "/dev/snd/hwC0D3"
#define MAX_LENGTH_OF_INTEGER_IN_STRING 13
@@ -88,22 +88,31 @@
return -EINVAL;
}
-static int do_DTS_Eagle_params(const struct audio_device *adev, struct dts_eagle_param_desc_alsa *t, bool get) {
+static int do_DTS_Eagle_params(const struct audio_device *adev, struct dts_eagle_param_desc_alsa *t, bool get, const struct stream_out *out) {
struct listnode *node;
struct audio_usecase *usecase;
- int ret = 0, sent = 0;
+ int ret = 0, sent = 0, tret = 0;
ALOGV("DTS_EAGLE_HAL (%s): enter", __func__);
- list_for_each(node, &adev->usecase_list) {
- usecase = node_to_item(node, struct audio_usecase, list);
- /* set/get eagle params for offload usecases only */
- if ((usecase->type == PCM_PLAYBACK) && is_offload_usecase(usecase->id)) {
- int tret = do_DTS_Eagle_params_stream(usecase->stream.out, t, get);
- if (tret < 0)
- ret = tret;
- else
- sent = 1;
+ if (out) {
+ /* if valid out stream is given, then send params to this stream only */
+ tret = do_DTS_Eagle_params_stream(out, t, get);
+ if (tret < 0)
+ ret = tret;
+ else
+ sent = 1;
+ } else {
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ /* set/get eagle params for offload usecases only */
+ if ((usecase->type == PCM_PLAYBACK) && is_offload_usecase(usecase->id)) {
+ tret = do_DTS_Eagle_params_stream(usecase->stream.out, t, get);
+ if (tret < 0)
+ ret = tret;
+ else
+ sent = 1;
+ }
}
}
@@ -136,13 +145,21 @@
}
static void fade_node(bool need_data) {
- int fd = creat(FADE_NOTIFY_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH), n = 0;
- char *str = need_data ? "need" : "have";
- if (fd < 0) {
- ALOGE("DTS_EAGLE_HAL (%s): opening fade notifier node failed", __func__);
+ char prop[PROPERTY_VALUE_MAX];
+ property_get("use.dts_eagle", prop, "0");
+ if (strncmp("true", prop, sizeof("true")))
return;
+ int fd, n = 0;
+ if ((fd = open(FADE_NOTIFY_FILE, O_TRUNC|O_WRONLY)) < 0) {
+ ALOGV("No fade node, create one");
+ fd = creat(FADE_NOTIFY_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ if (fd < 0) {
+ ALOGE("DTS_EAGLE_HAL (%s): Creating fade notifier node failed", __func__);
+ return;
+ }
+ chmod(FADE_NOTIFY_FILE, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH);
}
- chmod(FADE_NOTIFY_FILE, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH);
+ char *str = need_data ? "need" : "have";
n = write(fd, str, strlen(str));
close(fd);
if (n > 0)
@@ -151,7 +168,7 @@
ALOGE("DTS_EAGLE_HAL (%s): error writing to fade notifier node", __func__);
}
-int audio_extn_dts_eagle_fade(const struct audio_device *adev, bool fade_in) {
+int audio_extn_dts_eagle_fade(const struct audio_device *adev, bool fade_in, const struct stream_out *out) {
char prop[PROPERTY_VALUE_MAX];
ALOGV("DTS_EAGLE_HAL (%s): enter with fade %s requested", __func__, fade_in ? "in" : "out");
@@ -165,10 +182,10 @@
if (fade_in) {
if (fade_in_data)
- return do_DTS_Eagle_params(adev, fade_in_data, false);
+ return do_DTS_Eagle_params(adev, fade_in_data, false, out);
} else {
if (fade_out_data)
- return do_DTS_Eagle_params(adev, fade_out_data, false);
+ return do_DTS_Eagle_params(adev, fade_out_data, false, out);
}
return 0;
}
@@ -285,7 +302,7 @@
ALOGD("DTS_EAGLE_HAL (%s): id: 0x%X, size: %d, offset: %d, device: %d", __func__,
(*t)->d.id, (*t)->d.size, (*t)->d.offset, (*t)->d.device);
if (!fade_in) {
- ret = do_DTS_Eagle_params(adev, *t, false);
+ ret = do_DTS_Eagle_params(adev, *t, false, NULL);
if (ret < 0)
ALOGE("DTS_EAGLE_HAL (%s): failed setting params in kernel with error %i", __func__, ret);
}
@@ -301,7 +318,6 @@
if (fade_in > 0 && fade_in_data && fade_out_data)
fade_node(false);
}
-
ALOGV("DTS_EAGLE_HAL (%s): exit", __func__);
}
@@ -367,7 +383,7 @@
ALOGE("%s: requested data too large", __func__);
return -1;
}
- ret = do_DTS_Eagle_params(adev, t, true);
+ ret = do_DTS_Eagle_params(adev, t, true, NULL);
if (ret >= 0) {
data = (int*)(params + sizeof(struct dts_eagle_param_desc_alsa));
for (i = 0; i < count; i++)
@@ -427,10 +443,9 @@
chmod(path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH);
ALOGV("DTS_EAGLE_NODE_STREAM (%s): opening state notifier node successful", __func__);
close(fd);
+ if (!fade_in_data || !fade_out_data)
+ fade_node(true);
}
-
- if (!fade_in_data || !fade_out_data)
- fade_node(true);
}
void audio_extn_dts_notify_playback_state(int stream_out, int has_video, int sample_rate,
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 24852b6..369cf12 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -75,13 +75,19 @@
#define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4
/* ToDo: Check and update a proper value in msec */
-#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 96
+#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 50
#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000
#define PROXY_OPEN_RETRY_COUNT 100
#define PROXY_OPEN_WAIT_TIME 20
+#ifdef USE_LL_AS_PRIMARY_OUTPUT
+#define USECASE_AUDIO_PLAYBACK_PRIMARY USECASE_AUDIO_PLAYBACK_LOW_LATENCY
+#define PCM_CONFIG_AUDIO_PLAYBACK_PRIMARY pcm_config_low_latency
+#else
#define USECASE_AUDIO_PLAYBACK_PRIMARY USECASE_AUDIO_PLAYBACK_DEEP_BUFFER
+#define PCM_CONFIG_AUDIO_PLAYBACK_PRIMARY pcm_config_deep_buffer
+#endif
static unsigned int configured_low_latency_capture_period_size =
LOW_LATENCY_CAPTURE_PERIOD_SIZE;
@@ -279,7 +285,9 @@
format == AUDIO_FORMAT_AAC_HE_V2 ||
format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD ||
format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD ||
- format == AUDIO_FORMAT_FLAC)
+ format == AUDIO_FORMAT_FLAC ||
+ format == AUDIO_FORMAT_WMA ||
+ format == AUDIO_FORMAT_WMA_PRO)
return true;
return false;
@@ -302,6 +310,12 @@
case AUDIO_FORMAT_FLAC:
id = SND_AUDIOCODEC_FLAC;
break;
+ case AUDIO_FORMAT_WMA:
+ id = SND_AUDIOCODEC_WMA;
+ break;
+ case AUDIO_FORMAT_WMA_PRO:
+ id = SND_AUDIOCODEC_WMA_PRO;
+ break;
default:
ALOGE("%s: Unsupported audio format :%x", __func__, format);
}
@@ -465,8 +479,10 @@
adev->snd_dev_ref_cnt[snd_device]--;
return -EINVAL;
}
+ audio_extn_dev_arbi_acquire(snd_device);
if (audio_extn_spkr_prot_start_processing(snd_device)) {
ALOGE("%s: spkr_start_processing failed", __func__);
+ audio_extn_dev_arbi_release(snd_device);
return -EINVAL;
}
} else {
@@ -532,9 +548,9 @@
audio_extn_spkr_prot_stop_processing(snd_device);
} else {
audio_route_reset_and_update_path(adev->audio_route, device_name);
- audio_extn_dev_arbi_release(snd_device);
}
+ audio_extn_dev_arbi_release(snd_device);
audio_extn_sound_trigger_update_device_status(snd_device,
ST_EVENT_SND_DEVICE_FREE);
audio_extn_listen_update_device_status(snd_device,
@@ -652,6 +668,7 @@
if (usecase->type != PCM_PLAYBACK &&
usecase != uc_info &&
usecase->in_snd_device != snd_device &&
+ (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) &&
(usecase->id != USECASE_AUDIO_SPKR_CALIB_TX)) {
ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
__func__, use_case_table[usecase->id],
@@ -1547,6 +1564,14 @@
if (out->offload_callback)
compress_nonblock(out->compr, out->non_blocking);
+ /* Since small bufs uses blocking writes, a write will be blocked
+ for the default max poll time (20s) in the event of an SSR.
+ Reduce the poll time to observe and deal with SSR faster.
+ */
+ if (out->use_small_bufs) {
+ compress_set_max_poll_wait(out->compr, 1000);
+ }
+
audio_extn_dts_create_state_notifier_node(out->usecase);
audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
popcount(out->channel_mask),
@@ -1781,6 +1806,52 @@
}
}
+ if (out->format == AUDIO_FORMAT_WMA || out->format == AUDIO_FORMAT_WMA_PRO) {
+ ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_FORMAT_TAG, value, sizeof(value));
+ if (ret >= 0) {
+ out->compr_config.codec->format = atoi(value);
+ out->send_new_metadata = 1;
+ }
+ ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_BLOCK_ALIGN, value, sizeof(value));
+ if (ret >= 0) {
+ out->compr_config.codec->options.wma.super_block_align = atoi(value);
+ out->send_new_metadata = 1;
+ }
+ ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_BIT_PER_SAMPLE, value, sizeof(value));
+ if (ret >= 0) {
+ out->compr_config.codec->options.wma.bits_per_sample = atoi(value);
+ out->send_new_metadata = 1;
+ }
+ ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_CHANNEL_MASK, value, sizeof(value));
+ if (ret >= 0) {
+ out->compr_config.codec->options.wma.channelmask = atoi(value);
+ out->send_new_metadata = 1;
+ }
+ ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION, value, sizeof(value));
+ if (ret >= 0) {
+ out->compr_config.codec->options.wma.encodeopt = atoi(value);
+ out->send_new_metadata = 1;
+ }
+ ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION1, value, sizeof(value));
+ if (ret >= 0) {
+ out->compr_config.codec->options.wma.encodeopt1 = atoi(value);
+ out->send_new_metadata = 1;
+ }
+ ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION2, value, sizeof(value));
+ if (ret >= 0) {
+ out->compr_config.codec->options.wma.encodeopt2 = atoi(value);
+ out->send_new_metadata = 1;
+ }
+ ALOGV("WMA params: fmt %x, balgn %x, sr %d, chmsk %x, encop %x, op1 %x, op2 %x",
+ out->compr_config.codec->format,
+ out->compr_config.codec->options.wma.super_block_align,
+ out->compr_config.codec->options.wma.bits_per_sample,
+ out->compr_config.codec->options.wma.channelmask,
+ out->compr_config.codec->options.wma.encodeopt,
+ out->compr_config.codec->options.wma.encodeopt1,
+ out->compr_config.codec->options.wma.encodeopt2);
+ }
+
ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_SAMPLE_RATE, value, sizeof(value));
if(ret >= 0)
is_meta_data_params = true;
@@ -1957,7 +2028,7 @@
} else {
voice_extn_out_get_parameters(out, query, reply);
str = str_parms_to_str(reply);
- if (!strncmp(str, "", sizeof(""))) {
+ if (str && !strncmp(str, "", sizeof(""))) {
free(str);
str = strdup(keys);
}
@@ -1996,13 +2067,7 @@
uint32_t latency = 0;
if (is_offload_usecase(out->usecase)) {
- if (out->use_small_bufs == true)
- latency = ((out->compr_config.fragments *
- out->compr_config.fragment_size * 1000) /
- (out->sample_rate * out->compr_config.codec->ch_in *
- audio_bytes_per_sample(out->format)));
- else
- latency = COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
+ latency = COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
} else {
latency = (out->config.period_count * out->config.period_size * 1000) /
(out->config.rate);
@@ -2066,6 +2131,11 @@
pthread_mutex_lock(&out->lock);
if (SND_CARD_STATE_OFFLINE == snd_scard_state) {
+ // increase written size during SSR to avoid mismatch
+ // with the written frames count in AF
+ if (!is_offload_usecase(out->usecase))
+ out->written += bytes / (out->config.channels * sizeof(short));
+
if (out->pcm) {
ALOGD(" %s: sound card is not active/SSR state", __func__);
ret= -EIO;
@@ -2094,7 +2164,7 @@
}
if (is_offload_usecase(out->usecase)) {
- ALOGD("copl(%p): writing buffer (%zu bytes) to compress device", out, bytes);
+ ALOGVV("copl(%p): writing buffer (%zu bytes) to compress device", out, bytes);
if (out->send_new_metadata) {
ALOGD("copl(%p):send new gapless metadata", out);
compress_set_gapless_metadata(out->compr, &out->gapless_mdata);
@@ -2117,6 +2187,7 @@
}
if (!out->playback_started && ret >= 0) {
compress_start(out->compr);
+ audio_extn_dts_eagle_fade(adev, true, out);
out->playback_started = 1;
out->offload_state = OFFLOAD_STATE_PLAYING;
@@ -2308,7 +2379,7 @@
out->offload_state = OFFLOAD_STATE_PAUSED;
- audio_extn_dts_eagle_fade(adev, false);
+ audio_extn_dts_eagle_fade(adev, false, out);
audio_extn_dts_notify_playback_state(out->usecase, 0,
out->sample_rate, popcount(out->channel_mask),
0);
@@ -2336,7 +2407,7 @@
out->offload_state = OFFLOAD_STATE_PLAYING;
- audio_extn_dts_eagle_fade(adev, true);
+ audio_extn_dts_eagle_fade(adev, true, out);
audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
popcount(out->channel_mask), 1);
}
@@ -2937,11 +3008,16 @@
out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
out->config = pcm_config_low_latency;
out->sample_rate = out->config.rate;
+ } else if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
+ format = AUDIO_FORMAT_PCM_16_BIT;
+ out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
+ out->config = pcm_config_deep_buffer;
+ out->sample_rate = out->config.rate;
} else {
/* primary path is the default path selected if no other outputs are available/suitable */
format = AUDIO_FORMAT_PCM_16_BIT;
out->usecase = USECASE_AUDIO_PLAYBACK_PRIMARY;
- out->config = pcm_config_deep_buffer;
+ out->config = PCM_CONFIG_AUDIO_PLAYBACK_PRIMARY;
out->sample_rate = out->config.rate;
}
@@ -3063,14 +3139,13 @@
static void close_compress_sessions(struct audio_device *adev)
{
- struct stream_out *out = NULL;
- struct listnode *node = NULL;
- struct listnode *tmp = NULL;
- struct audio_usecase *usecase = NULL;
+ struct stream_out *out;
+ struct listnode *node;
+ struct audio_usecase *usecase;
pthread_mutex_lock(&adev->lock);
- list_for_each_safe(node, tmp, &adev->usecase_list) {
+ list_for_each(node, &adev->usecase_list) {
usecase = node_to_item(node, struct audio_usecase, list);
- if (is_offload_usecase(usecase->id)) {
+ if (usecase && is_offload_usecase(usecase->id)) {
if (usecase && usecase->stream.out) {
ALOGI(" %s closing compress session %d on OFFLINE state", __func__, usecase->id);
out = usecase->stream.out;
@@ -3345,7 +3420,7 @@
struct audio_stream_in **stream_in,
audio_input_flags_t flags __unused,
const char *address __unused,
- audio_source_t source __unused)
+ audio_source_t source)
{
struct audio_device *adev = (struct audio_device *)dev;
struct stream_in *in;
@@ -3365,8 +3440,8 @@
}
ALOGD("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x)\
- stream_handle(%p) io_handle(%d)",__func__, config->sample_rate, config->channel_mask,
- devices, &in->stream, handle);
+ stream_handle(%p) io_handle(%d) source(%d)",__func__, config->sample_rate, config->channel_mask,
+ devices, &in->stream, handle, source);
pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL);
@@ -3387,7 +3462,7 @@
in->stream.get_input_frames_lost = in_get_input_frames_lost;
in->device = devices;
- in->source = AUDIO_SOURCE_DEFAULT;
+ in->source = source;
in->dev = adev;
in->standby = 1;
in->channel_mask = config->channel_mask;
@@ -3453,6 +3528,13 @@
channel_count,
is_low_latency);
in->config.period_size = buffer_size / frame_size;
+ if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) &&
+ (in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
+ (voice_extn_compress_voip_is_format_supported(in->format)) &&
+ (in->config.rate == 8000 || in->config.rate == 16000) &&
+ (audio_channel_count_from_in_mask(in->channel_mask) == 1)) {
+ voice_extn_compress_voip_open_input_stream(in);
+ }
}
/* This stream could be for sound trigger lab,
@@ -3492,7 +3574,7 @@
} else
in_standby(&stream->common);
- if (audio_extn_ssr_get_enabled() &&
+ if (audio_extn_ssr_get_enabled() &&
(audio_channel_count_from_in_mask(in->channel_mask) == 6)) {
audio_extn_ssr_deinit();
}
diff --git a/hal/msm8916/hw_info.c b/hal/msm8916/hw_info.c
index 689e834..5fb5606 100644
--- a/hal/msm8916/hw_info.c
+++ b/hal/msm8916/hw_info.c
@@ -216,8 +216,26 @@
hw_info->snd_devices = NULL;
hw_info->num_snd_devices = 0;
strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "msm8952-snd-card")) {
+ strlcpy(hw_info->type, "", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8952", sizeof(hw_info->name));
+ hw_info->snd_devices = NULL;
+ hw_info->num_snd_devices = 0;
+ strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "msm8952-snd-card-mtp")) {
+ strlcpy(hw_info->type, "", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8952", sizeof(hw_info->name));
+ hw_info->snd_devices = NULL;
+ hw_info->num_snd_devices = 0;
+ strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+ } else if (!strcmp(snd_card_name, "msm8952-tomtom-snd-card")) {
+ strlcpy(hw_info->type, "", sizeof(hw_info->type));
+ strlcpy(hw_info->name, "msm8952", sizeof(hw_info->name));
+ hw_info->snd_devices = NULL;
+ hw_info->num_snd_devices = 0;
+ strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
} else {
- ALOGW("%s: Not an 8x16/8939/8909 device", __func__);
+ ALOGW("%s: Not an 8x16/8939/8909/8952 device", __func__);
}
}
@@ -232,7 +250,7 @@
}
if (strstr(snd_card_name, "msm8x16") || strstr(snd_card_name, "msm8939") ||
- strstr(snd_card_name, "msm8909")) {
+ strstr(snd_card_name, "msm8909") || strstr(snd_card_name, "msm8952")) {
ALOGV("8x16 - variant soundcard");
update_hardware_info_8x16(hw_info, snd_card_name);
} else {
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index c23ee09..1ebff09 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -33,7 +33,10 @@
#include "platform.h"
#include "audio_extn.h"
#include "voice_extn.h"
+#include "edid.h"
+#include "sound/compress_params.h"
#include "sound/msmcal-hwdep.h"
+#include <dirent.h>
#define SOUND_TRIGGER_DEVICE_HANDSET_MONO_LOW_POWER_ACDB_ID (100)
#define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
@@ -49,9 +52,12 @@
#define MIXER_XML_PATH_SKUL "/system/etc/mixer_paths_skul.xml"
#define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml"
#define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml"
+#define MIXER_XML_PATH_I2S "/system/etc/mixer_paths_i2s.xml"
#define MIXER_XML_PATH_WCD9306 "/system/etc/mixer_paths_wcd9306.xml"
#define MIXER_XML_PATH_WCD9330 "/system/etc/mixer_paths_wcd9330.xml"
#define PLATFORM_INFO_XML_PATH "/system/etc/audio_platform_info.xml"
+#define PLATFORM_INFO_XML_PATH_I2S "/system/etc/audio_platform_info_i2s.xml"
+
#define LIB_ACDB_LOADER "libacdbloader.so"
#define AUDIO_DATA_BLOCK_MIXER_CTL "HDMI EDID"
#define CVD_VERSION_MIXER_CTL "CVD Version"
@@ -61,15 +67,23 @@
#define COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING (2 * 1024)
#define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024)
/* Used in calculating fragment size for pcm offload */
-#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV 2000 /* 2 secs */
-#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING 100 /* 100 millisecs */
+#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV 1000 /* 1 sec */
+#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING 80 /* 80 millisecs */
+#define PCM_OFFLOAD_BUFFER_DURATION_FOR_SMALL_BUFFERS 20 /* 20 millisecs */
+#define PCM_OFFLOAD_BUFFER_DURATION_MAX 1200 /* 1200 millisecs */
/* MAX PCM fragment size cannot be increased further due
* to flinger's cblk size of 1mb,and it has to be a multiple of
* 24 - lcm of channels supported by DSP
*/
#define MAX_PCM_OFFLOAD_FRAGMENT_SIZE (240 * 1024)
-#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE (32 * 1024)
+#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE (4 * 1024)
+
+/*
+ * Offload buffer size for compress passthrough
+ */
+#define MIN_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE (2 * 1024)
+#define MAX_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE (8 * 1024)
#define ALIGN( num, to ) (((num) + (to-1)) & (~(to-1)))
/*
@@ -97,13 +111,23 @@
#define SAMPLE_RATE_8KHZ 8000
#define SAMPLE_RATE_16KHZ 16000
+#define MAX_SET_CAL_BYTE_SIZE 65536
+
#define AUDIO_PARAMETER_KEY_FLUENCE_TYPE "fluence"
#define AUDIO_PARAMETER_KEY_SLOWTALK "st_enable"
#define AUDIO_PARAMETER_KEY_HD_VOICE "hd_voice"
#define AUDIO_PARAMETER_KEY_VOLUME_BOOST "volume_boost"
+#define AUDIO_PARAMETER_KEY_AUD_CALDATA "cal_data"
+#define AUDIO_PARAMETER_KEY_AUD_CALRESULT "cal_result"
+
+
+/* Query external audio device connection status */
+#define AUDIO_PARAMETER_KEY_EXT_AUDIO_DEVICE "ext_audio_device"
+
+#define EVENT_EXTERNAL_SPK_1 "qc_ext_spk_1"
+#define EVENT_EXTERNAL_SPK_2 "qc_ext_spk_2"
+#define EVENT_EXTERNAL_MIC "qc_ext_mic"
#define MAX_CAL_NAME 20
-#define APP_TYPE_SYSTEM_SOUNDS 0x00011131
-#define APP_TYPE_GENERAL_RECORDING 0x00011132
char cal_name_info[WCD9XXX_MAX_CAL][MAX_CAL_NAME] = {
[WCD9XXX_ANC_CAL] = "anc_cal",
@@ -124,15 +148,30 @@
int length;
};
+typedef struct acdb_audio_cal_cfg {
+ uint32_t persist;
+ uint32_t snd_dev_id;
+ audio_devices_t dev_id;
+ int32_t acdb_dev_id;
+ uint32_t app_type;
+ uint32_t topo_id;
+ uint32_t sampling_rate;
+ uint32_t cal_type;
+ uint32_t module_id;
+ uint32_t param_id;
+} acdb_audio_cal_cfg_t;
+
/* Audio calibration related functions */
typedef void (*acdb_deallocate_t)();
-typedef int (*acdb_init_t)(char *, char *, int);
-typedef void (*acdb_send_audio_cal_t)(int, int, int, int);
+typedef int (*acdb_init_t)(const char *, char *, int);
+typedef void (*acdb_send_audio_cal_t)(int, int, int , int);
typedef void (*acdb_send_voice_cal_t)(int, int);
typedef int (*acdb_reload_vocvoltable_t)(int);
typedef int (*acdb_get_default_app_type_t)(void);
typedef int (*acdb_loader_get_calibration_t)(char *attr, int size, void *data);
acdb_loader_get_calibration_t acdb_loader_get_calibration;
+typedef int (*acdb_set_audio_cal_t) (void *, void *, uint32_t);
+typedef int (*acdb_get_audio_cal_t) (void *, void *, uint32_t*);
struct platform_data {
struct audio_device *adev;
@@ -140,18 +179,24 @@
bool fluence_in_voice_call;
bool fluence_in_voice_rec;
bool fluence_in_audio_rec;
+ bool external_spk_1;
+ bool external_spk_2;
+ bool external_mic;
int fluence_type;
char fluence_cap[PROPERTY_VALUE_MAX];
int fluence_mode;
bool slowtalk;
bool hd_voice;
bool ec_ref_enabled;
+ bool is_wsa_speaker;
/* Audio calibration related functions */
void *acdb_handle;
int voice_feature_set;
acdb_init_t acdb_init;
acdb_deallocate_t acdb_deallocate;
acdb_send_audio_cal_t acdb_send_audio_cal;
+ acdb_set_audio_cal_t acdb_set_audio_cal;
+ acdb_get_audio_cal_t acdb_get_audio_cal;
acdb_send_voice_cal_t acdb_send_voice_cal;
acdb_reload_vocvoltable_t acdb_reload_vocvoltable;
acdb_get_default_app_type_t acdb_get_default_app_type;
@@ -160,9 +205,11 @@
#endif
void *hw_info;
struct csd_data *csd;
+ void *edid_info;
+ bool edid_valid;
};
-static const int pcm_device_table[AUDIO_USECASE_MAX][2] = {
+int pcm_device_table[AUDIO_USECASE_MAX][2] = {
[USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {DEEP_BUFFER_PCM_DEVICE,
DEEP_BUFFER_PCM_DEVICE},
[USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
@@ -171,6 +218,24 @@
MULTIMEDIA2_PCM_DEVICE},
[USECASE_AUDIO_PLAYBACK_OFFLOAD] =
{PLAYBACK_OFFLOAD_DEVICE, PLAYBACK_OFFLOAD_DEVICE},
+#ifdef MULTIPLE_OFFLOAD_ENABLED
+ [USECASE_AUDIO_PLAYBACK_OFFLOAD2] =
+ {PLAYBACK_OFFLOAD_DEVICE2, PLAYBACK_OFFLOAD_DEVICE2},
+ [USECASE_AUDIO_PLAYBACK_OFFLOAD3] =
+ {PLAYBACK_OFFLOAD_DEVICE3, PLAYBACK_OFFLOAD_DEVICE3},
+ [USECASE_AUDIO_PLAYBACK_OFFLOAD4] =
+ {PLAYBACK_OFFLOAD_DEVICE4, PLAYBACK_OFFLOAD_DEVICE4},
+ [USECASE_AUDIO_PLAYBACK_OFFLOAD5] =
+ {PLAYBACK_OFFLOAD_DEVICE5, PLAYBACK_OFFLOAD_DEVICE5},
+ [USECASE_AUDIO_PLAYBACK_OFFLOAD6] =
+ {PLAYBACK_OFFLOAD_DEVICE6, PLAYBACK_OFFLOAD_DEVICE6},
+ [USECASE_AUDIO_PLAYBACK_OFFLOAD7] =
+ {PLAYBACK_OFFLOAD_DEVICE7, PLAYBACK_OFFLOAD_DEVICE7},
+ [USECASE_AUDIO_PLAYBACK_OFFLOAD8] =
+ {PLAYBACK_OFFLOAD_DEVICE8, PLAYBACK_OFFLOAD_DEVICE8},
+ [USECASE_AUDIO_PLAYBACK_OFFLOAD9] =
+ {PLAYBACK_OFFLOAD_DEVICE9, PLAYBACK_OFFLOAD_DEVICE9},
+#endif
[USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE},
[USECASE_AUDIO_RECORD_COMPRESS] = {COMPRESS_CAPTURE_DEVICE, COMPRESS_CAPTURE_DEVICE},
[USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
@@ -216,11 +281,17 @@
/* Playback sound devices */
[SND_DEVICE_OUT_HANDSET] = "handset",
[SND_DEVICE_OUT_SPEAKER] = "speaker",
+ [SND_DEVICE_OUT_SPEAKER_EXTERNAL_1] = "speaker-ext-1",
+ [SND_DEVICE_OUT_SPEAKER_EXTERNAL_2] = "speaker-ext-2",
+ [SND_DEVICE_OUT_SPEAKER_WSA] = "wsa-speaker",
[SND_DEVICE_OUT_SPEAKER_REVERSE] = "speaker-reverse",
[SND_DEVICE_OUT_HEADPHONES] = "headphones",
[SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = "speaker-and-headphones",
+ [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1] = "speaker-and-headphones-ext-1",
+ [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2] = "speaker-and-headphones-ext-2",
[SND_DEVICE_OUT_VOICE_HANDSET] = "voice-handset",
[SND_DEVICE_OUT_VOICE_SPEAKER] = "voice-speaker",
+ [SND_DEVICE_OUT_VOICE_SPEAKER_WSA] = "wsa-voice-speaker",
[SND_DEVICE_OUT_VOICE_HEADPHONES] = "voice-headphones",
[SND_DEVICE_OUT_HDMI] = "hdmi",
[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = "speaker-and-hdmi",
@@ -241,6 +312,7 @@
[SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = "speaker-and-anc-headphones",
[SND_DEVICE_OUT_ANC_HANDSET] = "anc-handset",
[SND_DEVICE_OUT_SPEAKER_PROTECTED] = "speaker-protected",
+ [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = "voice-speaker-protected",
#ifdef RECORD_PLAY_CONCURRENCY
[SND_DEVICE_OUT_VOIP_HANDSET] = "voip-handset",
[SND_DEVICE_OUT_VOIP_SPEAKER] = "voip-speaker",
@@ -249,6 +321,7 @@
/* Capture sound devices */
[SND_DEVICE_IN_HANDSET_MIC] = "handset-mic",
+ [SND_DEVICE_IN_HANDSET_MIC_EXTERNAL] = "handset-mic-ext",
[SND_DEVICE_IN_HANDSET_MIC_AEC] = "handset-mic",
[SND_DEVICE_IN_HANDSET_MIC_NS] = "handset-mic",
[SND_DEVICE_IN_HANDSET_MIC_AEC_NS] = "handset-mic",
@@ -304,16 +377,25 @@
[SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS] = "quad-mic",
};
+// Platform specific backend bit width table
+static int backend_bit_width_table[SND_DEVICE_MAX] = {0};
+
/* ACDB IDs (audio DSP path configuration IDs) for each sound device */
static int acdb_device_table[SND_DEVICE_MAX] = {
[SND_DEVICE_NONE] = -1,
[SND_DEVICE_OUT_HANDSET] = 7,
[SND_DEVICE_OUT_SPEAKER] = 14,
+ [SND_DEVICE_OUT_SPEAKER_EXTERNAL_1] = 14,
+ [SND_DEVICE_OUT_SPEAKER_EXTERNAL_2] = 14,
+ [SND_DEVICE_OUT_SPEAKER_WSA] = 135,
[SND_DEVICE_OUT_SPEAKER_REVERSE] = 14,
[SND_DEVICE_OUT_HEADPHONES] = 10,
[SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = 10,
+ [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1] = 10,
+ [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2] = 10,
[SND_DEVICE_OUT_VOICE_HANDSET] = 7,
[SND_DEVICE_OUT_VOICE_SPEAKER] = 14,
+ [SND_DEVICE_OUT_VOICE_SPEAKER_WSA] = 135,
[SND_DEVICE_OUT_VOICE_HEADPHONES] = 10,
[SND_DEVICE_OUT_HDMI] = 18,
[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 14,
@@ -333,7 +415,8 @@
[SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = 27,
[SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = 26,
[SND_DEVICE_OUT_ANC_HANDSET] = 103,
- [SND_DEVICE_OUT_SPEAKER_PROTECTED] = 101,
+ [SND_DEVICE_OUT_SPEAKER_PROTECTED] = 124,
+ [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = 101,
#ifdef RECORD_PLAY_CONCURRENCY
[SND_DEVICE_OUT_VOIP_HANDSET] = 133,
[SND_DEVICE_OUT_VOIP_SPEAKER] = 132,
@@ -341,6 +424,7 @@
#endif
[SND_DEVICE_IN_HANDSET_MIC] = 4,
+ [SND_DEVICE_IN_HANDSET_MIC_EXTERNAL] = 4,
[SND_DEVICE_IN_HANDSET_MIC_AEC] = 106,
[SND_DEVICE_IN_HANDSET_MIC_NS] = 107,
[SND_DEVICE_IN_HANDSET_MIC_AEC_NS] = 108,
@@ -396,7 +480,7 @@
[SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS] = 129,
};
-struct snd_device_index {
+struct name_to_index {
char name[100];
unsigned int index;
};
@@ -404,14 +488,20 @@
#define TO_NAME_INDEX(X) #X, X
/* Used to get index from parsed sting */
-struct snd_device_index snd_device_name_index[SND_DEVICE_MAX] = {
+static struct name_to_index snd_device_name_index[SND_DEVICE_MAX] = {
{TO_NAME_INDEX(SND_DEVICE_OUT_HANDSET)},
{TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_EXTERNAL_1)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_EXTERNAL_2)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_WSA)},
{TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_REVERSE)},
{TO_NAME_INDEX(SND_DEVICE_OUT_HEADPHONES)},
{TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2)},
{TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HANDSET)},
{TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_WSA)},
{TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HEADPHONES)},
{TO_NAME_INDEX(SND_DEVICE_OUT_HDMI)},
{TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HDMI)},
@@ -432,12 +522,14 @@
{TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET)},
{TO_NAME_INDEX(SND_DEVICE_OUT_ANC_HANDSET)},
{TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_PROTECTED)},
+ {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED)},
#ifdef RECORD_PLAY_CONCURRENCY
{TO_NAME_INDEX(SND_DEVICE_OUT_VOIP_HANDSET)},
{TO_NAME_INDEX(SND_DEVICE_OUT_VOIP_SPEAKER)},
{TO_NAME_INDEX(SND_DEVICE_OUT_VOIP_HEADPHONES)},
#endif
{TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_EXTERNAL)},
{TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_AEC)},
{TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_NS)},
{TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_AEC_NS)},
@@ -482,12 +574,47 @@
{TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_STEREO_DMIC)},
{TO_NAME_INDEX(SND_DEVICE_IN_CAPTURE_VI_FEEDBACK)},
{TO_NAME_INDEX(SND_DEVICE_IN_VOICE_FLUENCE_DMIC_AANC)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_BROADSIDE)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE)},
+ {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE)},
{TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_QMIC)},
{TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_AEC)},
{TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_NS)},
{TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS)},
};
+static char * backend_table[SND_DEVICE_MAX] = {0};
+
+static struct name_to_index usecase_name_index[AUDIO_USECASE_MAX] = {
+ {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_DEEP_BUFFER)},
+ {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_LOW_LATENCY)},
+ {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_MULTI_CH)},
+ {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD)},
+#ifdef MULTIPLE_OFFLOAD_ENABLED
+ {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD2)},
+ {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD3)},
+ {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD4)},
+ {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD5)},
+ {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD6)},
+ {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD7)},
+ {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD8)},
+ {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD9)},
+#endif
+ {TO_NAME_INDEX(USECASE_AUDIO_RECORD)},
+ {TO_NAME_INDEX(USECASE_AUDIO_RECORD_LOW_LATENCY)},
+ {TO_NAME_INDEX(USECASE_VOICE_CALL)},
+ {TO_NAME_INDEX(USECASE_VOICE2_CALL)},
+ {TO_NAME_INDEX(USECASE_VOLTE_CALL)},
+ {TO_NAME_INDEX(USECASE_QCHAT_CALL)},
+ {TO_NAME_INDEX(USECASE_VOWLAN_CALL)},
+ {TO_NAME_INDEX(USECASE_INCALL_REC_UPLINK)},
+ {TO_NAME_INDEX(USECASE_INCALL_REC_DOWNLINK)},
+ {TO_NAME_INDEX(USECASE_INCALL_REC_UPLINK_AND_DOWNLINK)},
+ {TO_NAME_INDEX(USECASE_AUDIO_HFP_SCO)},
+};
+
#define NO_COLS 2
static int msm_be_id_array_len;
static int (*msm_device_to_be_id)[];
@@ -670,6 +797,21 @@
msm_device_to_be_id = msm_device_to_be_id_internal_codec;
msm_be_id_array_len =
sizeof(msm_device_to_be_id_external_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+ } else if (!strncmp(snd_card_name, "msm8952-snd-card-mtp",
+ sizeof("msm8952-snd-card-mtpmsm8952-snd-card-mtp"))) {
+ strlcpy(mixer_xml_path, MIXER_XML_PATH_MTP,
+ sizeof(MIXER_XML_PATH_MTP));
+ msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+ msm_be_id_array_len =
+ sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+ } else if (!strncmp(snd_card_name, "msm8952-tomtom-snd-card",
+ sizeof("msm8952-tomtom-snd-card"))) {
+ strlcpy(mixer_xml_path, MIXER_XML_PATH_WCD9330,
+ sizeof(MIXER_XML_PATH_WCD9330));
+ msm_device_to_be_id = msm_device_to_be_id_external_codec;
+ msm_be_id_array_len =
+ sizeof(msm_device_to_be_id_external_codec) / sizeof(msm_device_to_be_id_external_codec[0]);
+
} else {
strlcpy(mixer_xml_path, MIXER_XML_PATH,
sizeof(MIXER_XML_PATH));
@@ -686,18 +828,17 @@
struct platform_data *my_data = (struct platform_data *)platform;
struct audio_device *adev = my_data->adev;
- if (enable) {
- my_data->ec_ref_enabled = enable;
- audio_route_apply_and_update_path(adev->audio_route, "echo-reference");
- } else {
- if (my_data->ec_ref_enabled) {
- audio_route_reset_and_update_path(adev->audio_route, "echo-reference");
- my_data->ec_ref_enabled = enable;
- } else {
- ALOGV("EC reference is already disabled : %d", my_data->ec_ref_enabled);
- }
+ if (my_data->ec_ref_enabled) {
+ my_data->ec_ref_enabled = false;
+ ALOGV("%s: disabling echo-reference", __func__);
+ audio_route_reset_and_update_path(adev->audio_route, "echo-reference");
}
- ALOGV("Setting EC Reference: %d", enable);
+
+ if (enable) {
+ my_data->ec_ref_enabled = true;
+ ALOGD("%s: enabling echo-reference", __func__);
+ audio_route_apply_and_update_path(adev->audio_route, "echo-reference");
+ }
}
static struct csd_data *open_csd_client()
@@ -814,6 +955,8 @@
__func__, dlerror());
goto error;
}
+
+
csd->init = (init_t)dlsym(csd->csd_client, "csd_client_init");
if (csd->init == NULL) {
@@ -842,6 +985,38 @@
}
}
+
+static void set_platform_defaults()
+{
+ int32_t dev;
+ for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
+ backend_table[dev] = NULL;
+ }
+ for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
+ backend_bit_width_table[dev] = 16;
+ }
+
+ // TBD - do these go to the platform-info.xml file.
+ // will help in avoiding strdups here
+ backend_table[SND_DEVICE_IN_BT_SCO_MIC] = strdup("bt-sco");
+ backend_table[SND_DEVICE_IN_BT_SCO_MIC_WB] = strdup("bt-sco-wb");
+ backend_table[SND_DEVICE_IN_BT_SCO_MIC_NREC] = strdup("bt-sco");
+ backend_table[SND_DEVICE_IN_BT_SCO_MIC_WB_NREC] = strdup("bt-sco-wb");
+ backend_table[SND_DEVICE_OUT_BT_SCO] = strdup("bt-sco");
+ backend_table[SND_DEVICE_OUT_BT_SCO_WB] = strdup("bt-sco-wb");
+ backend_table[SND_DEVICE_OUT_HDMI] = strdup("hdmi");
+ backend_table[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = strdup("speaker-and-hdmi");
+ backend_table[SND_DEVICE_OUT_VOICE_TX] = strdup("afe-proxy");
+ backend_table[SND_DEVICE_IN_VOICE_RX] = strdup("afe-proxy");
+ backend_table[SND_DEVICE_OUT_AFE_PROXY] = strdup("afe-proxy");
+ backend_table[SND_DEVICE_OUT_USB_HEADSET] = strdup("usb-headphones");
+ backend_table[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] =
+ strdup("speaker-and-usb-headphones");
+ backend_table[SND_DEVICE_IN_USB_HEADSET_MIC] = strdup("usb-headset-mic");
+ backend_table[SND_DEVICE_IN_CAPTURE_FM] = strdup("capture-fm");
+ backend_table[SND_DEVICE_OUT_TRANSMISSION_FM] = strdup("transmission-fm");
+}
+
void get_cvd_version(char *cvd_version, struct audio_device *adev)
{
struct mixer_ctl *ctl;
@@ -1036,10 +1211,15 @@
my_data->fluence_in_voice_call = false;
my_data->fluence_in_voice_rec = false;
my_data->fluence_in_audio_rec = false;
+ my_data->external_spk_1 = false;
+ my_data->external_spk_2 = false;
+ my_data->external_mic = false;
my_data->fluence_type = FLUENCE_NONE;
my_data->fluence_mode = FLUENCE_ENDFIRE;
my_data->slowtalk = false;
my_data->hd_voice = false;
+ my_data->edid_info = NULL;
+ my_data->is_wsa_speaker = false;
property_get("ro.qc.sdk.audio.fluencetype", my_data->fluence_cap, "");
if (!strncmp("fluencepro", my_data->fluence_cap, sizeof("fluencepro"))) {
@@ -1079,6 +1259,7 @@
property_get("persist.audio.FFSP.enable", ffspEnable, "");
if (!strncmp("true", ffspEnable, sizeof("true"))) {
acdb_device_table[SND_DEVICE_OUT_SPEAKER] = 131;
+ acdb_device_table[SND_DEVICE_OUT_SPEAKER_WSA] = 131;
acdb_device_table[SND_DEVICE_OUT_SPEAKER_REVERSE] = 131;
acdb_device_table[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 131;
acdb_device_table[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 131;
@@ -1104,6 +1285,18 @@
ALOGE("%s: Could not find the symbol acdb_send_audio_cal from %s",
__func__, LIB_ACDB_LOADER);
+ my_data->acdb_set_audio_cal = (acdb_set_audio_cal_t)dlsym(my_data->acdb_handle,
+ "acdb_loader_set_audio_cal_v2");
+ if (!my_data->acdb_set_audio_cal)
+ ALOGE("%s: Could not find the symbol acdb_set_audio_cal_v2 from %s",
+ __func__, LIB_ACDB_LOADER);
+
+ my_data->acdb_get_audio_cal = (acdb_get_audio_cal_t)dlsym(my_data->acdb_handle,
+ "acdb_loader_get_audio_cal_v2");
+ if (!my_data->acdb_get_audio_cal)
+ ALOGE("%s: Could not find the symbol acdb_get_audio_cal_v2 from %s",
+ __func__, LIB_ACDB_LOADER);
+
my_data->acdb_send_voice_cal = (acdb_send_voice_cal_t)dlsym(my_data->acdb_handle,
"acdb_loader_send_voice_cal");
if (!my_data->acdb_send_voice_cal)
@@ -1141,7 +1334,29 @@
}
audio_extn_pm_vote();
+ // Check if WSA speaker is supported in codec
+ char CodecPeek[1024] = "/sys/kernel/debug/asoc/";
+ DIR *dir;
+ struct dirent *dirent;
+ char file_name[10] = "wsa";
+ strcat(CodecPeek, snd_card_name);
+
+ dir = opendir(CodecPeek);
+ if (dir != NULL) {
+ while (NULL != (dirent = readdir(dir))) {
+ if (strstr (dirent->d_name,file_name))
+ {
+ my_data->is_wsa_speaker = true;
+ break;
+ }
+ }
+ closedir(dir);
+ }
+
acdb_init_fail:
+
+ set_platform_defaults();
+
/* Initialize ACDB ID's */
platform_info_init(PLATFORM_INFO_XML_PATH);
@@ -1160,6 +1375,10 @@
audio_extn_dolby_set_license(adev);
audio_hwdep_send_cal(my_data);
+ /* init audio device arbitration */
+ audio_extn_dev_arbi_init();
+
+ my_data->edid_info = NULL;
return my_data;
}
@@ -1167,9 +1386,30 @@
{
struct platform_data *my_data = (struct platform_data *)platform;
+ if (my_data->edid_info) {
+ free(my_data->edid_info);
+ my_data->edid_info = NULL;
+ }
+
hw_info_deinit(my_data->hw_info);
close_csd_client(my_data->csd);
+ int32_t dev;
+ for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
+ if (backend_table[dev]) {
+ free(backend_table[dev]);
+ backend_table[dev]= NULL;
+ }
+ }
+
+ /* deinit audio device arbitration */
+ audio_extn_dev_arbi_deinit();
+
+ if (my_data->edid_info) {
+ free(my_data->edid_info);
+ my_data->edid_info = NULL;
+ }
+
free(platform);
/* deinit usb */
audio_extn_usb_deinit();
@@ -1202,37 +1442,17 @@
void platform_add_backend_name(char *mixer_path, snd_device_t snd_device)
{
- if ((snd_device == SND_DEVICE_IN_BT_SCO_MIC) ||
- (snd_device == SND_DEVICE_IN_BT_SCO_MIC_NREC))
- strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH);
- else if ((snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB) ||
- (snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB_NREC))
- strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH);
- else if(snd_device == SND_DEVICE_OUT_BT_SCO)
- strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH);
- else if(snd_device == SND_DEVICE_OUT_BT_SCO_WB)
- strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH);
- else if (snd_device == SND_DEVICE_OUT_HDMI)
- strlcat(mixer_path, " hdmi", MIXER_PATH_MAX_LENGTH);
- else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HDMI)
- strlcat(mixer_path, " speaker-and-hdmi", MIXER_PATH_MAX_LENGTH);
- else if (snd_device == SND_DEVICE_OUT_VOICE_TX)
- strlcat(mixer_path, " afe-proxy", MIXER_PATH_MAX_LENGTH);
- else if (snd_device == SND_DEVICE_IN_VOICE_RX)
- strlcat(mixer_path, " afe-proxy", MIXER_PATH_MAX_LENGTH);
- else if (snd_device == SND_DEVICE_OUT_AFE_PROXY)
- strlcat(mixer_path, " afe-proxy", MIXER_PATH_MAX_LENGTH);
- else if (snd_device == SND_DEVICE_OUT_USB_HEADSET)
- strlcat(mixer_path, " usb-headphones", MIXER_PATH_MAX_LENGTH);
- else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET)
- strlcat(mixer_path, " speaker-and-usb-headphones",
- MIXER_PATH_MAX_LENGTH);
- else if (snd_device == SND_DEVICE_IN_USB_HEADSET_MIC)
- strlcat(mixer_path, " usb-headset-mic", MIXER_PATH_MAX_LENGTH);
- else if (snd_device == SND_DEVICE_IN_CAPTURE_FM)
- strlcat(mixer_path, " capture-fm", MIXER_PATH_MAX_LENGTH);
- else if (snd_device == SND_DEVICE_OUT_TRANSMISSION_FM)
- strlcat(mixer_path, " transmission-fm", MIXER_PATH_MAX_LENGTH);
+ if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
+ ALOGE("%s: Invalid snd_device = %d", __func__, snd_device);
+ return;
+ }
+
+ const char * suffix = backend_table[snd_device];
+
+ if (suffix != NULL) {
+ strlcat(mixer_path, " ", MIXER_PATH_MAX_LENGTH);
+ strlcat(mixer_path, suffix, MIXER_PATH_MAX_LENGTH);
+ }
}
int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type)
@@ -1245,25 +1465,36 @@
return device_id;
}
-int platform_get_snd_device_index(char *snd_device_index_name)
+static int find_index(struct name_to_index * table, int32_t len, const char * name)
{
int ret = 0;
- int i;
+ int32_t i;
- if (snd_device_index_name == NULL) {
- ALOGE("%s: snd_device_index_name is NULL", __func__);
+ if (table == NULL) {
+ ALOGE("%s: table is NULL", __func__);
ret = -ENODEV;
goto done;
}
- for (i=0; i < SND_DEVICE_MAX; i++) {
- if(strcmp(snd_device_name_index[i].name, snd_device_index_name) == 0) {
- ret = snd_device_name_index[i].index;
+ if (name == NULL) {
+ ALOGE("null key");
+ ret = -ENODEV;
+ goto done;
+ }
+
+ for (i=0; i < len; i++) {
+ const char* tn = table[i].name;
+ size_t len = strlen(tn);
+ if (strncmp(tn, name, len) == 0) {
+ if (strlen(name) != len) {
+ continue; // substring
+ }
+ ret = table[i].index;
goto done;
}
}
- ALOGE("%s: Could not find index for snd_device_index_name = %s",
- __func__, snd_device_index_name);
+ ALOGE("%s: Could not find index for name = %s",
+ __func__, name);
ret = -ENODEV;
done:
return ret;
@@ -1326,6 +1557,16 @@
return ret;
}
+int platform_get_snd_device_index(char *device_name)
+{
+ return find_index(snd_device_name_index, SND_DEVICE_MAX, device_name);
+}
+
+int platform_get_usecase_index(const char *usecase_name)
+{
+ return find_index(usecase_name_index, AUDIO_USECASE_MAX, usecase_name);
+}
+
int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id)
{
int ret = 0;
@@ -1360,17 +1601,30 @@
}
return acdb_device_table[snd_device];
}
-int platform_set_snd_device_bit_width(snd_device_t snd_device __unused,
- unsigned int bit_width __unused)
+
+int platform_set_snd_device_bit_width(snd_device_t snd_device, unsigned int bit_width)
{
- ALOGE("%s: Not implemented", __func__);
- return -ENOSYS;
+ int ret = 0;
+
+ if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
+ ALOGE("%s: Invalid snd_device = %d",
+ __func__, snd_device);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ backend_bit_width_table[snd_device] = bit_width;
+done:
+ return ret;
}
-int platform_get_snd_device_bit_width(snd_device_t snd_device __unused)
+int platform_get_snd_device_bit_width(snd_device_t snd_device)
{
- ALOGE("%s: Not implemented", __func__);
- return -ENOSYS;
+ if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
+ ALOGE("%s: Invalid snd_device = %d", __func__, snd_device);
+ return DEFAULT_OUTPUT_SAMPLING_RATE;
+ }
+ return backend_bit_width_table[snd_device];
}
int platform_send_audio_calibration(void *platform, struct audio_usecase *usecase,
@@ -1381,18 +1635,12 @@
struct audio_device *adev = my_data->adev;
int snd_device = SND_DEVICE_OUT_SPEAKER;
- if (usecase->type == PCM_PLAYBACK) {
- snd_device = platform_get_output_snd_device(adev->platform,
- usecase->stream.out->devices);
- if(usecase->id != USECASE_AUDIO_PLAYBACK_OFFLOAD)
- app_type = APP_TYPE_SYSTEM_SOUNDS;
- } else if ((usecase->type == PCM_HFP_CALL) || (usecase->type == PCM_CAPTURE)) {
- snd_device = platform_get_input_snd_device(adev->platform,
- adev->primary_output->devices);
- app_type = APP_TYPE_GENERAL_RECORDING;
- }
+ if (usecase->type == PCM_PLAYBACK)
+ snd_device = usecase->out_snd_device;
+ else if ((usecase->type == PCM_HFP_CALL) || (usecase->type == PCM_CAPTURE))
+ snd_device = usecase->in_snd_device;
+ acdb_dev_id = acdb_device_table[audio_extn_get_spkr_prot_snd_device(snd_device)];
- acdb_dev_id = acdb_device_table[snd_device];
if (acdb_dev_id < 0) {
ALOGE("%s: Could not find acdb id for device(%d)",
__func__, snd_device);
@@ -1428,6 +1676,7 @@
}
return ret;
}
+
int platform_switch_voice_call_enable_device_config(void *platform,
snd_device_t out_snd_device,
snd_device_t in_snd_device)
@@ -1436,25 +1685,31 @@
int acdb_rx_id, acdb_tx_id;
int ret = 0;
- acdb_rx_id = acdb_device_table[out_snd_device];
+ if (my_data->csd == NULL)
+ return ret;
+
+ if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER &&
+ audio_extn_spkr_prot_is_enabled())
+ acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_SPEAKER_PROTECTED];
+ else
+ acdb_rx_id = acdb_device_table[out_snd_device];
+
acdb_tx_id = acdb_device_table[in_snd_device];
- if (my_data->csd != NULL) {
- if (acdb_rx_id > 0 && acdb_tx_id > 0) {
- ret = my_data->csd->enable_device_config(acdb_rx_id, acdb_tx_id);
- if (ret < 0) {
- ALOGE("%s: csd_enable_device_config, failed, error %d",
- __func__, ret);
- }
- } else {
- ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
- acdb_rx_id, acdb_tx_id);
+ if (acdb_rx_id > 0 && acdb_tx_id > 0) {
+ ret = my_data->csd->enable_device_config(acdb_rx_id, acdb_tx_id);
+ if (ret < 0) {
+ ALOGE("%s: csd_enable_device_config, failed, error %d",
+ __func__, ret);
}
+ } else {
+ ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
+ acdb_rx_id, acdb_tx_id);
}
+
return ret;
}
-
int platform_switch_voice_call_device_post(void *platform,
snd_device_t out_snd_device,
snd_device_t in_snd_device)
@@ -1465,6 +1720,10 @@
if (my_data->acdb_send_voice_cal == NULL) {
ALOGE("%s: dlsym error for acdb_send_voice_call", __func__);
} else {
+ if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER &&
+ audio_extn_spkr_prot_is_enabled())
+ out_snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED;
+
acdb_rx_id = acdb_device_table[out_snd_device];
acdb_tx_id = acdb_device_table[in_snd_device];
@@ -1486,22 +1745,28 @@
int acdb_rx_id, acdb_tx_id;
int ret = 0;
- acdb_rx_id = acdb_device_table[out_snd_device];
+ if (my_data->csd == NULL)
+ return ret;
+
+ if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER &&
+ audio_extn_spkr_prot_is_enabled())
+ acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_SPEAKER_PROTECTED];
+ else
+ acdb_rx_id = acdb_device_table[out_snd_device];
+
acdb_tx_id = acdb_device_table[in_snd_device];
- if (my_data->csd != NULL) {
- if (acdb_rx_id > 0 && acdb_tx_id > 0) {
- ret = my_data->csd->enable_device(acdb_rx_id, acdb_tx_id,
- my_data->adev->acdb_settings);
- if (ret < 0) {
- ALOGE("%s: csd_enable_device, failed, error %d",
- __func__, ret);
- }
- } else {
- ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
- acdb_rx_id, acdb_tx_id);
+ if (acdb_rx_id > 0 && acdb_tx_id > 0) {
+ ret = my_data->csd->enable_device(acdb_rx_id, acdb_tx_id,
+ my_data->adev->acdb_settings);
+ if (ret < 0) {
+ ALOGE("%s: csd_enable_device, failed, error %d", __func__, ret);
}
+ } else {
+ ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
+ acdb_rx_id, acdb_tx_id);
}
+
return ret;
}
@@ -1533,7 +1798,7 @@
return ret;
}
-int platform_get_sample_rate(void *platform __unused, uint32_t *rate __unused)
+int platform_get_sample_rate(void *platform, uint32_t *rate)
{
return 0;
}
@@ -1565,7 +1830,8 @@
mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
if (my_data->csd != NULL) {
- ret = my_data->csd->volume(ALL_SESSION_VSID, volume);
+ ret = my_data->csd->volume(ALL_SESSION_VSID, volume,
+ DEFAULT_VOLUME_RAMP_DURATION_MS);
if (ret < 0) {
ALOGE("%s: csd_volume error %d", __func__, ret);
}
@@ -1582,7 +1848,7 @@
int ret = 0;
uint32_t set_values[ ] = {0,
ALL_SESSION_VSID,
- DEFAULT_VOLUME_RAMP_DURATION_MS};
+ DEFAULT_MUTE_RAMP_DURATION_MS};
set_values[0] = state;
ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
@@ -1595,7 +1861,8 @@
mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
if (my_data->csd != NULL) {
- ret = my_data->csd->mic_mute(ALL_SESSION_VSID, state);
+ ret = my_data->csd->mic_mute(ALL_SESSION_VSID, state,
+ DEFAULT_MUTE_RAMP_DURATION_MS);
if (ret < 0) {
ALOGE("%s: csd_mic_mute error %d", __func__, ret);
}
@@ -1674,11 +1941,20 @@
if (popcount(devices) == 2) {
if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
AUDIO_DEVICE_OUT_SPEAKER)) {
- snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
+ if (my_data->external_spk_1)
+ snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1;
+ else if (my_data->external_spk_2)
+ snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2;
+ else
+ snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
} else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET |
AUDIO_DEVICE_OUT_SPEAKER)) {
if (audio_extn_get_anc_enabled())
snd_device = SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET;
+ else if (my_data->external_spk_1)
+ snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1;
+ else if (my_data->external_spk_2)
+ snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2;
else
snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
} else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL |
@@ -1734,7 +2010,10 @@
else
snd_device = SND_DEVICE_OUT_BT_SCO;
} else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
- snd_device = SND_DEVICE_OUT_VOICE_SPEAKER;
+ if (my_data->is_wsa_speaker)
+ snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_WSA;
+ else
+ snd_device = SND_DEVICE_OUT_VOICE_SPEAKER;
} else if (devices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET ||
devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
snd_device = SND_DEVICE_OUT_USB_HEADSET;
@@ -1787,7 +2066,12 @@
if (adev->speaker_lr_swap)
snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE;
else
- snd_device = SND_DEVICE_OUT_SPEAKER;
+ {
+ if (my_data->is_wsa_speaker)
+ snd_device = SND_DEVICE_OUT_SPEAKER_WSA;
+ else
+ snd_device = SND_DEVICE_OUT_SPEAKER;
+ }
}
} else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
if (adev->bt_wb_speech_enabled)
@@ -1841,7 +2125,23 @@
ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
__func__, out_device, in_device);
- if ((out_device != AUDIO_DEVICE_NONE) && (voice_is_in_call(adev) ||
+ if (my_data->external_mic) {
+ if ((out_device != AUDIO_DEVICE_NONE && voice_is_in_call(adev)) ||
+ voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev)) {
+ if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+ out_device & AUDIO_DEVICE_OUT_EARPIECE ||
+ out_device & AUDIO_DEVICE_OUT_SPEAKER )
+ snd_device = SND_DEVICE_IN_HANDSET_MIC_EXTERNAL;
+ } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC ||
+ in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+ snd_device = SND_DEVICE_IN_HANDSET_MIC_EXTERNAL;
+ }
+ }
+
+ if (snd_device != AUDIO_DEVICE_NONE)
+ goto exit;
+
+ if ((out_device != AUDIO_DEVICE_NONE) && ((voice_is_in_call(adev)) ||
voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev))) {
if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
!voice_extn_compress_voip_is_active(adev)) {
@@ -1875,6 +2175,7 @@
} else if (out_device & AUDIO_DEVICE_OUT_EARPIECE &&
audio_extn_should_use_handset_anc(channel_count)) {
snd_device = SND_DEVICE_IN_AANC_HANDSET_MIC;
+ adev->acdb_settings |= ANC_FLAG;
} else if (my_data->fluence_type == FLUENCE_NONE ||
my_data->fluence_in_voice_call == false) {
snd_device = SND_DEVICE_IN_HANDSET_MIC;
@@ -1886,8 +2187,8 @@
}
} else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC;
- if (audio_extn_hfp_is_active(adev))
- platform_set_echo_reference(adev->platform, true);
+ if (audio_extn_hfp_is_active(adev))
+ platform_set_echo_reference(adev->platform, true);
} else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) {
if (adev->bt_wb_speech_enabled) {
if (adev->bluetooth_nrec)
@@ -2057,7 +2358,8 @@
if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
if (audio_extn_ssr_get_enabled() && channel_count == 6)
snd_device = SND_DEVICE_IN_QUAD_MIC;
- else if (channel_count == 2)
+ else if (my_data->fluence_type & (FLUENCE_DUAL_MIC | FLUENCE_QUAD_MIC) &&
+ channel_count == 2)
snd_device = SND_DEVICE_IN_HANDSET_STEREO_DMIC;
else
snd_device = SND_DEVICE_IN_HANDSET_MIC;
@@ -2165,54 +2467,27 @@
int platform_edid_get_max_channels(void *platform)
{
+ int channel_count;
+ int max_channels = 2;
+ int i = 0, ret = 0;
struct platform_data *my_data = (struct platform_data *)platform;
struct audio_device *adev = my_data->adev;
- char block[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE];
- char *sad = block;
- int num_audio_blocks;
- int channel_count;
- int max_channels = 0;
- int i, ret, count;
+ edid_audio_info *info = NULL;
+ ret = platform_get_edid_info(platform);
+ info = (edid_audio_info *)my_data->edid_info;
- struct mixer_ctl *ctl;
-
- ctl = mixer_get_ctl_by_name(adev->mixer, AUDIO_DATA_BLOCK_MIXER_CTL);
- if (!ctl) {
- ALOGE("%s: Could not get ctl for mixer cmd - %s",
- __func__, AUDIO_DATA_BLOCK_MIXER_CTL);
- return 0;
- }
-
- mixer_ctl_update(ctl);
-
- count = mixer_ctl_get_num_values(ctl);
-
- /* Read SAD blocks, clamping the maximum size for safety */
- if (count > (int)sizeof(block))
- count = (int)sizeof(block);
-
- ret = mixer_ctl_get_array(ctl, block, count);
- if (ret != 0) {
- ALOGE("%s: mixer_ctl_get_array() failed to get EDID info", __func__);
- return 0;
- }
-
- /* Calculate the number of SAD blocks */
- num_audio_blocks = count / SAD_BLOCK_SIZE;
-
- for (i = 0; i < num_audio_blocks; i++) {
- /* Only consider LPCM blocks */
- if ((sad[0] >> 3) != EDID_FORMAT_LPCM) {
- sad += 3;
- continue;
+ if(ret == 0 && info != NULL) {
+ for (i = 0; i < info->audio_blocks && i < MAX_EDID_BLOCKS; i++) {
+ ALOGV("%s:format %d channel %d", __func__,
+ info->audio_blocks_array[i].format_id,
+ info->audio_blocks_array[i].channels);
+ if (info->audio_blocks_array[i].format_id == LPCM) {
+ channel_count = info->audio_blocks_array[i].channels;
+ if (channel_count > max_channels) {
+ max_channels = channel_count;
+ }
+ }
}
-
- channel_count = (sad[0] & 0x7) + 1;
- if (channel_count > max_channels)
- max_channels = channel_count;
-
- /* Advance to next block */
- sad += 3;
}
return max_channels;
@@ -2273,6 +2548,159 @@
return ret;
}
+static int update_external_device_status(struct platform_data *my_data,
+ char* event_name, bool status)
+{
+ int ret = 0;
+ struct audio_usecase *usecase;
+ struct listnode *node;
+
+ ALOGD("Recieved external event switch %s", event_name);
+
+ if (!strcmp(event_name, EVENT_EXTERNAL_SPK_1))
+ my_data->external_spk_1 = status;
+ else if (!strcmp(event_name, EVENT_EXTERNAL_SPK_2))
+ my_data->external_spk_2 = status;
+ else if (!strcmp(event_name, EVENT_EXTERNAL_MIC))
+ my_data->external_mic = status;
+ else {
+ ALOGE("The audio event type is not found");
+ return -EINVAL;
+ }
+
+ list_for_each(node, &my_data->adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ select_devices(my_data->adev, usecase->id);
+ }
+
+ return ret;
+}
+
+static int parse_audiocal_cfg(struct str_parms *parms, acdb_audio_cal_cfg_t *cal)
+{
+ int err;
+ unsigned int val;
+ char value[64];
+ int ret = 0;
+
+ if(parms == NULL || cal == NULL)
+ return ret;
+
+ err = str_parms_get_str(parms, "cal_persist", value, sizeof(value));
+ if (err >= 0) {
+ str_parms_del(parms, "cal_persist");
+ cal->persist = (uint32_t) strtoul(value, NULL, 0);
+ ret = ret | 0x1;
+ }
+ err = str_parms_get_str(parms, "cal_apptype", value, sizeof(value));
+ if (err >= 0) {
+ str_parms_del(parms, "cal_apptype");
+ cal->app_type = (uint32_t) strtoul(value, NULL, 0);
+ ret = ret | 0x2;
+ }
+ err = str_parms_get_str(parms, "cal_caltype", value, sizeof(value));
+ if (err >= 0) {
+ str_parms_del(parms, "cal_caltype");
+ cal->cal_type = (uint32_t) strtoul(value, NULL, 0);
+ ret = ret | 0x4;
+ }
+ err = str_parms_get_str(parms, "cal_samplerate", value, sizeof(value));
+ if (err >= 0) {
+ str_parms_del(parms, "cal_samplerate");
+ cal->sampling_rate = (uint32_t) strtoul(value, NULL, 0);
+ ret = ret | 0x8;
+ }
+ err = str_parms_get_str(parms, "cal_devid", value, sizeof(value));
+ if (err >= 0) {
+ str_parms_del(parms, "cal_devid");
+ cal->dev_id = (uint32_t) strtoul(value, NULL, 0);
+ ret = ret | 0x10;
+ }
+ err = str_parms_get_str(parms, "cal_snddevid", value, sizeof(value));
+ if (err >= 0) {
+ str_parms_del(parms, "cal_snddevid");
+ cal->snd_dev_id = (uint32_t) strtoul(value, NULL, 0);
+ ret = ret | 0x20;
+ }
+ err = str_parms_get_str(parms, "cal_topoid", value, sizeof(value));
+ if (err >= 0) {
+ str_parms_del(parms, "cal_topoid");
+ cal->topo_id = (uint32_t) strtoul(value, NULL, 0);
+ ret = ret | 0x40;
+ }
+ err = str_parms_get_str(parms, "cal_moduleid", value, sizeof(value));
+ if (err >= 0) {
+ str_parms_del(parms, "cal_moduleid");
+ cal->module_id = (uint32_t) strtoul(value, NULL, 0);
+ ret = ret | 0x80;
+ }
+ err = str_parms_get_str(parms, "cal_paramid", value, sizeof(value));
+ if (err >= 0) {
+ str_parms_del(parms, "cal_paramid");
+ cal->param_id = (uint32_t) strtoul(value, NULL, 0);
+ ret = ret | 0x100;
+ }
+ return ret;
+}
+
+static void set_audiocal(void *platform, struct str_parms *parms, char *value, int len) {
+ struct platform_data *my_data = (struct platform_data *)platform;
+ acdb_audio_cal_cfg_t cal={0};
+ uint8_t *dptr = NULL;
+ int32_t dlen;
+ int err, ret;
+ if(value == NULL || platform == NULL || parms == NULL) {
+ ALOGE("[%s] received null pointer, failed",__func__);
+ goto done_key_audcal;
+ }
+
+ /* parse audio calibration keys */
+ ret = parse_audiocal_cfg(parms, &cal);
+
+ /* handle audio calibration data now */
+ err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_AUD_CALDATA, value, len);
+ if (err >= 0) {
+ str_parms_del(parms, AUDIO_PARAMETER_KEY_AUD_CALDATA);
+ dlen = strlen(value);
+ if(dlen <= 0) {
+ ALOGE("[%s] null data received",__func__);
+ goto done_key_audcal;
+ }
+ dptr = (uint8_t*) calloc(dlen, sizeof(uint8_t));
+ if(dptr == NULL) {
+ ALOGE("[%s] memory allocation failed for %d",__func__, dlen);
+ goto done_key_audcal;
+ }
+ dlen = b64decode(value, strlen(value), dptr);
+ if(dlen<=0) {
+ ALOGE("[%s] data decoding failed %d", __func__, dlen);
+ goto done_key_audcal;
+ }
+
+ if(cal.dev_id) {
+ if(audio_is_input_device(cal.dev_id)) {
+ cal.snd_dev_id = platform_get_input_snd_device(platform, cal.dev_id);
+ } else {
+ cal.snd_dev_id = platform_get_output_snd_device(platform, cal.dev_id);
+ }
+ }
+ cal.acdb_dev_id = platform_get_snd_device_acdb_id(cal.snd_dev_id);
+ ALOGD("Setting audio calibration for snd_device(%d) acdb_id(%d)",
+ cal.snd_dev_id, cal.acdb_dev_id);
+ if(cal.acdb_dev_id == -EINVAL) {
+ ALOGE("[%s] Invalid acdb_device id %d for snd device id %d",
+ __func__, cal.acdb_dev_id, cal.snd_dev_id);
+ goto done_key_audcal;
+ }
+ if(my_data->acdb_set_audio_cal) {
+ ret = my_data->acdb_set_audio_cal((void *)&cal, (void*)dptr, dlen);
+ }
+ }
+done_key_audcal:
+ if(dptr != NULL)
+ free(dptr);
+}
+
int platform_set_parameters(void *platform, struct str_parms *parms)
{
struct platform_data *my_data = (struct platform_data *)platform;
@@ -2450,13 +2878,106 @@
return ret;
}
+static void get_audiocal(void *platform, void *keys, void *pReply) {
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct str_parms *query = (struct str_parms *)keys;
+ struct str_parms *reply=(struct str_parms *)pReply;
+ acdb_audio_cal_cfg_t cal={0};
+ uint8_t *dptr = NULL;
+ char value[512] = {0};
+ char *rparms=NULL;
+ int ret=0, err;
+ uint32_t param_len;
+
+ if(query==NULL || platform==NULL || reply==NULL) {
+ ALOGE("[%s] received null pointer",__func__);
+ ret=-EINVAL;
+ goto done;
+ }
+ /* parse audiocal configuration keys */
+ ret = parse_audiocal_cfg(query, &cal);
+ if(ret == 0) {
+ /* No calibration keys found */
+ goto done;
+ }
+ err = str_parms_get_str(query, AUDIO_PARAMETER_KEY_AUD_CALDATA, value, sizeof(value));
+ if (err >= 0) {
+ str_parms_del(query, AUDIO_PARAMETER_KEY_AUD_CALDATA);
+ } else {
+ goto done;
+ }
+
+ if(cal.dev_id & AUDIO_DEVICE_BIT_IN) {
+ cal.snd_dev_id = platform_get_input_snd_device(platform, cal.dev_id);
+ } else if(cal.dev_id) {
+ cal.snd_dev_id = platform_get_output_snd_device(platform, cal.dev_id);
+ }
+ cal.acdb_dev_id = platform_get_snd_device_acdb_id(cal.snd_dev_id);
+ if (cal.acdb_dev_id < 0) {
+ ALOGE("%s: Failed. Could not find acdb id for snd device(%d)",
+ __func__, cal.snd_dev_id);
+ ret = -EINVAL;
+ goto done_key_audcal;
+ }
+ ALOGD("[%s] Getting audio calibration for snd_device(%d) acdb_id(%d)",
+ __func__, cal.snd_dev_id, cal.acdb_dev_id);
+
+ param_len = MAX_SET_CAL_BYTE_SIZE;
+ dptr = (uint8_t*)calloc(param_len, sizeof(uint8_t));
+ if(dptr == NULL) {
+ ALOGE("[%s] Memory allocation failed for length %d",__func__,param_len);
+ ret = -ENOMEM;
+ goto done_key_audcal;
+ }
+ if (my_data->acdb_get_audio_cal != NULL) {
+ ret = my_data->acdb_get_audio_cal((void*)&cal, (void*)dptr, ¶m_len);
+ if (ret == 0) {
+ int dlen;
+ if(param_len == 0 || param_len == MAX_SET_CAL_BYTE_SIZE) {
+ ret = -EINVAL;
+ goto done_key_audcal;
+ }
+ /* Allocate memory for encoding */
+ rparms = (char*)calloc((param_len*2), sizeof(char));
+ if(rparms == NULL) {
+ ALOGE("[%s] Memory allocation failed for size %d",
+ __func__, param_len*2);
+ ret = -ENOMEM;
+ goto done_key_audcal;
+ }
+ if(cal.persist==0 && cal.module_id && cal.param_id) {
+ err = b64encode(dptr+12, param_len-12, rparms);
+ } else {
+ err = b64encode(dptr, param_len, rparms);
+ }
+ if(err < 0) {
+ ALOGE("[%s] failed to convert data to string", __func__);
+ ret = -EINVAL;
+ goto done_key_audcal;
+ }
+ str_parms_add_int(reply, AUDIO_PARAMETER_KEY_AUD_CALRESULT, ret);
+ str_parms_add_str(reply, AUDIO_PARAMETER_KEY_AUD_CALDATA, rparms);
+ }
+ }
+done_key_audcal:
+ if(ret != 0) {
+ str_parms_add_int(reply, AUDIO_PARAMETER_KEY_AUD_CALRESULT, ret);
+ str_parms_add_str(reply, AUDIO_PARAMETER_KEY_AUD_CALDATA, "");
+ }
+done:
+ if(dptr != NULL)
+ free(dptr);
+ if(rparms != NULL)
+ free(rparms);
+}
+
void platform_get_parameters(void *platform,
struct str_parms *query,
struct str_parms *reply)
{
struct platform_data *my_data = (struct platform_data *)platform;
char *str = NULL;
- char value[256] = {0};
+ char value[512] = {0};
int ret;
char *kv_pairs = NULL;
@@ -2486,6 +3007,7 @@
str_parms_add_str(reply, AUDIO_PARAMETER_KEY_VOLUME_BOOST, value);
}
+ /* Handle audio calibration keys */
kv_pairs = str_parms_to_str(reply);
ALOGV("%s: exit: returns - %s", __func__, kv_pairs);
free(kv_pairs);
@@ -2647,6 +3169,14 @@
fragment_size = atoi(value) * 1024;
}
+ // For FLAC use max size since it is loss less, and has sampling rates
+ // upto 192kHZ
+ if (info != NULL && !info->has_video &&
+ info->format == AUDIO_FORMAT_FLAC) {
+ fragment_size = MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE;
+ ALOGV("FLAC fragment size %d", fragment_size);
+ }
+
if (info != NULL && info->has_video && info->is_streaming) {
fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING;
ALOGV("%s: offload fragment size reduced for AV streaming to %d",
@@ -2665,103 +3195,749 @@
uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info)
{
- uint32_t fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
+ uint32_t fragment_size = 0;
uint32_t bits_per_sample = 16;
+ uint32_t pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_SMALL_BUFFERS;
if (info->format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) {
bits_per_sample = 32;
}
- if (!info->has_video) {
- fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;
-
- } else if (info->has_video && info->is_streaming) {
- fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING
- * info->sample_rate
- * bits_per_sample
- * popcount(info->channel_mask))/1000;
-
- } else if (info->has_video) {
- fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV
- * info->sample_rate
- * bits_per_sample
- * popcount(info->channel_mask))/1000;
+ if (info->use_small_bufs) {
+ pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_SMALL_BUFFERS;
+ } else {
+ if (!info->has_video) {
+ pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_MAX;
+ } else if (info->has_video && info->is_streaming) {
+ pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING;
+ } else if (info->has_video) {
+ pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_AV;
+ }
}
- fragment_size = ALIGN( fragment_size, 1024);
-
+ //duration is set to 20 ms worth of stereo data at 48Khz
+ //with 16 bit per sample, modify this when the channel
+ //configuration is different
+ fragment_size = (pcm_offload_time
+ * info->sample_rate
+ * (bits_per_sample >> 3)
+ * popcount(info->channel_mask))/1000;
+ // align with LCM of 2, 4, 6, 8
+ fragment_size = ALIGN( fragment_size, 24 );
if(fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE)
fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
else if(fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE)
fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;
- ALOGV("%s: fragment_size %d", __func__, fragment_size);
+ ALOGI("PCM offload Fragment size to %d bytes", fragment_size);
return fragment_size;
}
+int platform_set_codec_backend_cfg(struct audio_device* adev,
+ unsigned int bit_width, unsigned int sample_rate)
+{
+ ALOGV("%s bit width: %d, sample rate: %d", __func__, bit_width, sample_rate);
+
+ int ret = 0;
+ if (bit_width != adev->cur_codec_backend_bit_width) {
+ const char * mixer_ctl_name = "SLIM_0_RX Format";
+ struct mixer_ctl *ctl;
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer command - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+
+ if (bit_width == 24) {
+ mixer_ctl_set_enum_by_string(ctl, "S24_LE");
+ } else {
+ mixer_ctl_set_enum_by_string(ctl, "S16_LE");
+ sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+ }
+ adev->cur_codec_backend_bit_width = bit_width;
+ ALOGE("Backend bit width is set to %d ", bit_width);
+ }
+
+ /*
+ * Backend sample rate configuration follows:
+ * 16 bit playback - 48khz for streams at any valid sample rate
+ * 24 bit playback - 48khz for stream sample rate less than 48khz
+ * 24 bit playback - 96khz for sample rate range of 48khz to 96khz
+ * 24 bit playback - 192khz for sample rate range of 96khz to 192 khz
+ * Upper limit is inclusive in the sample rate range.
+ */
+ // TODO: This has to be more dynamic based on policy file
+ if (sample_rate != adev->cur_codec_backend_samplerate) {
+ char *rate_str = NULL;
+ const char * mixer_ctl_name = "SLIM_0_RX SampleRate";
+ struct mixer_ctl *ctl;
+
+ switch (sample_rate) {
+ case 8000:
+ case 11025:
+ case 16000:
+ case 22050:
+ case 32000:
+ case 44100:
+ case 48000:
+ rate_str = "KHZ_48";
+ break;
+ case 64000:
+ case 88200:
+ case 96000:
+ rate_str = "KHZ_96";
+ break;
+ case 176400:
+ case 192000:
+ rate_str = "KHZ_192";
+ break;
+ default:
+ rate_str = "KHZ_48";
+ break;
+ }
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if(!ctl) {
+ ALOGE("%s: Could not get ctl for mixer command - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+
+ ALOGV("Set sample rate as rate_str = %s", rate_str);
+ mixer_ctl_set_enum_by_string(ctl, rate_str);
+ adev->cur_codec_backend_samplerate = sample_rate;
+ }
+
+ return ret;
+}
+
+bool platform_check_codec_backend_cfg(struct audio_device* adev,
+ struct audio_usecase* usecase __unused,
+ unsigned int* new_bit_width,
+ unsigned int* new_sample_rate)
+{
+ bool backend_change = false;
+ struct listnode *node;
+ struct stream_out *out = NULL;
+ unsigned int bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+ unsigned int sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+
+ // For voice calls use default configuration
+ // force routing is not required here, caller will do it anyway
+ if (voice_is_in_call(adev) || adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
+ ALOGW("%s:Use default bw and sr for voice/voip calls ",__func__);
+ bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+ sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+ } else {
+ /*
+ * The backend should be configured at highest bit width and/or
+ * sample rate amongst all playback usecases.
+ * If the selected sample rate and/or bit width differ with
+ * current backend sample rate and/or bit width, then, we set the
+ * backend re-configuration flag.
+ *
+ * Exception: 16 bit playbacks is allowed through 16 bit/48 khz backend only
+ */
+ list_for_each(node, &adev->usecase_list) {
+ struct audio_usecase *curr_usecase;
+ curr_usecase = node_to_item(node, struct audio_usecase, list);
+ if (curr_usecase->type == PCM_PLAYBACK) {
+ struct stream_out *out =
+ (struct stream_out*) curr_usecase->stream.out;
+ if (out != NULL ) {
+ ALOGV("Offload playback running bw %d sr %d",
+ out->bit_width, out->sample_rate);
+ if (bit_width < out->bit_width)
+ bit_width = out->bit_width;
+ if (sample_rate < out->sample_rate)
+ sample_rate = out->sample_rate;
+ }
+ }
+ }
+ }
+
+ // 16 bit playback on speakers is allowed through 48 khz backend only
+ if (16 == bit_width) {
+ sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+ }
+ // 24 bit playback on speakers is allowed through 48 khz backend only
+ // bit width re-configured based on platform info
+ if ((24 == bit_width) &&
+ (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER)) {
+ bit_width = (uint32_t)platform_get_snd_device_bit_width(SND_DEVICE_OUT_SPEAKER);
+ sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+ }
+ // Force routing if the expected bitwdith or samplerate
+ // is not same as current backend comfiguration
+ if ((bit_width != adev->cur_codec_backend_bit_width) ||
+ (sample_rate != adev->cur_codec_backend_samplerate)) {
+ *new_bit_width = bit_width;
+ *new_sample_rate = sample_rate;
+ backend_change = true;
+ ALOGI("%s Codec backend needs to be updated. new bit width: %d new sample rate: %d",
+ __func__, *new_bit_width, *new_sample_rate);
+ }
+
+ return backend_change;
+}
+
+bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase)
+{
+ ALOGV("platform_check_and_set_codec_backend_cfg usecase = %d",usecase->id );
+
+ unsigned int new_bit_width, old_bit_width;
+ unsigned int new_sample_rate, old_sample_rate;
+
+ new_bit_width = old_bit_width = adev->cur_codec_backend_bit_width;
+ new_sample_rate = old_sample_rate = adev->cur_codec_backend_samplerate;
+
+ ALOGW("Codec backend bitwidth %d, samplerate %d", old_bit_width, old_sample_rate);
+ if (platform_check_codec_backend_cfg(adev, usecase,
+ &new_bit_width, &new_sample_rate)) {
+ platform_set_codec_backend_cfg(adev, new_bit_width, new_sample_rate);
+ return true;
+ }
+
+ return false;
+}
+
+int platform_set_snd_device_backend(snd_device_t device, const char *backend)
+{
+ int ret = 0;
+
+ if ((device < SND_DEVICE_MIN) || (device >= SND_DEVICE_MAX)) {
+ ALOGE("%s: Invalid snd_device = %d",
+ __func__, device);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (backend_table[device]) {
+ free(backend_table[device]);
+ }
+ backend_table[device] = strdup(backend);
+done:
+ return ret;
+}
+
+int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t pcm_id)
+{
+ int ret = 0;
+ if ((usecase <= USECASE_INVALID) || (usecase >= AUDIO_USECASE_MAX)) {
+ ALOGE("%s: invalid usecase case idx %d", __func__, usecase);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((type != 0) && (type != 1)) {
+ ALOGE("%s: invalid usecase type", __func__);
+ ret = -EINVAL;
+ }
+ pcm_device_table[usecase][type] = pcm_id;
+done:
+ return ret;
+}
+
void platform_get_device_to_be_id_map(int **device_to_be_id, int *length)
{
*device_to_be_id = msm_device_to_be_id;
*length = msm_be_id_array_len;
}
+int platform_set_stream_channel_map(void *platform, audio_channel_mask_t channel_mask, int snd_id)
+{
+ int ret = 0;
+ int channels = audio_channel_count_from_out_mask(channel_mask);
-bool platform_check_24_bit_support() {
+ char channel_map[8];
+ memset(channel_map, 0, sizeof(channel_map));
+ /* Following are all most common standard WAV channel layouts
+ overridden by channel mask if its allowed and different */
+ switch (channels) {
+ case 1:
+ /* AUDIO_CHANNEL_OUT_MONO */
+ channel_map[0] = PCM_CHANNEL_FC;
+ break;
+ case 2:
+ /* AUDIO_CHANNEL_OUT_STEREO */
+ channel_map[0] = PCM_CHANNEL_FL;
+ channel_map[1] = PCM_CHANNEL_FR;
+ break;
+ case 3:
+ /* AUDIO_CHANNEL_OUT_2POINT1 */
+ channel_map[0] = PCM_CHANNEL_FL;
+ channel_map[1] = PCM_CHANNEL_FR;
+ channel_map[2] = PCM_CHANNEL_FC;
+ break;
+ case 4:
+ /* AUDIO_CHANNEL_OUT_QUAD_SIDE */
+ channel_map[0] = PCM_CHANNEL_FL;
+ channel_map[1] = PCM_CHANNEL_FR;
+ channel_map[2] = PCM_CHANNEL_LS;
+ channel_map[3] = PCM_CHANNEL_RS;
+ if (channel_mask == AUDIO_CHANNEL_OUT_QUAD_BACK)
+ {
+ channel_map[2] = PCM_CHANNEL_LB;
+ channel_map[3] = PCM_CHANNEL_RB;
+ }
+ if (channel_mask == AUDIO_CHANNEL_OUT_SURROUND)
+ {
+ channel_map[2] = PCM_CHANNEL_FC;
+ channel_map[3] = PCM_CHANNEL_CS;
+ }
+ break;
+ case 5:
+ /* AUDIO_CHANNEL_OUT_PENTA */
+ channel_map[0] = PCM_CHANNEL_FL;
+ channel_map[1] = PCM_CHANNEL_FR;
+ channel_map[2] = PCM_CHANNEL_FC;
+ channel_map[3] = PCM_CHANNEL_LB;
+ channel_map[4] = PCM_CHANNEL_RB;
+ break;
+ case 6:
+ /* AUDIO_CHANNEL_OUT_5POINT1 */
+ channel_map[0] = PCM_CHANNEL_FL;
+ channel_map[1] = PCM_CHANNEL_FR;
+ channel_map[2] = PCM_CHANNEL_FC;
+ channel_map[3] = PCM_CHANNEL_LFE;
+ channel_map[4] = PCM_CHANNEL_LB;
+ channel_map[5] = PCM_CHANNEL_RB;
+ if (channel_mask == AUDIO_CHANNEL_OUT_5POINT1_SIDE)
+ {
+ channel_map[4] = PCM_CHANNEL_LS;
+ channel_map[5] = PCM_CHANNEL_RS;
+ }
+ break;
+ case 7:
+ /* AUDIO_CHANNEL_OUT_6POINT1 */
+ channel_map[0] = PCM_CHANNEL_FL;
+ channel_map[1] = PCM_CHANNEL_FR;
+ channel_map[2] = PCM_CHANNEL_FC;
+ channel_map[3] = PCM_CHANNEL_LFE;
+ channel_map[4] = PCM_CHANNEL_LB;
+ channel_map[5] = PCM_CHANNEL_RB;
+ channel_map[6] = PCM_CHANNEL_CS;
+ break;
+ case 8:
+ /* AUDIO_CHANNEL_OUT_7POINT1 */
+ channel_map[0] = PCM_CHANNEL_FL;
+ channel_map[1] = PCM_CHANNEL_FR;
+ channel_map[2] = PCM_CHANNEL_FC;
+ channel_map[3] = PCM_CHANNEL_LFE;
+ channel_map[4] = PCM_CHANNEL_LB;
+ channel_map[5] = PCM_CHANNEL_RB;
+ channel_map[6] = PCM_CHANNEL_LS;
+ channel_map[7] = PCM_CHANNEL_RS;
+ break;
+ default:
+ ALOGE("unsupported channels %d for setting channel map", channels);
+ return -1;
+ }
+ ret = platform_set_channel_map(platform, channels, channel_map, snd_id);
+ return ret;
+}
+
+int platform_get_edid_info(void *platform)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ char block[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE];
+ char *sad = block;
+ int num_audio_blocks;
+ int channel_count = 2;
+ int i, ret, count;
+
+ struct mixer_ctl *ctl;
+ char edid_data[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE + 1] = {0};
+ edid_audio_info *info;
+
+ if (my_data->edid_valid) {
+ /* use cached edid */
+ return 0;
+ }
+
+ if (my_data->edid_info == NULL) {
+ my_data->edid_info =
+ (struct edid_audio_info *)calloc(1, sizeof(struct edid_audio_info));
+ }
+
+ info = my_data->edid_info;
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, AUDIO_DATA_BLOCK_MIXER_CTL);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, AUDIO_DATA_BLOCK_MIXER_CTL);
+ goto fail;
+ }
+
+ mixer_ctl_update(ctl);
+
+ count = mixer_ctl_get_num_values(ctl);
+
+ /* Read SAD blocks, clamping the maximum size for safety */
+ if (count > (int)sizeof(block))
+ count = (int)sizeof(block);
+
+ ret = mixer_ctl_get_array(ctl, block, count);
+ if (ret != 0) {
+ ALOGE("%s: mixer_ctl_get_array() failed to get EDID info", __func__);
+ goto fail;
+ }
+ edid_data[0] = count;
+ memcpy(&edid_data[1], block, count);
+
+#ifdef AUDIO_FEATURE_ENABLED_HDMI_EDID
+ if (!edid_get_sink_caps(info, edid_data)) {
+ ALOGE("%s: Failed to get HDMI sink capabilities", __func__);
+ goto fail;
+ }
+ my_data->edid_valid = true;
+ return 0;
+#endif
+fail:
+ if (my_data->edid_info) {
+ free(my_data->edid_info);
+ my_data->edid_info = NULL;
+ my_data->edid_valid = false;
+ }
+ ALOGE("%s: return -EINVAL", __func__);
+ return -EINVAL;
+}
+
+
+int platform_set_channel_allocation(void *platform, int channel_alloc)
+{
+ struct mixer_ctl *ctl;
+ const char *mixer_ctl_name = "HDMI RX CA";
+ int ret;
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ ret = EINVAL;
+ }
+ ALOGD(":%s channel allocation = 0x%x", __func__, channel_alloc);
+ ret = mixer_ctl_set_value(ctl, 0, channel_alloc);
+
+ if (ret < 0) {
+ ALOGE("%s: Could not set ctl, error:%d ", __func__, ret);
+ }
+
+ return ret;
+}
+
+int platform_set_channel_map(void *platform, int ch_count, char *ch_map, int snd_id)
+{
+ struct mixer_ctl *ctl;
+ char mixer_ctl_name[44]; // max length of name is 44 as defined
+ int ret;
+ unsigned int i;
+ int set_values[8] = {0};
+ char device_num[13]; // device number up to 2 digit
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ ALOGV("%s channel_count:%d",__func__, ch_count);
+ if (NULL == ch_map) {
+ ALOGE("%s: Invalid channel mapping used", __func__);
+ return -EINVAL;
+ }
+ strlcpy(mixer_ctl_name, "Playback Channel Map", sizeof(mixer_ctl_name));
+ if (snd_id >= 0) {
+ snprintf(device_num, sizeof(device_num), "%d", snd_id);
+ strncat(mixer_ctl_name, device_num, 13);
+ }
+
+ ALOGD("%s mixer_ctl_name:%s", __func__, mixer_ctl_name);
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+ for (i = 0; i< ARRAY_SIZE(set_values); i++) {
+ set_values[i] = ch_map[i];
+ }
+
+ ALOGD("%s: set mapping(%d %d %d %d %d %d %d %d) for channel:%d", __func__,
+ set_values[0], set_values[1], set_values[2], set_values[3], set_values[4],
+ set_values[5], set_values[6], set_values[7], ch_count);
+
+ ret = mixer_ctl_set_array(ctl, set_values, ch_count);
+ if (ret < 0) {
+ ALOGE("%s: Could not set ctl, error:%d ch_count:%d",
+ __func__, ret, ch_count);
+ }
+ return ret;
+}
+
+unsigned char platform_map_to_edid_format(int audio_format)
+{
+ unsigned char format;
+ switch (audio_format & AUDIO_FORMAT_MAIN_MASK) {
+ case AUDIO_FORMAT_AC3:
+ ALOGV("%s: AC3", __func__);
+ format = AC3;
+ break;
+ case AUDIO_FORMAT_AAC:
+ ALOGV("%s:AAC", __func__);
+ format = AAC;
+ break;
+ case AUDIO_FORMAT_E_AC3:
+ ALOGV("%s:E_AC3", __func__);
+ format = DOLBY_DIGITAL_PLUS;
+ break;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ case AUDIO_FORMAT_PCM_16_BIT_OFFLOAD:
+ case AUDIO_FORMAT_PCM_24_BIT_OFFLOAD:
+ default:
+ ALOGV("%s:PCM", __func__);
+ format = LPCM;
+ break;
+ }
+ return format;
+}
+
+uint32_t platform_get_compress_passthrough_buffer_size(
+ audio_offload_info_t* info)
+{
+ uint32_t fragment_size = MIN_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE;
+ if (!info->has_video)
+ fragment_size = MIN_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE;
+
+ return fragment_size;
+}
+
+void platform_reset_edid_info(void *platform) {
+
+ ALOGV("%s:", __func__);
+ struct platform_data *my_data = (struct platform_data *)platform;
+ if (my_data->edid_info) {
+ ALOGV("%s :free edid", __func__);
+ free(my_data->edid_info);
+ my_data->edid_info = NULL;
+ }
+}
+
+bool platform_is_edid_supported_format(void *platform, int format)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ edid_audio_info *info = NULL;
+ int num_audio_blocks;
+ int i, ret, count;
+ unsigned char format_id = platform_map_to_edid_format(format);
+
+ ret = platform_get_edid_info(platform);
+ info = (edid_audio_info *)my_data->edid_info;
+ if (ret == 0 && info != NULL) {
+ for (i = 0; i < info->audio_blocks && i < MAX_EDID_BLOCKS; i++) {
+ /*
+ * To check
+ * is there any special for CONFIG_HDMI_PASSTHROUGH_CONVERT
+ * & DOLBY_DIGITAL_PLUS
+ */
+ if (info->audio_blocks_array[i].format_id == format_id) {
+ ALOGV("%s:platform_is_edid_supported_format true %x",
+ __func__, format);
+ return true;
+ }
+ }
+ }
+ ALOGV("%s:platform_is_edid_supported_format false %x",
+ __func__, format);
return false;
}
-bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev __unused,
- struct audio_usecase *usecase __unused)
-{
- return false;
-}
+int platform_set_edid_channels_configuration(void *platform, int channels) {
-int platform_get_usecase_index(const char * usecase __unused)
-{
- return -ENOSYS;
-}
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ edid_audio_info *info = NULL;
+ int num_audio_blocks;
+ int channel_count = 2;
+ int i, ret, count;
+ char default_channelMap[MAX_CHANNELS_SUPPORTED] = {0};
-int platform_set_usecase_pcm_id(audio_usecase_t usecase __unused, int32_t type __unused,
- int32_t pcm_id __unused)
-{
- return -ENOSYS;
-}
+ ret = platform_get_edid_info(platform);
+ info = (edid_audio_info *)my_data->edid_info;
+ if(ret == 0 && info != NULL) {
+ if (channels > 2) {
-int platform_set_snd_device_backend(snd_device_t snd_device __unused,
- const char * backend __unused)
-{
- return -ENOSYS;
-}
-int platform_get_edid_info(void *platform __unused)
-{
- return -ENOSYS;
-}
+ ALOGV("%s:able to get HDMI sink capabilities multi channel playback",
+ __func__);
+ for (i = 0; i < info->audio_blocks && i < MAX_EDID_BLOCKS; i++) {
+ if (info->audio_blocks_array[i].format_id == LPCM &&
+ info->audio_blocks_array[i].channels > channel_count &&
+ info->audio_blocks_array[i].channels <= MAX_HDMI_CHANNEL_CNT) {
+ channel_count = info->audio_blocks_array[i].channels;
+ }
+ }
+ ALOGV("%s:channel_count:%d", __func__, channel_count);
+ /*
+ * Channel map is set for supported hdmi max channel count even
+ * though the input channel count set on adm is less than or equal to
+ * max supported channel count
+ */
+ platform_set_channel_map(platform, channel_count, info->channel_map, -1);
+ platform_set_channel_allocation(platform, info->channel_allocation);
+ } else {
+ default_channelMap[0] = PCM_CHANNEL_FL;
+ default_channelMap[1] = PCM_CHANNEL_FR;
+ platform_set_channel_map(platform,2,default_channelMap,-1);
+ platform_set_channel_allocation(platform,0);
+ }
+ }
-int platform_set_channel_map(void *platform __unused, int ch_count __unused,
- char *ch_map __unused, int snd_id __unused)
-{
- return -ENOSYS;
-}
-
-int platform_set_stream_channel_map(void *platform __unused,
- audio_channel_mask_t channel_mask __unused,
- int snd_id __unused)
-{
- return -ENOSYS;
-}
-
-int platform_set_edid_channels_configuration(void *platform __unused,
- int channels __unused)
-{
return 0;
}
-void platform_cache_edid(void * platform __unused)
+void platform_cache_edid(void * platform)
{
+ platform_get_edid_info(platform);
}
-void platform_invalidate_edid(void * platform __unused)
+void platform_invalidate_edid(void * platform)
{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ my_data->edid_valid = false;
+ if (my_data->edid_info) {
+ memset(my_data->edid_info, 0, sizeof(struct edid_audio_info));
+ }
}
+
+int platform_set_mixer_control(struct stream_out *out, const char * mixer_ctl_name,
+ const char *mixer_val)
+{
+ struct audio_device *adev = out->dev;
+ struct mixer_ctl *ctl = NULL;
+ ALOGD("setting mixer ctl %s with value %s", mixer_ctl_name, mixer_val);
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+
+ return mixer_ctl_set_enum_by_string(ctl, mixer_val);
+}
+
+int platform_set_hdmi_config(struct stream_out *out)
+{
+ struct listnode *node;
+ struct audio_usecase *usecase;
+ struct audio_device *adev = out->dev;
+ const char *hdmi_format_ctrl = "HDMI RX Format";
+ const char *hdmi_rate_ctrl = "HDMI_RX SampleRate";
+ int sample_rate = out->sample_rate;
+ /*TODO: Add rules and check if this needs to be done.*/
+ if((is_offload_usecase(out->usecase)) &&
+ (out->compr_config.codec->compr_passthr == PASSTHROUGH ||
+ out->compr_config.codec->compr_passthr == PASSTHROUGH_CONVERT)) {
+ /* TODO: can we add mixer control for channels here avoid setting */
+ if ((out->format == AUDIO_FORMAT_E_AC3 ||
+ out->format == AUDIO_FORMAT_E_AC3_JOC) &&
+ (out->compr_config.codec->compr_passthr == PASSTHROUGH))
+ sample_rate = out->sample_rate * 4;
+ ALOGD("%s:HDMI compress format and samplerate %d, sample_rate %d",
+ __func__, out->sample_rate, sample_rate);
+ platform_set_mixer_control(out, hdmi_format_ctrl, "Compr");
+ switch (sample_rate) {
+ case 32000:
+ platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_32");
+ break;
+ case 44100:
+ platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_44_1");
+ break;
+ case 96000:
+ platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_96");
+ break;
+ case 176400:
+ platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_176_4");
+ break;
+ case 192000:
+ platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_192");
+ break;
+ case 128000:
+ if (out->format != AUDIO_FORMAT_E_AC3) {
+ platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_128");
+ break;
+ } else
+ ALOGW("Unsupported sample rate for E_AC3 32K");
+ default:
+ case 48000:
+ platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_48");
+ break;
+ }
+ } else {
+ ALOGD("%s: HDMI pcm and samplerate %d", __func__,
+ out->sample_rate);
+ platform_set_mixer_control(out, hdmi_format_ctrl, "LPCM");
+ platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_48");
+ }
+
+ /*
+ * Deroute all the playback streams routed to HDMI so that
+ * the back end is deactivated. Note that backend will not
+ * be deactivated if any one stream is connected to it.
+ */
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ ALOGV("%s:disable: usecase type %d, devices 0x%x", __func__,
+ usecase->type, usecase->devices);
+ if (usecase->type == PCM_PLAYBACK &&
+ usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+ disable_audio_route(adev, usecase);
+ }
+ }
+
+ /*
+ * Enable all the streams disabled above. Now the HDMI backend
+ * will be activated with new channel configuration
+ */
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ ALOGV("%s:enable: usecase type %d, devices 0x%x", __func__,
+ usecase->type, usecase->devices);
+ if (usecase->type == PCM_PLAYBACK &&
+ usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+ enable_audio_route(adev, usecase);
+ }
+ }
+
+ return 0;
+}
+
+int platform_set_device_params(struct stream_out *out, int param, int value)
+{
+ struct audio_device *adev = out->dev;
+ struct mixer_ctl *ctl;
+ char *mixer_ctl_name = "Device PP Params";
+ int ret = 0;
+ uint32_t set_values[] = {0,0};
+
+ set_values[0] = param;
+ set_values[1] = value;
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ ALOGV("%s: Setting device pp params param: %d, value %d mixer ctrl:%s",
+ __func__,param, value, mixer_ctl_name);
+ mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+end:
+ return ret;
+}
+
int platform_get_subsys_image_name(char *buf)
{
strlcpy(buf, PLATFORM_IMAGE_NAME, sizeof(PLATFORM_IMAGE_NAME));
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index 1cdb013..7e87a3c 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -55,11 +55,17 @@
SND_DEVICE_OUT_BEGIN = SND_DEVICE_MIN,
SND_DEVICE_OUT_HANDSET = SND_DEVICE_OUT_BEGIN,
SND_DEVICE_OUT_SPEAKER,
+ SND_DEVICE_OUT_SPEAKER_EXTERNAL_1,
+ SND_DEVICE_OUT_SPEAKER_EXTERNAL_2,
SND_DEVICE_OUT_SPEAKER_REVERSE,
+ SND_DEVICE_OUT_SPEAKER_WSA,
SND_DEVICE_OUT_HEADPHONES,
SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+ SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1,
+ SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2,
SND_DEVICE_OUT_VOICE_HANDSET,
SND_DEVICE_OUT_VOICE_SPEAKER,
+ SND_DEVICE_OUT_VOICE_SPEAKER_WSA,
SND_DEVICE_OUT_VOICE_HEADPHONES,
SND_DEVICE_OUT_HDMI,
SND_DEVICE_OUT_SPEAKER_AND_HDMI,
@@ -80,6 +86,7 @@
SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
SND_DEVICE_OUT_ANC_HANDSET,
SND_DEVICE_OUT_SPEAKER_PROTECTED,
+ SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED,
#ifdef RECORD_PLAY_CONCURRENCY
SND_DEVICE_OUT_VOIP_HANDSET,
SND_DEVICE_OUT_VOIP_SPEAKER,
@@ -94,6 +101,7 @@
/* Capture devices */
SND_DEVICE_IN_BEGIN = SND_DEVICE_OUT_END,
SND_DEVICE_IN_HANDSET_MIC = SND_DEVICE_IN_BEGIN,
+ SND_DEVICE_IN_HANDSET_MIC_EXTERNAL,
SND_DEVICE_IN_HANDSET_MIC_AEC,
SND_DEVICE_IN_HANDSET_MIC_NS,
SND_DEVICE_IN_HANDSET_MIC_AEC_NS,
@@ -156,7 +164,7 @@
#define DEFAULT_OUTPUT_SAMPLING_RATE 48000
#define ALL_SESSION_VSID 0xFFFFFFFF
-#define DEFAULT_MUTE_RAMP_DURATION 500
+#define DEFAULT_MUTE_RAMP_DURATION_MS 20
#define DEFAULT_VOLUME_RAMP_DURATION_MS 20
#define MIXER_PATH_MAX_LENGTH 100
@@ -174,7 +182,7 @@
* the buffer size of an input/output stream
*/
#define DEEP_BUFFER_OUTPUT_PERIOD_SIZE 960
-#define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 4
+#define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 5
#define LOW_LATENCY_OUTPUT_PERIOD_SIZE 240
#define LOW_LATENCY_OUTPUT_PERIOD_COUNT 2
@@ -190,6 +198,10 @@
#define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20
#define AUDIO_CAPTURE_PERIOD_COUNT 2
+#define LOW_LATENCY_CAPTURE_SAMPLE_RATE 48000
+#define LOW_LATENCY_CAPTURE_PERIOD_SIZE 240
+#define LOW_LATENCY_CAPTURE_USE_CASE 1
+
#define DEVICE_NAME_MAX_SIZE 128
#define HW_INFO_ARRAY_MAX_SIZE 32
@@ -207,6 +219,18 @@
#define SPKR_PROT_CALIB_RX_PCM_DEVICE 5
#define SPKR_PROT_CALIB_TX_PCM_DEVICE 22
#define PLAYBACK_OFFLOAD_DEVICE 9
+
+#ifdef MULTIPLE_OFFLOAD_ENABLED
+#define PLAYBACK_OFFLOAD_DEVICE2 17
+#define PLAYBACK_OFFLOAD_DEVICE3 18
+#define PLAYBACK_OFFLOAD_DEVICE4 37
+#define PLAYBACK_OFFLOAD_DEVICE5 38
+#define PLAYBACK_OFFLOAD_DEVICE6 39
+#define PLAYBACK_OFFLOAD_DEVICE7 40
+#define PLAYBACK_OFFLOAD_DEVICE8 41
+#define PLAYBACK_OFFLOAD_DEVICE9 42
+#endif
+
#define COMPRESS_VOIP_CALL_PCM_DEVICE 3
/* Define macro for Internal FM volume mixer */
@@ -219,7 +243,7 @@
#define VOICE_CALL_PCM_DEVICE 2
#define VOICE2_CALL_PCM_DEVICE 13
#define VOLTE_CALL_PCM_DEVICE 15
-#define QCHAT_CALL_PCM_DEVICE 14
+#define QCHAT_CALL_PCM_DEVICE 26
#define VOWLAN_CALL_PCM_DEVICE 16
#define AFE_PROXY_PLAYBACK_PCM_DEVICE 7
@@ -232,8 +256,8 @@
typedef int (*disable_device_t)();
typedef int (*enable_device_config_t)(int, int);
typedef int (*enable_device_t)(int, int, uint32_t);
-typedef int (*volume_t)(uint32_t, int);
-typedef int (*mic_mute_t)(uint32_t, int);
+typedef int (*volume_t)(uint32_t, int, uint16_t);
+typedef int (*mic_mute_t)(uint32_t, int, uint16_t);
typedef int (*slow_talk_t)(uint32_t, uint8_t);
typedef int (*start_voice_t)(uint32_t);
typedef int (*stop_voice_t)(uint32_t);
@@ -264,4 +288,16 @@
int platform_get_subsys_image_name (char *buf);
+/* HDMI Passthrough defines */
+enum {
+ LEGACY_PCM = 0,
+ PASSTHROUGH,
+ PASSTHROUGH_CONVERT
+};
+/*
+ * ID for setting mute and lateny on the device side
+ * through Device PP Params mixer control.
+ */
+#define DEVICE_PARAM_MUTE_ID 0
+#define DEVICE_PARAM_LATENCY_ID 1
#endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/msm8974/hw_info.c b/hal/msm8974/hw_info.c
index e5ab181..c96d11e 100644
--- a/hal/msm8974/hw_info.c
+++ b/hal/msm8974/hw_info.c
@@ -87,7 +87,7 @@
SND_DEVICE_IN_HANDSET_MIC,
};
-static const snd_device_t tomtom_thulium_CDP_variant_devices[] = {
+static const snd_device_t tomtom_8996_CDP_variant_devices[] = {
};
static const snd_device_t tomtom_liquid_variant_devices[] = {
@@ -252,34 +252,34 @@
}
}
-static void update_hardware_info_thulium(struct hardware_info *hw_info, const char *snd_card_name)
+static void update_hardware_info_8996(struct hardware_info *hw_info, const char *snd_card_name)
{
- if (!strcmp(snd_card_name, "thulium-tomtom-mtp-snd-card")) {
+ if (!strcmp(snd_card_name, "msm8996-tomtom-mtp-snd-card")) {
strlcpy(hw_info->type, " mtp", sizeof(hw_info->type));
- strlcpy(hw_info->name, "thulium", sizeof(hw_info->name));
+ strlcpy(hw_info->name, "msm8996", sizeof(hw_info->name));
hw_info->snd_devices = NULL;
hw_info->num_snd_devices = 0;
strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
- } else if (!strcmp(snd_card_name, "thulium-tomtom-cdp-snd-card")) {
+ } else if (!strcmp(snd_card_name, "msm8996-tomtom-cdp-snd-card")) {
strlcpy(hw_info->type, " cdp", sizeof(hw_info->type));
- strlcpy(hw_info->name, "thulium", sizeof(hw_info->name));
- hw_info->snd_devices = (snd_device_t *)tomtom_thulium_CDP_variant_devices;
- hw_info->num_snd_devices = ARRAY_SIZE(tomtom_thulium_CDP_variant_devices);
+ strlcpy(hw_info->name, "msm8996", sizeof(hw_info->name));
+ hw_info->snd_devices = (snd_device_t *)tomtom_8996_CDP_variant_devices;
+ hw_info->num_snd_devices = ARRAY_SIZE(tomtom_8996_CDP_variant_devices);
strlcpy(hw_info->dev_extn, "-cdp", sizeof(hw_info->dev_extn));
- } else if (!strcmp(snd_card_name, "thulium-tomtom-stp-snd-card")) {
+ } else if (!strcmp(snd_card_name, "msm8996-tomtom-stp-snd-card")) {
strlcpy(hw_info->type, " stp", sizeof(hw_info->type));
- strlcpy(hw_info->name, "thulium", sizeof(hw_info->name));
+ strlcpy(hw_info->name, "msm8996", sizeof(hw_info->name));
hw_info->snd_devices = (snd_device_t *)tomtom_stp_variant_devices;
hw_info->num_snd_devices = ARRAY_SIZE(tomtom_stp_variant_devices);
strlcpy(hw_info->dev_extn, "-stp", sizeof(hw_info->dev_extn));
- } else if (!strcmp(snd_card_name, "thulium-tomtom-liquid-snd-card")) {
+ } else if (!strcmp(snd_card_name, "msm8996-tomtom-liquid-snd-card")) {
strlcpy(hw_info->type, " liquid", sizeof(hw_info->type));
- strlcpy(hw_info->name, "thulium", sizeof(hw_info->name));
+ strlcpy(hw_info->name, "msm8996", sizeof(hw_info->name));
hw_info->snd_devices = (snd_device_t *)tomtom_liquid_variant_devices;
hw_info->num_snd_devices = ARRAY_SIZE(tomtom_liquid_variant_devices);
strlcpy(hw_info->dev_extn, "-liquid", sizeof(hw_info->dev_extn));
} else {
- ALOGW("%s: Not a thulium device", __func__);
+ ALOGW("%s: Not a 8996 device", __func__);
}
}
@@ -408,9 +408,9 @@
} else if(strstr(snd_card_name, "msm8994")) {
ALOGV("8994 - variant soundcard");
update_hardware_info_8994(hw_info, snd_card_name);
- } else if(strstr(snd_card_name, "thulium")) {
- ALOGV("thulium - variant soundcard");
- update_hardware_info_thulium(hw_info, snd_card_name);
+ } else if(strstr(snd_card_name, "msm8996")) {
+ ALOGV("8996 - variant soundcard");
+ update_hardware_info_8996(hw_info, snd_card_name);
} else {
ALOGE("%s: Unsupported target %s:",__func__, snd_card_name);
free(hw_info);
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 635bcb7..dcabaf8 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -79,7 +79,8 @@
#define MIN_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE (2 * 1024)
#define MAX_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE (8 * 1024)
-#define ALIGN( num, to ) (((num) + (to-1)) & (~(to-1)))
+#define DIV_ROUND_UP(x, y) (((x) + (y) - 1)/(y))
+#define ALIGN(x, y) ((y) * DIV_ROUND_UP((x), (y)))
/*
* This file will have a maximum of 38 bytes:
*
@@ -2489,6 +2490,12 @@
int ret = 0, err;
char *kv_pairs = str_parms_to_str(parms);
+ if(kv_pairs == NULL) {
+ ret = -ENOMEM;
+ ALOGE("[%s] key-value pair is NULL",__func__);
+ goto done;
+ }
+
ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs);
len = strlen(kv_pairs);
@@ -2568,7 +2575,8 @@
done:
ALOGV("%s: exit with code(%d)", __func__, ret);
- free(kv_pairs);
+ if(kv_pairs != NULL)
+ free(kv_pairs);
if(value != NULL)
free(value);
return ret;
@@ -2935,8 +2943,11 @@
* info->sample_rate
* (bits_per_sample >> 3)
* popcount(info->channel_mask))/1000;
- // align with LCM of 2, 4, 6, 8
- fragment_size = ALIGN( fragment_size, 24 );
+ // To have same PCM samples for all channels, the buffer size requires to
+ // be multiple of (number of channels * bytes per sample)
+ // For writes to succeed, the buffer must be written at address which is multiple of 32
+ // Alignment of 96 satsfies both of the above requirements
+ fragment_size = ALIGN(fragment_size, 96);
if(fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE)
fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
else if(fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE)
@@ -3355,10 +3366,15 @@
ALOGE("%s: Invalid channel mapping used", __func__);
return -EINVAL;
}
- strlcpy(mixer_ctl_name, "Playback Channel Map", sizeof(mixer_ctl_name));
+
+ /*
+ * If snd_id is greater than 0, stream channel mapping
+ * If snd_id is below 0, typically -1, device channel mapping
+ */
if (snd_id >= 0) {
- snprintf(device_num, sizeof(device_num), "%d", snd_id);
- strncat(mixer_ctl_name, device_num, 13);
+ snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "Playback Channel Map%d", snd_id);
+ } else {
+ strlcpy(mixer_ctl_name, "Playback Device Channel Map", sizeof(mixer_ctl_name));
}
ALOGD("%s mixer_ctl_name:%s", __func__, mixer_ctl_name);
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 552dd41..42725fb 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -229,7 +229,7 @@
#define PLAYBACK_OFFLOAD_DEVICE8 38
#define PLAYBACK_OFFLOAD_DEVICE9 39
#endif
-#if defined (PLATFORM_MSM8994) || defined (PLATFORM_THULIUM)
+#if defined (PLATFORM_MSM8994) || defined (PLATFORM_MSM8996)
#define PLAYBACK_OFFLOAD_DEVICE2 17
#define PLAYBACK_OFFLOAD_DEVICE3 18
#define PLAYBACK_OFFLOAD_DEVICE4 37
@@ -303,7 +303,7 @@
#define FM_RX_VOLUME "Quat MI2S FM RX Volume"
#elif PLATFORM_MSM8994
#define FM_RX_VOLUME "PRI MI2S LOOPBACK Volume"
-#elif PLATFORM_THULIUM
+#elif PLATFORM_MSM8996
#define FM_RX_VOLUME "Tert MI2S LOOPBACK Volume"
#else
#define FM_RX_VOLUME "Internal FM RX Volume"
diff --git a/hal/voice.c b/hal/voice.c
index 5bc0a4e..9fc1081 100644
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -157,6 +157,8 @@
}
ALOGD("voice_config.rate %d\n", voice_config.rate);
+ voice_set_mic_mute(adev, adev->voice.mic_mute);
+
ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
__func__, adev->snd_card, pcm_dev_rx_id);
session->pcm_rx = pcm_open(adev->snd_card,
@@ -293,6 +295,18 @@
session_id, rec_mode);
ALOGV("%s: Update usecase to %d",__func__, in->usecase);
} else {
+ /*
+ * Reject the recording instances, where the recording is started
+ * with In-call voice recording source types but voice call is not
+ * active by the time input is started
+ */
+ if ((in->source == AUDIO_SOURCE_VOICE_UPLINK) ||
+ (in->source == AUDIO_SOURCE_VOICE_DOWNLINK) ||
+ (in->source == AUDIO_SOURCE_VOICE_CALL)) {
+ ret = -EINVAL;
+ ALOGE("%s: As voice call is not active, Incall rec usecase can't be \
+ selected for requested source:%d",__func__, in->source);
+ }
ALOGV("%s: voice call not active", __func__);
}
diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c
index 26636db..14af6fc 100644
--- a/hal/voice_extn/compress_voip.c
+++ b/hal/voice_extn/compress_voip.c
@@ -328,6 +328,7 @@
int i, ret = 0;
struct audio_usecase *uc_info;
int pcm_dev_rx_id, pcm_dev_tx_id;
+ unsigned int flags = PCM_OUT | PCM_MONOTONIC;
ALOGD("%s: enter", __func__);
@@ -368,7 +369,7 @@
__func__, adev->snd_card, pcm_dev_rx_id);
voip_data.pcm_rx = pcm_open(adev->snd_card,
pcm_dev_rx_id,
- PCM_OUT, voip_config);
+ flags, voip_config);
if (voip_data.pcm_rx && !pcm_is_ready(voip_data.pcm_rx)) {
ALOGE("%s: %s", __func__, pcm_get_error(voip_data.pcm_rx));
pcm_close(voip_data.pcm_rx);
@@ -696,6 +697,10 @@
voip_data.sample_rate = in->config.rate;
}
+ ret = voip_set_mode(in->dev, in->format);
+ if (ret < 0)
+ goto done;
+
in->usecase = USECASE_COMPRESS_VOIP_CALL;
if (in->config.rate == 16000)
in->config = pcm_config_voip_wb;
@@ -703,7 +708,6 @@
in->config = pcm_config_voip_nb;
voip_data.in_stream_count++;
- ret = voip_set_mode(in->dev, in->format);
done:
ALOGV("%s: exit, ret=%d", __func__, ret);
diff --git a/post_proc/Android.mk b/post_proc/Android.mk
index 880838a..be70166 100644
--- a/post_proc/Android.mk
+++ b/post_proc/Android.mk
@@ -26,7 +26,8 @@
LOCAL_SHARED_LIBRARIES := \
libcutils \
liblog \
- libtinyalsa
+ libtinyalsa \
+ libdl
LOCAL_MODULE_TAGS := optional
diff --git a/post_proc/bass_boost.c b/post_proc/bass_boost.c
index 57cf8ef..ad1e7c9 100644
--- a/post_proc/bass_boost.c
+++ b/post_proc/bass_boost.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
* Not a Contribution.
*
* Copyright (C) 2013 The Android Open Source Project
@@ -17,14 +17,17 @@
* limitations under the License.
*/
-#define LOG_TAG "offload_effect_bass_boost"
+#define LOG_TAG "offload_effect_bass"
//#define LOG_NDEBUG 0
#include <cutils/list.h>
#include <cutils/log.h>
+#include <cutils/properties.h>
#include <tinyalsa/asoundlib.h>
#include <sound/audio_effects.h>
#include <audio_effects/effect_bassboost.h>
+#include <stdlib.h>
+#include <dlfcn.h>
#include "effect_api.h"
#include "bass_boost.h"
@@ -41,6 +44,243 @@
"The Android Open Source Project",
};
+#define LIB_ACDB_LOADER "libacdbloader.so"
+#define PBE_CONF_APP_ID 0x00011134
+
+enum {
+ AUDIO_DEVICE_CAL_TYPE = 0,
+ AUDIO_STREAM_CAL_TYPE,
+};
+
+typedef struct acdb_audio_cal_cfg {
+ uint32_t persist;
+ uint32_t snd_dev_id;
+ uint32_t dev_id;
+ int32_t acdb_dev_id;
+ uint32_t app_type;
+ uint32_t topo_id;
+ uint32_t sampling_rate;
+ uint32_t cal_type;
+ uint32_t module_id;
+ uint32_t param_id;
+} acdb_audio_cal_cfg_t;
+
+typedef int (*acdb_get_audio_cal_t) (void *, void *, uint32_t*);
+static int pbe_load_config(struct pbe_params *params);
+
+/*
+ * Bass operations
+ */
+int bass_get_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t *size)
+{
+ bass_context_t *bass_ctxt = (bass_context_t *)context;
+ int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+ int32_t *param_tmp = (int32_t *)p->data;
+ int32_t param = *param_tmp++;
+ void *value = p->data + voffset;
+ int i;
+
+ ALOGV("%s", __func__);
+
+ p->status = 0;
+
+ switch (param) {
+ case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
+ if (p->vsize < sizeof(uint32_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint32_t);
+ break;
+ case BASSBOOST_PARAM_STRENGTH:
+ if (p->vsize < sizeof(int16_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(int16_t);
+ break;
+ default:
+ p->status = -EINVAL;
+ }
+
+ *size = sizeof(effect_param_t) + voffset + p->vsize;
+
+ if (p->status != 0)
+ return 0;
+
+ switch (param) {
+ case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
+ ALOGV("%s: BASSBOOST_PARAM_STRENGTH_SUPPORTED", __func__);
+ if (bass_ctxt->active_index == BASS_BOOST)
+ *(uint32_t *)value = 1;
+ else
+ *(uint32_t *)value = 0;
+ break;
+
+ case BASSBOOST_PARAM_STRENGTH:
+ ALOGV("%s: BASSBOOST_PARAM_STRENGTH", __func__);
+ if (bass_ctxt->active_index == BASS_BOOST)
+ *(int16_t *)value = bassboost_get_strength(&(bass_ctxt->bassboost_ctxt));
+ else
+ *(int16_t *)value = 0;
+ break;
+
+ default:
+ p->status = -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+int bass_set_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t size __unused)
+{
+ bass_context_t *bass_ctxt = (bass_context_t *)context;
+ int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+ void *value = p->data + voffset;
+ int32_t *param_tmp = (int32_t *)p->data;
+ int32_t param = *param_tmp++;
+ uint32_t strength;
+
+ ALOGV("%s", __func__);
+
+ p->status = 0;
+
+ switch (param) {
+ case BASSBOOST_PARAM_STRENGTH:
+ ALOGV("%s BASSBOOST_PARAM_STRENGTH", __func__);
+ if (bass_ctxt->active_index == BASS_BOOST) {
+ strength = (uint32_t)(*(int16_t *)value);
+ bassboost_set_strength(&(bass_ctxt->bassboost_ctxt), strength);
+ } else {
+ /* stength supported only for BB and not for PBE, but do not
+ * return error for unsupported case, as it fails cts test
+ */
+ ALOGD("%s ignore set strength, index %d",
+ __func__, bass_ctxt->active_index);
+ break;
+ }
+ break;
+ default:
+ p->status = -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+int bass_set_device(effect_context_t *context, uint32_t device)
+{
+ bass_context_t *bass_ctxt = (bass_context_t *)context;
+
+ if (device == AUDIO_DEVICE_OUT_SPEAKER) {
+ bass_ctxt->active_index = BASS_PBE;
+ ALOGV("%s: set PBE mode, device: %x", __func__, device);
+ } else if (device == AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+ device == AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+ device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES) {
+ ALOGV("%s: set BB mode, device: %x", __func__, device);
+ bass_ctxt->active_index = BASS_BOOST;
+ } else {
+ ALOGI("%s: disabled by device: %x", __func__, device);
+ bass_ctxt->active_index = BASS_INVALID;
+ }
+
+ bassboost_set_device((effect_context_t *)&(bass_ctxt->bassboost_ctxt), device);
+ pbe_set_device((effect_context_t *)&(bass_ctxt->pbe_ctxt), device);
+
+ return 0;
+}
+
+int bass_reset(effect_context_t *context)
+{
+ bass_context_t *bass_ctxt = (bass_context_t *)context;
+
+ bassboost_reset((effect_context_t *)&(bass_ctxt->bassboost_ctxt));
+ pbe_reset((effect_context_t *)&(bass_ctxt->pbe_ctxt));
+
+ return 0;
+}
+
+int bass_init(effect_context_t *context)
+{
+ bass_context_t *bass_ctxt = (bass_context_t *)context;
+
+ // convery i/o channel config to sub effects
+ bass_ctxt->bassboost_ctxt.common.config = context->config;
+ bass_ctxt->pbe_ctxt.common.config = context->config;
+
+ ALOGV("%s", __func__);
+
+ bass_ctxt->active_index = BASS_BOOST;
+
+
+ bassboost_init((effect_context_t *)&(bass_ctxt->bassboost_ctxt));
+ pbe_init((effect_context_t *)&(bass_ctxt->pbe_ctxt));
+
+ return 0;
+}
+
+int bass_enable(effect_context_t *context)
+{
+ bass_context_t *bass_ctxt = (bass_context_t *)context;
+
+ ALOGV("%s", __func__);
+
+ bassboost_enable((effect_context_t *)&(bass_ctxt->bassboost_ctxt));
+ pbe_enable((effect_context_t *)&(bass_ctxt->pbe_ctxt));
+
+ return 0;
+}
+
+int bass_disable(effect_context_t *context)
+{
+ bass_context_t *bass_ctxt = (bass_context_t *)context;
+
+ ALOGV("%s", __func__);
+
+ bassboost_disable((effect_context_t *)&(bass_ctxt->bassboost_ctxt));
+ pbe_disable((effect_context_t *)&(bass_ctxt->pbe_ctxt));
+
+ return 0;
+}
+
+int bass_start(effect_context_t *context, output_context_t *output)
+{
+ bass_context_t *bass_ctxt = (bass_context_t *)context;
+
+ ALOGV("%s", __func__);
+
+ bassboost_start((effect_context_t *)&(bass_ctxt->bassboost_ctxt), output);
+ pbe_start((effect_context_t *)&(bass_ctxt->pbe_ctxt), output);
+
+ return 0;
+}
+
+int bass_stop(effect_context_t *context, output_context_t *output)
+{
+ bass_context_t *bass_ctxt = (bass_context_t *)context;
+
+ ALOGV("%s", __func__);
+
+ bassboost_stop((effect_context_t *)&(bass_ctxt->bassboost_ctxt), output);
+ pbe_stop((effect_context_t *)&(bass_ctxt->pbe_ctxt), output);
+
+ return 0;
+}
+
+int bass_set_mode(effect_context_t *context, int32_t hw_acc_fd)
+{
+ bass_context_t *bass_ctxt = (bass_context_t *)context;
+
+ ALOGV("%s", __func__);
+
+ bassboost_set_mode((effect_context_t *)&(bass_ctxt->bassboost_ctxt), hw_acc_fd);
+ pbe_set_mode((effect_context_t *)&(bass_ctxt->pbe_ctxt), hw_acc_fd);
+
+ return 0;
+}
+
+#undef LOG_TAG
+#define LOG_TAG "offload_effect_bb"
/*
* Bassboost operations
*/
@@ -70,99 +310,30 @@
return 0;
}
-int bassboost_get_parameter(effect_context_t *context, effect_param_t *p,
- uint32_t *size)
-{
- bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
- int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
- int32_t *param_tmp = (int32_t *)p->data;
- int32_t param = *param_tmp++;
- void *value = p->data + voffset;
- int i;
-
- ALOGV("%s: ctxt %p, param %d", __func__, bass_ctxt, param);
-
- p->status = 0;
-
- switch (param) {
- case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
- if (p->vsize < sizeof(uint32_t))
- p->status = -EINVAL;
- p->vsize = sizeof(uint32_t);
- break;
- case BASSBOOST_PARAM_STRENGTH:
- if (p->vsize < sizeof(int16_t))
- p->status = -EINVAL;
- p->vsize = sizeof(int16_t);
- break;
- default:
- p->status = -EINVAL;
- }
-
- *size = sizeof(effect_param_t) + voffset + p->vsize;
-
- if (p->status != 0)
- return 0;
-
- switch (param) {
- case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
- *(uint32_t *)value = 1;
- break;
-
- case BASSBOOST_PARAM_STRENGTH:
- *(int16_t *)value = bassboost_get_strength(bass_ctxt);
- break;
-
- default:
- p->status = -EINVAL;
- break;
- }
-
- return 0;
-}
-
-int bassboost_set_parameter(effect_context_t *context, effect_param_t *p,
- uint32_t size __unused)
-{
- bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
- int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
- void *value = p->data + voffset;
- int32_t *param_tmp = (int32_t *)p->data;
- int32_t param = *param_tmp++;
- uint32_t strength;
-
- ALOGV("%s: ctxt %p, param %d", __func__, bass_ctxt, param);
-
- p->status = 0;
-
- switch (param) {
- case BASSBOOST_PARAM_STRENGTH:
- strength = (uint32_t)(*(int16_t *)value);
- bassboost_set_strength(bass_ctxt, strength);
- break;
- default:
- p->status = -EINVAL;
- break;
- }
-
- return 0;
-}
-
int bassboost_set_device(effect_context_t *context, uint32_t device)
{
bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
ALOGV("%s: ctxt %p, device 0x%x", __func__, bass_ctxt, device);
bass_ctxt->device = device;
- if((device == AUDIO_DEVICE_OUT_SPEAKER) ||
- (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) ||
- (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) ||
-#ifdef AFE_PROXY_ENABLED
- (device == AUDIO_DEVICE_OUT_PROXY) ||
-#endif
- (device == AUDIO_DEVICE_OUT_AUX_DIGITAL) ||
- (device == AUDIO_DEVICE_OUT_USB_ACCESSORY) ||
- (device == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET)) {
+ if (device == AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+ device == AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+ device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES) {
+ if (bass_ctxt->temp_disabled) {
+ if (effect_is_active(&bass_ctxt->common)) {
+ offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true);
+ if (bass_ctxt->ctl)
+ offload_bassboost_send_params(bass_ctxt->ctl,
+ &bass_ctxt->offload_bass,
+ OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
+ if (bass_ctxt->hw_acc_fd > 0)
+ hw_acc_bassboost_send_params(bass_ctxt->hw_acc_fd,
+ &bass_ctxt->offload_bass,
+ OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
+ }
+ bass_ctxt->temp_disabled = false;
+ }
+ } else {
if (!bass_ctxt->temp_disabled) {
if (effect_is_active(&bass_ctxt->common)) {
offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false);
@@ -178,21 +349,6 @@
bass_ctxt->temp_disabled = true;
}
ALOGI("%s: ctxt %p, disabled based on device", __func__, bass_ctxt);
- } else {
- if (bass_ctxt->temp_disabled) {
- if (effect_is_active(&bass_ctxt->common)) {
- offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true);
- if (bass_ctxt->ctl)
- offload_bassboost_send_params(bass_ctxt->ctl,
- &bass_ctxt->offload_bass,
- OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
- if (bass_ctxt->hw_acc_fd > 0)
- hw_acc_bassboost_send_params(bass_ctxt->hw_acc_fd,
- &bass_ctxt->offload_bass,
- OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
- }
- bass_ctxt->temp_disabled = false;
- }
}
offload_bassboost_set_device(&(bass_ctxt->offload_bass), device);
return 0;
@@ -329,3 +485,234 @@
OFFLOAD_SEND_BASSBOOST_STRENGTH);
return 0;
}
+
+#undef LOG_TAG
+#define LOG_TAG "offload_effect_pbe"
+/*
+ * PBE operations
+ */
+
+int pbe_set_device(effect_context_t *context, uint32_t device)
+{
+ pbe_context_t *pbe_ctxt = (pbe_context_t *)context;
+ char propValue[PROPERTY_VALUE_MAX];
+ bool pbe_enabled_by_prop = false;
+
+ ALOGV("%s: device: %d", __func__, device);
+ pbe_ctxt->device = device;
+
+ if (property_get("audio.safx.pbe.enabled", propValue, NULL)) {
+ pbe_enabled_by_prop = atoi(propValue) ||
+ !strncmp("true", propValue, 4);
+ }
+
+ if (device == AUDIO_DEVICE_OUT_SPEAKER && pbe_enabled_by_prop == true) {
+ if (pbe_ctxt->temp_disabled) {
+ if (effect_is_active(&pbe_ctxt->common)) {
+ offload_pbe_set_enable_flag(&(pbe_ctxt->offload_pbe), true);
+ if (pbe_ctxt->ctl)
+ offload_pbe_send_params(pbe_ctxt->ctl,
+ &pbe_ctxt->offload_pbe,
+ OFFLOAD_SEND_PBE_ENABLE_FLAG |
+ OFFLOAD_SEND_PBE_CONFIG);
+ if (pbe_ctxt->hw_acc_fd > 0)
+ hw_acc_pbe_send_params(pbe_ctxt->hw_acc_fd,
+ &pbe_ctxt->offload_pbe,
+ OFFLOAD_SEND_PBE_ENABLE_FLAG |
+ OFFLOAD_SEND_PBE_CONFIG);
+ }
+ pbe_ctxt->temp_disabled = false;
+ }
+ } else {
+ if (!pbe_ctxt->temp_disabled) {
+ if (effect_is_active(&pbe_ctxt->common)) {
+ offload_pbe_set_enable_flag(&(pbe_ctxt->offload_pbe), false);
+ if (pbe_ctxt->ctl)
+ offload_pbe_send_params(pbe_ctxt->ctl,
+ &pbe_ctxt->offload_pbe,
+ OFFLOAD_SEND_PBE_ENABLE_FLAG);
+ if (pbe_ctxt->hw_acc_fd > 0)
+ hw_acc_pbe_send_params(pbe_ctxt->hw_acc_fd,
+ &pbe_ctxt->offload_pbe,
+ OFFLOAD_SEND_PBE_ENABLE_FLAG);
+ }
+ pbe_ctxt->temp_disabled = true;
+ }
+ }
+ offload_pbe_set_device(&(pbe_ctxt->offload_pbe), device);
+ return 0;
+}
+
+int pbe_reset(effect_context_t *context)
+{
+ pbe_context_t *pbe_ctxt = (pbe_context_t *)context;
+
+ return 0;
+}
+
+int pbe_init(effect_context_t *context)
+{
+ pbe_context_t *pbe_ctxt = (pbe_context_t *)context;
+
+ ALOGV("%s", __func__);
+ context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+ context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+ context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ context->config.inputCfg.samplingRate = 44100;
+ context->config.inputCfg.bufferProvider.getBuffer = NULL;
+ context->config.inputCfg.bufferProvider.releaseBuffer = NULL;
+ context->config.inputCfg.bufferProvider.cookie = NULL;
+ context->config.inputCfg.mask = EFFECT_CONFIG_ALL;
+ context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+ context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+ context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ context->config.outputCfg.samplingRate = 44100;
+ context->config.outputCfg.bufferProvider.getBuffer = NULL;
+ context->config.outputCfg.bufferProvider.releaseBuffer = NULL;
+ context->config.outputCfg.bufferProvider.cookie = NULL;
+ context->config.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+ set_config(context, &context->config);
+
+ pbe_ctxt->hw_acc_fd = -1;
+ pbe_ctxt->temp_disabled = false;
+ memset(&(pbe_ctxt->offload_pbe), 0, sizeof(struct pbe_params));
+ pbe_load_config(&(pbe_ctxt->offload_pbe));
+
+ return 0;
+}
+
+int pbe_enable(effect_context_t *context)
+{
+ pbe_context_t *pbe_ctxt = (pbe_context_t *)context;
+
+ ALOGV("%s", __func__);
+
+ if (!offload_pbe_get_enable_flag(&(pbe_ctxt->offload_pbe)) &&
+ !(pbe_ctxt->temp_disabled)) {
+ offload_pbe_set_enable_flag(&(pbe_ctxt->offload_pbe), true);
+ if (pbe_ctxt->ctl)
+ offload_pbe_send_params(pbe_ctxt->ctl,
+ &pbe_ctxt->offload_pbe,
+ OFFLOAD_SEND_PBE_ENABLE_FLAG |
+ OFFLOAD_SEND_PBE_CONFIG);
+ if (pbe_ctxt->hw_acc_fd > 0)
+ hw_acc_pbe_send_params(pbe_ctxt->hw_acc_fd,
+ &pbe_ctxt->offload_pbe,
+ OFFLOAD_SEND_PBE_ENABLE_FLAG |
+ OFFLOAD_SEND_PBE_CONFIG);
+ }
+ return 0;
+}
+
+int pbe_disable(effect_context_t *context)
+{
+ pbe_context_t *pbe_ctxt = (pbe_context_t *)context;
+
+ ALOGV("%s", __func__);
+ if (offload_pbe_get_enable_flag(&(pbe_ctxt->offload_pbe))) {
+ offload_pbe_set_enable_flag(&(pbe_ctxt->offload_pbe), false);
+ if (pbe_ctxt->ctl)
+ offload_pbe_send_params(pbe_ctxt->ctl,
+ &pbe_ctxt->offload_pbe,
+ OFFLOAD_SEND_PBE_ENABLE_FLAG);
+ if (pbe_ctxt->hw_acc_fd > 0)
+ hw_acc_pbe_send_params(pbe_ctxt->hw_acc_fd,
+ &pbe_ctxt->offload_pbe,
+ OFFLOAD_SEND_PBE_ENABLE_FLAG);
+ }
+ return 0;
+}
+
+int pbe_start(effect_context_t *context, output_context_t *output)
+{
+ pbe_context_t *pbe_ctxt = (pbe_context_t *)context;
+
+ ALOGV("%s", __func__);
+ pbe_ctxt->ctl = output->ctl;
+ ALOGV("output->ctl: %p", output->ctl);
+ if (offload_pbe_get_enable_flag(&(pbe_ctxt->offload_pbe))) {
+ if (pbe_ctxt->ctl)
+ offload_pbe_send_params(pbe_ctxt->ctl, &pbe_ctxt->offload_pbe,
+ OFFLOAD_SEND_PBE_ENABLE_FLAG |
+ OFFLOAD_SEND_PBE_CONFIG);
+ if (pbe_ctxt->hw_acc_fd > 0)
+ hw_acc_pbe_send_params(pbe_ctxt->hw_acc_fd,
+ &pbe_ctxt->offload_pbe,
+ OFFLOAD_SEND_PBE_ENABLE_FLAG |
+ OFFLOAD_SEND_PBE_CONFIG);
+ }
+ return 0;
+}
+
+int pbe_stop(effect_context_t *context, output_context_t *output __unused)
+{
+ pbe_context_t *pbe_ctxt = (pbe_context_t *)context;
+
+ ALOGV("%s", __func__);
+ pbe_ctxt->ctl = NULL;
+ return 0;
+}
+
+int pbe_set_mode(effect_context_t *context, int32_t hw_acc_fd)
+{
+ pbe_context_t *pbe_ctxt = (pbe_context_t *)context;
+
+ ALOGV("%s: ctxt %p", __func__, pbe_ctxt);
+ pbe_ctxt->hw_acc_fd = hw_acc_fd;
+ if ((pbe_ctxt->hw_acc_fd > 0) &&
+ (offload_pbe_get_enable_flag(&(pbe_ctxt->offload_pbe))))
+ hw_acc_pbe_send_params(pbe_ctxt->hw_acc_fd,
+ &pbe_ctxt->offload_pbe,
+ OFFLOAD_SEND_PBE_ENABLE_FLAG |
+ OFFLOAD_SEND_PBE_CONFIG);
+ return 0;
+}
+
+static int pbe_load_config(struct pbe_params *params)
+{
+ int ret = 0;
+ uint32_t len = 0;
+ uint32_t propValue = 0;
+ uint32_t pbe_app_type = PBE_CONF_APP_ID;
+ char propValueStr[PROPERTY_VALUE_MAX];
+ void *acdb_handle = NULL;
+ acdb_get_audio_cal_t acdb_get_audio_cal = NULL;
+ acdb_audio_cal_cfg_t cal_cfg = {0};
+
+ acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW);
+ if (acdb_handle == NULL) {
+ ALOGE("%s error opening library %s", __func__, LIB_ACDB_LOADER);
+ return -EFAULT;
+ }
+
+ acdb_get_audio_cal = (acdb_get_audio_cal_t)dlsym(acdb_handle,
+ "acdb_loader_get_audio_cal_v2");
+ if (acdb_get_audio_cal == NULL) {
+ dlclose(acdb_handle);
+ ALOGE("%s error resolving acdb func symbols", __func__);
+ return -EFAULT;
+ }
+ if (property_get("audio.safx.pbe.app.type", propValueStr, "0")) {
+ propValue = atoll(propValueStr);
+ if (propValue != 0) {
+ pbe_app_type = propValue;
+ }
+ }
+ ALOGD("%s pbe_app_type = 0x%.8x", __func__, pbe_app_type);
+
+ cal_cfg.persist = 1;
+ cal_cfg.cal_type = AUDIO_STREAM_CAL_TYPE;
+ cal_cfg.app_type = pbe_app_type;
+ cal_cfg.module_id = PBE_CONF_MODULE_ID;
+ cal_cfg.param_id = PBE_CONF_PARAM_ID;
+
+ len = sizeof(params->config);
+ ret = acdb_get_audio_cal((void *)&cal_cfg, (void*)&(params->config), &len);
+ ALOGD("%s ret = %d, len = %u", __func__, ret, len);
+ if (ret == 0)
+ params->cfg_len = len;
+
+ dlclose(acdb_handle);
+ return ret;
+}
diff --git a/post_proc/bass_boost.h b/post_proc/bass_boost.h
index 6f0e61b..14d6c97 100644
--- a/post_proc/bass_boost.h
+++ b/post_proc/bass_boost.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
* Not a Contribution.
*
* Copyright (C) 2013 The Android Open Source Project
@@ -22,6 +22,13 @@
#include "bundle.h"
+enum {
+ BASS_INVALID = -1,
+ BASS_BOOST = 0, // index of bassboost
+ BASS_PBE, // index of PBE
+ BASS_COUNT // totol number of bass type
+};
+
extern const effect_descriptor_t bassboost_descriptor;
typedef struct bassboost_context_s {
@@ -37,11 +44,50 @@
struct bass_boost_params offload_bass;
} bassboost_context_t;
-int bassboost_get_parameter(effect_context_t *context, effect_param_t *p,
- uint32_t *size);
+typedef struct pbe_context_s {
+ effect_context_t common;
-int bassboost_set_parameter(effect_context_t *context, effect_param_t *p,
- uint32_t size);
+ // Offload vars
+ struct mixer_ctl *ctl;
+ int hw_acc_fd;
+ bool temp_disabled;
+ uint32_t device;
+ struct pbe_params offload_pbe;
+} pbe_context_t;
+
+typedef struct bass_context_s {
+ effect_context_t common;
+ bassboost_context_t bassboost_ctxt;
+ pbe_context_t pbe_ctxt;
+ int active_index;
+} bass_context_t;
+
+int bass_get_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t *size);
+
+int bass_set_parameter(effect_context_t *context, effect_param_t *p,
+ uint32_t size);
+
+int bass_set_device(effect_context_t *context, uint32_t device);
+
+int bass_set_mode(effect_context_t *context, int32_t hw_acc_fd);
+
+int bass_reset(effect_context_t *context);
+
+int bass_init(effect_context_t *context);
+
+int bass_enable(effect_context_t *context);
+
+int bass_disable(effect_context_t *context);
+
+int bass_start(effect_context_t *context, output_context_t *output);
+
+int bass_stop(effect_context_t *context, output_context_t *output);
+
+
+int bassboost_get_strength(bassboost_context_t *context);
+
+int bassboost_set_strength(bassboost_context_t *context, uint32_t strength);
int bassboost_set_device(effect_context_t *context, uint32_t device);
@@ -59,4 +105,20 @@
int bassboost_stop(effect_context_t *context, output_context_t *output);
+int pbe_set_device(effect_context_t *context, uint32_t device);
+
+int pbe_set_mode(effect_context_t *context, int32_t hw_acc_fd);
+
+int pbe_reset(effect_context_t *context);
+
+int pbe_init(effect_context_t *context);
+
+int pbe_enable(effect_context_t *context);
+
+int pbe_disable(effect_context_t *context);
+
+int pbe_start(effect_context_t *context, output_context_t *output);
+
+int pbe_stop(effect_context_t *context, output_context_t *output);
+
#endif /* OFFLOAD_EFFECT_BASS_BOOST_H_ */
diff --git a/post_proc/bundle.c b/post_proc/bundle.c
index 410e17b..e38a41c 100644
--- a/post_proc/bundle.c
+++ b/post_proc/bundle.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
* Not a Contribution.
*
* Copyright (C) 2013 The Android Open Source Project
@@ -520,25 +520,26 @@
eq_ctxt->ctl = NULL;
} else if (memcmp(uuid, &bassboost_descriptor.uuid,
sizeof(effect_uuid_t)) == 0) {
- bassboost_context_t *bass_ctxt = (bassboost_context_t *)
- calloc(1, sizeof(bassboost_context_t));
+ bass_context_t *bass_ctxt = (bass_context_t *)
+ calloc(1, sizeof(bass_context_t));
if (bass_ctxt == NULL) {
return -ENOMEM;
}
context = (effect_context_t *)bass_ctxt;
- context->ops.init = bassboost_init;
- context->ops.reset = bassboost_reset;
- context->ops.set_parameter = bassboost_set_parameter;
- context->ops.get_parameter = bassboost_get_parameter;
- context->ops.set_device = bassboost_set_device;
- context->ops.set_hw_acc_mode = bassboost_set_mode;
- context->ops.enable = bassboost_enable;
- context->ops.disable = bassboost_disable;
- context->ops.start = bassboost_start;
- context->ops.stop = bassboost_stop;
+ context->ops.init = bass_init;
+ context->ops.reset = bass_reset;
+ context->ops.set_parameter = bass_set_parameter;
+ context->ops.get_parameter = bass_get_parameter;
+ context->ops.set_device = bass_set_device;
+ context->ops.set_hw_acc_mode = bass_set_mode;
+ context->ops.enable = bass_enable;
+ context->ops.disable = bass_disable;
+ context->ops.start = bass_start;
+ context->ops.stop = bass_stop;
context->desc = &bassboost_descriptor;
- bass_ctxt->ctl = NULL;
+ bass_ctxt->bassboost_ctxt.ctl = NULL;
+ bass_ctxt->pbe_ctxt.ctl = NULL;
} else if (memcmp(uuid, &virtualizer_descriptor.uuid,
sizeof(effect_uuid_t)) == 0) {
virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)
@@ -713,8 +714,8 @@
/* Stub function for effect interface: never called for offloaded effects */
/* called for hw accelerated effects */
int effect_process(effect_handle_t self,
- audio_buffer_t *inBuffer,
- audio_buffer_t *outBuffer)
+ audio_buffer_t *inBuffer __unused,
+ audio_buffer_t *outBuffer __unused)
{
effect_context_t * context = (effect_context_t *)self;
int status = 0;
diff --git a/post_proc/effect_api.c b/post_proc/effect_api.c
index 7c1968e..e15db17 100644
--- a/post_proc/effect_api.c
+++ b/post_proc/effect_api.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -114,7 +114,7 @@
return -EINVAL;
} else {
*ctl = mixer_get_ctl_by_name(*mixer, mixer_string);
- if (!ctl) {
+ if (!(*ctl)) {
ALOGE("mixer_get_ctl_by_name failed");
mixer_close(*mixer);
*mixer = NULL;
@@ -235,6 +235,83 @@
bassboost, param_send_flags);
}
+void offload_pbe_set_device(struct pbe_params *pbe,
+ uint32_t device)
+{
+ ALOGV("%s: device=%d", __func__, device);
+ pbe->device = device;
+}
+
+void offload_pbe_set_enable_flag(struct pbe_params *pbe,
+ bool enable)
+{
+ ALOGV("%s: enable=%d", __func__, enable);
+ pbe->enable_flag = enable;
+}
+
+int offload_pbe_get_enable_flag(struct pbe_params *pbe)
+{
+ ALOGV("%s: enabled=%d", __func__, pbe->enable_flag);
+ return pbe->enable_flag;
+}
+
+static int pbe_send_params(eff_mode_t mode, void *ctl,
+ struct pbe_params *pbe,
+ unsigned param_send_flags)
+{
+ int param_values[128] = {0};
+ int i, *p_param_values = param_values, *cfg = NULL;
+
+ ALOGV("%s: enabled=%d", __func__, pbe->enable_flag);
+ *p_param_values++ = PBE_MODULE;
+ *p_param_values++ = pbe->device;
+ *p_param_values++ = 0; /* num of commands*/
+ if (param_send_flags & OFFLOAD_SEND_PBE_ENABLE_FLAG) {
+ *p_param_values++ = PBE_ENABLE;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = PBE_ENABLE_PARAM_LEN;
+ *p_param_values++ = pbe->enable_flag;
+ param_values[2] += 1;
+ }
+ if (param_send_flags & OFFLOAD_SEND_PBE_CONFIG) {
+ *p_param_values++ = PBE_CONFIG;
+ *p_param_values++ = CONFIG_SET;
+ *p_param_values++ = 0; /* start offset if param size if greater than 128 */
+ *p_param_values++ = pbe->cfg_len;
+ cfg = (int *)&pbe->config;
+ for (i = 0; i < (int)pbe->cfg_len ; i+= sizeof(*p_param_values))
+ *p_param_values++ = *cfg++;
+ param_values[2] += 1;
+ }
+
+ if ((mode == OFFLOAD) && param_values[2] && ctl) {
+ mixer_ctl_set_array((struct mixer_ctl *)ctl, param_values,
+ ARRAY_SIZE(param_values));
+ } else if ((mode == HW_ACCELERATOR) && param_values[2] &&
+ ctl && *(int *)ctl) {
+ if (ioctl(*(int *)ctl, AUDIO_EFFECTS_SET_PP_PARAMS, param_values) < 0)
+ ALOGE("%s: sending h/w acc effects params fail[%d]", __func__, errno);
+ }
+
+ return 0;
+}
+
+int offload_pbe_send_params(struct mixer_ctl *ctl,
+ struct pbe_params *pbe,
+ unsigned param_send_flags)
+{
+ return pbe_send_params(OFFLOAD, (void *)ctl, pbe,
+ param_send_flags);
+}
+
+int hw_acc_pbe_send_params(int fd, struct pbe_params *pbe,
+ unsigned param_send_flags)
+{
+ return pbe_send_params(HW_ACCELERATOR, (void *)&fd,
+ pbe, param_send_flags);
+}
+
void offload_virtualizer_set_device(struct virtualizer_params *virtualizer,
uint32_t device)
{
@@ -891,6 +968,11 @@
uint32_t i;
ALOGV("%s", __func__);
+ if (!ctl) {
+ ALOGE("%s: ctl is NULL, return invalid", __func__);
+ return -EINVAL;
+ }
+
if (param_send_flags & OFFLOAD_SEND_HPX_STATE_OFF) {
*p_param_values++ = DTS_EAGLE_MODULE_ENABLE;
*p_param_values++ = 0; /* hpx off*/
@@ -899,7 +981,7 @@
*p_param_values++ = 1; /* hpx on*/
}
- if ((mode == OFFLOAD) && ctl)
+ if (mode == OFFLOAD)
mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
else {
if (ioctl(*(int *)ctl, AUDIO_EFFECTS_SET_PP_PARAMS, param_values) < 0)
diff --git a/post_proc/effect_api.h b/post_proc/effect_api.h
index e05924a..ce0503a 100644
--- a/post_proc/effect_api.h
+++ b/post_proc/effect_api.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -39,6 +39,21 @@
struct mixer_ctl **ctl);
void offload_close_mixer(struct mixer **mixer);
+
+#define OFFLOAD_SEND_PBE_ENABLE_FLAG (1 << 0)
+#define OFFLOAD_SEND_PBE_CONFIG (OFFLOAD_SEND_PBE_ENABLE_FLAG << 1)
+void offload_pbe_set_device(struct pbe_params *pbe,
+ uint32_t device);
+void offload_pbe_set_enable_flag(struct pbe_params *pbe,
+ bool enable);
+int offload_pbe_get_enable_flag(struct pbe_params *pbe);
+
+int offload_pbe_send_params(struct mixer_ctl *ctl,
+ struct pbe_params *pbe,
+ unsigned param_send_flags);
+int hw_acc_pbe_send_params(int fd,
+ struct pbe_params *pbe,
+ unsigned param_send_flags);
#define OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG (1 << 0)
#define OFFLOAD_SEND_BASSBOOST_STRENGTH \
(OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG << 1)
diff --git a/post_proc/effect_util.c b/post_proc/effect_util.c
index cda89bc..8f7a604 100644
--- a/post_proc/effect_util.c
+++ b/post_proc/effect_util.c
@@ -44,7 +44,7 @@
"bassboost_param_strength"
};
-#define EFFECT_FILE "/data/data/dts/effect"
+#define EFFECT_FILE "/data/misc/dts/effect"
#define MAX_LENGTH_OF_INTEGER_IN_STRING 13
#ifdef DTS_EAGLE
diff --git a/post_proc/virtualizer.c b/post_proc/virtualizer.c
index f6e2881..2748568 100644
--- a/post_proc/virtualizer.c
+++ b/post_proc/virtualizer.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
* Not a Contribution.
*
* Copyright (C) 2013 The Android Open Source Project
@@ -69,6 +69,197 @@
return 0;
}
+/*
+ * Check if an audio device is supported by this implementation
+ *
+ * [in]
+ * device device that is intented for processing (e.g. for binaural vs transaural)
+ * [out]
+ * false device is not applicable for effect
+ * true device is applicable for effect
+ */
+bool virtualizer_is_device_supported(audio_devices_t device) {
+ switch (device) {
+ case AUDIO_DEVICE_OUT_SPEAKER:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
+#ifdef AFE_PROXY_ENABLED
+ case AUDIO_DEVICE_OUT_PROXY:
+#endif
+ case AUDIO_DEVICE_OUT_AUX_DIGITAL:
+ case AUDIO_DEVICE_OUT_USB_ACCESSORY:
+ case AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET:
+ return false;
+ default :
+ return true;
+ }
+}
+
+/*
+ * Check if a channel mask + audio device is supported by this implementation
+ *
+ * [in]
+ * channel_mask channel mask of input buffer
+ * device device that is intented for processing (e.g. for binaural vs transaural)
+ * [out]
+ * false if the configuration is not supported or it is unknown
+ * true if the configuration is supported
+ */
+bool virtualizer_is_configuration_supported(audio_channel_mask_t channel_mask,
+ audio_devices_t device) {
+ uint32_t channelCount = audio_channel_count_from_out_mask(channel_mask);
+ if ((channelCount == 0) || (channelCount > 2)) {
+ return false;
+ }
+
+ return virtualizer_is_device_supported(device);
+}
+
+/*
+ * Force the virtualization mode to that of the given audio device
+ *
+ * [in]
+ * context effect engine context
+ * forced_device device whose virtualization mode we'll always use
+ * [out]
+ * -EINVAL if the device is not supported or is unknown
+ * 0 if the device is supported and the virtualization mode forced
+ */
+int virtualizer_force_virtualization_mode(virtualizer_context_t *context,
+ audio_devices_t forced_device) {
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+ int status = 0;
+ bool use_virt = false;
+ int is_virt_enabled =
+ offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt));
+
+ ALOGV("%s: ctxt %p, forcedDev=0x%x enabled=%d tmpDisabled=%d", __func__, virt_ctxt,
+ forced_device, is_virt_enabled, virt_ctxt->temp_disabled);
+
+ if (virtualizer_is_device_supported(forced_device) == false) {
+ if (forced_device != AUDIO_DEVICE_NONE) {
+ //forced device is not supported, make it behave as a reset of forced mode
+ forced_device = AUDIO_DEVICE_NONE;
+ // but return an error
+ status = -EINVAL;
+ }
+ }
+
+ if (forced_device == AUDIO_DEVICE_NONE) {
+ // disabling forced virtualization mode:
+ // verify whether the virtualization should be enabled or disabled
+ if (virtualizer_is_device_supported(virt_ctxt->device)) {
+ use_virt = (is_virt_enabled == true);
+ }
+ virt_ctxt->forced_device = AUDIO_DEVICE_NONE;
+ } else {
+ // forcing virtualization mode:
+ // TODO: we assume device is supported, so hard coded a fixed one.
+ virt_ctxt->forced_device = AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+ // TODO: only enable for a supported mode, when the effect is enabled
+ use_virt = (is_virt_enabled == true);
+ }
+
+ if (use_virt) {
+ if (virt_ctxt->temp_disabled == true) {
+ if (effect_is_active(&virt_ctxt->common)) {
+ offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true);
+ if (virt_ctxt->ctl)
+ offload_virtualizer_send_params(virt_ctxt->ctl,
+ &virt_ctxt->offload_virt,
+ OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+ if (virt_ctxt->hw_acc_fd > 0)
+ hw_acc_virtualizer_send_params(virt_ctxt->hw_acc_fd,
+ &virt_ctxt->offload_virt,
+ OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+ }
+ ALOGV("%s: re-enable VIRTUALIZER", __func__);
+ virt_ctxt->temp_disabled = false;
+ } else {
+ ALOGV("%s: leaving VIRTUALIZER enabled", __func__);
+ }
+ } else {
+ if (virt_ctxt->temp_disabled == false) {
+ if (effect_is_active(&virt_ctxt->common)) {
+ offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false);
+ if (virt_ctxt->ctl)
+ offload_virtualizer_send_params(virt_ctxt->ctl,
+ &virt_ctxt->offload_virt,
+ OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+ if (virt_ctxt->hw_acc_fd > 0)
+ hw_acc_virtualizer_send_params(virt_ctxt->hw_acc_fd,
+ &virt_ctxt->offload_virt,
+ OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+ }
+ ALOGV("%s: disable VIRTUALIZER", __func__);
+ virt_ctxt->temp_disabled = true;
+ } else {
+ ALOGV("%s: leaving VIRTUALIZER disabled", __func__);
+ }
+ }
+
+ ALOGV("after %s: ctxt %p, enabled=%d tmpDisabled=%d", __func__, virt_ctxt,
+ is_virt_enabled, virt_ctxt->temp_disabled);
+
+ return status;
+}
+
+/*
+ * Get the virtual speaker angles for a channel mask + audio device configuration
+ * which is guaranteed to be supported by this implementation
+ *
+ * [in]
+ * channel_mask the channel mask of the input to virtualize
+ * device the type of device that affects the processing (e.g. for binaural vs transaural)
+ * [in/out]
+ * speaker_angles the array of integer where each speaker angle is written as a triplet in the
+ * following format:
+ * int32_t a bit mask with a single value selected for each speaker, following
+ * the convention of the audio_channel_mask_t type
+ * int32_t a value in degrees expressing the speaker azimuth, where 0 is in front
+ * of the user, 180 behind, -90 to the left, 90 to the right of the user
+ * int32_t a value in degrees expressing the speaker elevation, where 0 is the
+ * horizontal plane, +90 is directly above the user, -90 below
+ *
+ */
+void virtualizer_get_speaker_angles(audio_channel_mask_t channel_mask __unused,
+ audio_devices_t device __unused, int32_t *speaker_angles) {
+ // the channel count is guaranteed to be 1 or 2
+ // the device is guaranteed to be of type headphone
+ // this virtualizer is always 2in with speakers at -90 and 90deg of azimuth, 0deg of elevation
+ *speaker_angles++ = (int32_t) AUDIO_CHANNEL_OUT_FRONT_LEFT;
+ *speaker_angles++ = -90; // azimuth
+ *speaker_angles++ = 0; // elevation
+ *speaker_angles++ = (int32_t) AUDIO_CHANNEL_OUT_FRONT_RIGHT;
+ *speaker_angles++ = 90; // azimuth
+ *speaker_angles = 0; // elevation
+}
+
+/*
+ * Retrieve the current device whose processing mode is used by this effect
+ *
+ * [out]
+ * AUDIO_DEVICE_NONE if the effect is not virtualizing
+ * or the device type if the effect is virtualizing
+ */
+audio_devices_t virtualizer_get_virtualization_mode(virtualizer_context_t *context) {
+ virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+ audio_devices_t device = AUDIO_DEVICE_NONE;
+
+ if ((offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt)))
+ && (virt_ctxt->temp_disabled == false)) {
+ if (virt_ctxt->forced_device != AUDIO_DEVICE_NONE) {
+ // virtualization mode is forced, return that device
+ device = virt_ctxt->forced_device;
+ } else {
+ // no forced mode, return the current device
+ device = virt_ctxt->device;
+ }
+ }
+ ALOGV("%s: returning 0x%x", __func__, device);
+ return device;
+}
+
int virtualizer_get_parameter(effect_context_t *context, effect_param_t *p,
uint32_t *size)
{
@@ -94,6 +285,15 @@
p->status = -EINVAL;
p->vsize = sizeof(int16_t);
break;
+ case VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES:
+ // return value size can only be interpreted as relative to input value,
+ // deferring validity check to below
+ break;
+ case VIRTUALIZER_PARAM_VIRTUALIZATION_MODE:
+ if (p->vsize != sizeof(uint32_t))
+ p->status = -EINVAL;
+ p->vsize = sizeof(uint32_t);
+ break;
default:
p->status = -EINVAL;
}
@@ -112,6 +312,31 @@
*(int16_t *)value = virtualizer_get_strength(virt_ctxt);
break;
+ case VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES:
+ {
+ const audio_channel_mask_t channel_mask = (audio_channel_mask_t) *param_tmp++;
+ const audio_devices_t device = (audio_devices_t) *param_tmp;
+ uint32_t channel_cnt = audio_channel_count_from_out_mask(channel_mask);
+
+ if (p->vsize < 3 * channel_cnt * sizeof(int32_t)){
+ p->status = -EINVAL;
+ break;
+ }
+ // verify the configuration is supported
+ if(virtualizer_is_configuration_supported(channel_mask, device)) {
+ // configuration is supported, get the angles
+ virtualizer_get_speaker_angles(channel_mask, device, (int32_t *)value);
+ } else {
+ p->status = -EINVAL;
+ }
+
+ break;
+ }
+
+ case VIRTUALIZER_PARAM_VIRTUALIZATION_MODE:
+ *(uint32_t *)value = (uint32_t) virtualizer_get_virtualization_mode(virt_ctxt);
+ break;
+
default:
p->status = -EINVAL;
break;
@@ -121,7 +346,7 @@
}
int virtualizer_set_parameter(effect_context_t *context, effect_param_t *p,
- uint32_t size)
+ uint32_t size __unused)
{
virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
@@ -139,6 +364,14 @@
strength = (uint32_t)(*(int16_t *)value);
virtualizer_set_strength(virt_ctxt, strength);
break;
+ case VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE:
+ {
+ const audio_devices_t device = *(audio_devices_t *)value;
+ if (0 != virtualizer_force_virtualization_mode(virt_ctxt, device)) {
+ p->status = -EINVAL;
+ }
+ break;
+ }
default:
p->status = -EINVAL;
break;
@@ -153,46 +386,44 @@
ALOGV("%s: ctxt %p, device: 0x%x", __func__, virt_ctxt, device);
virt_ctxt->device = device;
- if((device == AUDIO_DEVICE_OUT_SPEAKER) ||
- (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) ||
- (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) ||
-#ifdef AFE_PROXY_ENABLED
- (device == AUDIO_DEVICE_OUT_PROXY) ||
-#endif
- (device == AUDIO_DEVICE_OUT_AUX_DIGITAL) ||
- (device == AUDIO_DEVICE_OUT_USB_ACCESSORY) ||
- (device == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET)) {
- if (!virt_ctxt->temp_disabled) {
- if (effect_is_active(&virt_ctxt->common)) {
- offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false);
- if (virt_ctxt->ctl)
- offload_virtualizer_send_params(virt_ctxt->ctl,
- &virt_ctxt->offload_virt,
- OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
- if (virt_ctxt->hw_acc_fd > 0)
- hw_acc_virtualizer_send_params(virt_ctxt->hw_acc_fd,
- &virt_ctxt->offload_virt,
- OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+
+ if (virt_ctxt->forced_device == AUDIO_DEVICE_NONE) {
+ // default case unless configuration is forced
+ if (virtualizer_is_device_supported(device) == false) {
+ if (!virt_ctxt->temp_disabled) {
+ if (effect_is_active(&virt_ctxt->common)) {
+ offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false);
+ if (virt_ctxt->ctl)
+ offload_virtualizer_send_params(virt_ctxt->ctl,
+ &virt_ctxt->offload_virt,
+ OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+ if (virt_ctxt->hw_acc_fd > 0)
+ hw_acc_virtualizer_send_params(virt_ctxt->hw_acc_fd,
+ &virt_ctxt->offload_virt,
+ OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+ }
+ virt_ctxt->temp_disabled = true;
+ ALOGI("%s: ctxt %p, disabled based on device", __func__, virt_ctxt);
}
- virt_ctxt->temp_disabled = true;
- ALOGI("%s: ctxt %p, disabled based on device", __func__, virt_ctxt);
- }
- } else {
- if (virt_ctxt->temp_disabled) {
- if (effect_is_active(&virt_ctxt->common)) {
- offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true);
- if (virt_ctxt->ctl)
- offload_virtualizer_send_params(virt_ctxt->ctl,
- &virt_ctxt->offload_virt,
- OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
- if (virt_ctxt->hw_acc_fd > 0)
- hw_acc_virtualizer_send_params(virt_ctxt->hw_acc_fd,
- &virt_ctxt->offload_virt,
- OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+ } else {
+ if (virt_ctxt->temp_disabled) {
+ if (effect_is_active(&virt_ctxt->common)) {
+ offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true);
+ if (virt_ctxt->ctl)
+ offload_virtualizer_send_params(virt_ctxt->ctl,
+ &virt_ctxt->offload_virt,
+ OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+ if (virt_ctxt->hw_acc_fd > 0)
+ hw_acc_virtualizer_send_params(virt_ctxt->hw_acc_fd,
+ &virt_ctxt->offload_virt,
+ OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+ }
+ virt_ctxt->temp_disabled = false;
}
- virt_ctxt->temp_disabled = false;
}
}
+ // else virtualization mode is forced to a certain device, nothing to do
+
offload_virtualizer_set_device(&(virt_ctxt->offload_virt), device);
return 0;
}
@@ -230,6 +461,8 @@
virt_ctxt->temp_disabled = false;
virt_ctxt->hw_acc_fd = -1;
+ virt_ctxt->forced_device = AUDIO_DEVICE_NONE;
+ virt_ctxt->device = AUDIO_DEVICE_NONE;
memset(&(virt_ctxt->offload_virt), 0, sizeof(struct virtualizer_params));
return 0;
diff --git a/post_proc/virtualizer.h b/post_proc/virtualizer.h
index 440c8a2..b5293fb 100644
--- a/post_proc/virtualizer.h
+++ b/post_proc/virtualizer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
* Not a Contribution.
*
* Copyright (C) 2013 The Android Open Source Project
@@ -33,7 +33,8 @@
struct mixer_ctl *ctl;
int hw_acc_fd;
bool temp_disabled;
- uint32_t device;
+ audio_devices_t forced_device;
+ audio_devices_t device;
struct virtualizer_params offload_virt;
} virtualizer_context_t;