hal: Add device sidetone support for USB audio ADSP solution
Add device sidetone support for USB ADSP solution if the USB headset
has the sidetone capability.
CRs-Fixed: 1019158
Change-Id: Ie40c286eb9988aeb5093f32c7f81cdb142e88eb6
diff --git a/configs/msmcobalt/audio_platform_info.xml b/configs/msmcobalt/audio_platform_info.xml
index fc86a53..ae252bc 100644
--- a/configs/msmcobalt/audio_platform_info.xml
+++ b/configs/msmcobalt/audio_platform_info.xml
@@ -69,6 +69,8 @@
<!-- followed by perf lock options -->
<param key="perf_lock_opts" value="4, 0x101, 0x704, 0x20F, 0x1E01"/>
<param key="input_mic_max_count" value="4"/>
+ <!-- In the below value string, the value indicates sidetone gain in dB -->
+ <param key="usb_sidetone_gain" value="35"/>
</config_params>
<backend_names>
<device name="SND_DEVICE_OUT_HEADPHONES" backend="headphones" interface="SLIMBUS_6_RX"/>
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 0ef1783..0420105 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -156,6 +156,8 @@
#define audio_extn_usb_add_device(device, card) (0)
#define audio_extn_usb_remove_device(device, card) (0)
#define audio_extn_usb_is_config_supported(bit_width, sample_rate, ch) (0)
+#define audio_extn_usb_enable_sidetone(device, enable) (0)
+#define audio_extn_usb_set_sidetone_gain(parms, value, len) (0)
#else
void audio_extn_usb_init(void *adev);
void audio_extn_usb_deinit();
@@ -164,6 +166,9 @@
bool audio_extn_usb_is_config_supported(unsigned int *bit_width,
unsigned int *sample_rate,
unsigned int ch);
+int audio_extn_usb_enable_sidetone(int device, bool enable);
+int audio_extn_usb_set_sidetone_gain(struct str_parms *parms,
+ char *value, int len);
#endif
#ifndef SSR_ENABLED
diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c
index 141ef37..da80422 100644
--- a/hal/audio_extn/usb.c
+++ b/hal/audio_extn/usb.c
@@ -29,21 +29,22 @@
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/stat.h>
-
#include <system/audio.h>
#include <tinyalsa/asoundlib.h>
#include <audio_hw.h>
#include <cutils/properties.h>
+#include <ctype.h>
+#include <math.h>
#ifdef USB_HEADSET_ENABLED
#define USB_BUFF_SIZE 2048
#define CHANNEL_NUMBER_STR "Channels: "
#define PLAYBACK_PROFILE_STR "Playback:"
#define CAPTURE_PROFILE_STR "Capture:"
+#define USB_SIDETONE_GAIN_STR "usb_sidetone_gain"
#define ABS_SUB(A, B) (((A) > (B)) ? ((A) - (B)):((B) - (A)))
#define SAMPLE_RATE_8000 8000
#define SAMPLE_RATE_11025 11025
-
// Supported sample rates for USB
static uint32_t supported_sample_rates[] =
{44100, 48000, 64000, 88200, 96000, 176400, 192000};
@@ -55,6 +56,12 @@
USB_CAPTURE,
};
+enum {
+ USB_SIDETONE_ENABLE_INDEX = 0,
+ USB_SIDETONE_VOLUME_INDEX,
+ USB_SIDETONE_MAX_INDEX,
+};
+
struct usb_device_config {
struct listnode list;
unsigned int bit_width;
@@ -68,15 +75,120 @@
audio_devices_t usb_device_type;
int usb_card;
struct listnode usb_device_conf_list;
+ struct mixer *usb_snd_mixer;
+ int usb_sidetone_index[USB_SIDETONE_MAX_INDEX];
+ int usb_sidetone_vol_min;
+ int usb_sidetone_vol_max;
};
struct usb_module {
struct listnode usb_card_conf_list;
struct audio_device *adev;
+ int sidetone_gain;
};
static struct usb_module *usbmod = NULL;
static bool usb_audio_debug_enable = false;
+static int usb_sidetone_gain = 0;
+
+static const char * const usb_sidetone_enable_str[] = {
+ "Sidetone Playback Switch",
+ "Mic Playback Switchs",
+};
+
+static const char * const usb_sidetone_volume_str[] = {
+ "Sidetone Playback Volume",
+ "Mic Playback Volume",
+};
+
+static void usb_mixer_print_enum(struct mixer_ctl *ctl)
+{
+ unsigned int num_enums;
+ unsigned int i;
+ const char *string;
+
+ num_enums = mixer_ctl_get_num_enums(ctl);
+
+ for (i = 0; i < num_enums; i++) {
+ string = mixer_ctl_get_enum_string(ctl, i);
+ ALOGI("\t%s%s", mixer_ctl_get_value(ctl, 0) == (int)i ? ">" : "", string);
+ }
+}
+
+static void usb_soundcard_detail_control(struct mixer *mixer, const char *control)
+{
+ struct mixer_ctl *ctl;
+ enum mixer_ctl_type type;
+ unsigned int num_values;
+ unsigned int i;
+ int min, max;
+
+ if (isdigit(control[0]))
+ ctl = mixer_get_ctl(mixer, atoi(control));
+ else
+ ctl = mixer_get_ctl_by_name(mixer, control);
+
+ if (!ctl) {
+ fprintf(stderr, "Invalid mixer control\n");
+ return;
+ }
+
+ type = mixer_ctl_get_type(ctl);
+ num_values = mixer_ctl_get_num_values(ctl);
+
+ ALOGI("%s:", mixer_ctl_get_name(ctl));
+
+ for (i = 0; i < num_values; i++) {
+ switch (type) {
+ case MIXER_CTL_TYPE_INT:
+ ALOGI(" %d", mixer_ctl_get_value(ctl, i));
+ break;
+ case MIXER_CTL_TYPE_BOOL:
+ ALOGI(" %s", mixer_ctl_get_value(ctl, i) ? "On" : "Off");
+ break;
+ case MIXER_CTL_TYPE_ENUM:
+ usb_mixer_print_enum(ctl);
+ break;
+ case MIXER_CTL_TYPE_BYTE:
+ ALOGI(" 0x%02x", mixer_ctl_get_value(ctl, i));
+ break;
+ default:
+ ALOGI(" unknown");
+ break;
+ }
+ }
+
+ if (type == MIXER_CTL_TYPE_INT) {
+ min = mixer_ctl_get_range_min(ctl);
+ max = mixer_ctl_get_range_max(ctl);
+ ALOGI(" (range %d->%d)", min, max);
+ }
+}
+
+static void usb_soundcard_list_controls(struct mixer *mixer)
+{
+ struct mixer_ctl *ctl;
+ const char *name, *type;
+ unsigned int num_ctls, num_values;
+ unsigned int i;
+
+ num_ctls = mixer_get_num_ctls(mixer);
+
+ ALOGI("Number of controls: %d\n", num_ctls);
+
+ ALOGI("ctl\ttype\tnum\t%-40s value\n", "name");
+ for (i = 0; i < num_ctls; i++) {
+ ctl = mixer_get_ctl(mixer, i);
+ if (ctl != NULL) {
+ name = mixer_ctl_get_name(ctl);
+ type = mixer_ctl_get_type_string(ctl);
+ num_values = mixer_ctl_get_num_values(ctl);
+ ALOGI("%d\t%s\t%d\t%-40s", i, type, num_values, name);
+ if (name != NULL)
+ usb_soundcard_detail_control(mixer, name);
+ }
+ }
+}
static int usb_set_channel_mixer_ctl(int channel,
char *ch_mixer_ctl_name)
@@ -400,6 +512,46 @@
return ret;
}
+static void usb_get_sidetone_mixer(struct usb_card_config *usb_card_info)
+{
+ struct mixer_ctl *ctl;
+ unsigned int index;
+
+ for (index = 0; index < USB_SIDETONE_MAX_INDEX; index++)
+ usb_card_info->usb_sidetone_index[index] = -1;
+
+ usb_card_info->usb_snd_mixer = mixer_open(usb_card_info->usb_card);
+ for (index = 0;
+ index < sizeof(usb_sidetone_enable_str)/sizeof(usb_sidetone_enable_str[0]);
+ index++) {
+ ctl = mixer_get_ctl_by_name(usb_card_info->usb_snd_mixer,
+ usb_sidetone_enable_str[index]);
+ if (ctl) {
+ usb_card_info->usb_sidetone_index[USB_SIDETONE_ENABLE_INDEX] = index;
+ /* Disable device sidetone by default */
+ mixer_ctl_set_value(ctl, 0, false);
+ break;
+ }
+ }
+ for (index = 0;
+ index < sizeof(usb_sidetone_volume_str)/sizeof(usb_sidetone_volume_str[0]);
+ index++) {
+ ctl = mixer_get_ctl_by_name(usb_card_info->usb_snd_mixer,
+ usb_sidetone_volume_str[index]);
+ if (ctl) {
+ usb_card_info->usb_sidetone_index[USB_SIDETONE_VOLUME_INDEX] = index;
+ usb_card_info->usb_sidetone_vol_min = mixer_ctl_get_range_min(ctl);
+ usb_card_info->usb_sidetone_vol_max = mixer_ctl_get_range_max(ctl);
+ break;
+ }
+ }
+
+ if ((usb_card_info->usb_snd_mixer != NULL) && (usb_audio_debug_enable))
+ usb_soundcard_list_controls(usb_card_info->usb_snd_mixer);
+
+ return;
+}
+
static bool usb_valid_device(int device)
{
bool is_usb_device = false;
@@ -631,7 +783,6 @@
return true;
}
-
static bool usb_audio_backend_apply_policy(struct listnode *dev_list,
unsigned int *bit_width,
unsigned int *sample_rate,
@@ -666,6 +817,72 @@
return is_usb_supported;
}
+static int usb_get_sidetone_gain(struct usb_card_config *card_info)
+{
+ int gain = card_info->usb_sidetone_vol_min + usbmod->sidetone_gain;
+ if (gain > card_info->usb_sidetone_vol_max)
+ gain = card_info->usb_sidetone_vol_max;
+ return gain;
+}
+
+void audio_extn_usb_set_sidetone_gain(struct str_parms *parms,
+ char *value, int len)
+{
+ int err;
+
+ err = str_parms_get_str(parms, USB_SIDETONE_GAIN_STR,
+ value, len);
+ if (err >= 0) {
+ usb_sidetone_gain = pow(10.0, (float)(atoi(value))/10.0);
+ ALOGV("%s: sidetone gain(%s) decimal %d",
+ __func__, value, usb_sidetone_gain);
+ str_parms_del(parms, USB_SIDETONE_GAIN_STR);
+ }
+ return;
+}
+
+int audio_extn_usb_enable_sidetone(int device, bool enable)
+{
+ int ret = -ENODEV;
+ struct listnode *node_i;
+ struct usb_card_config *card_info;
+ int i;
+ ALOGV("%s: card_dev_type (0x%x), sidetone enable(%d)",
+ __func__, device, enable);
+
+ list_for_each(node_i, &usbmod->usb_card_conf_list) {
+ card_info = node_to_item(node_i, struct usb_card_config, list);
+ ALOGV("%s: card_dev_type (0x%x), card_no(%d)",
+ __func__, card_info->usb_device_type, card_info->usb_card);
+ if (card_info->usb_device_type == AUDIO_DEVICE_OUT_USB_DEVICE) {
+ if ((i = card_info->usb_sidetone_index[USB_SIDETONE_ENABLE_INDEX]) != -1) {
+ struct mixer_ctl *ctl = mixer_get_ctl_by_name(
+ card_info->usb_snd_mixer,
+ usb_sidetone_enable_str[i]);
+ if (ctl)
+ mixer_ctl_set_value(ctl, 0, enable);
+ else
+ break;
+
+ if ((i = card_info->usb_sidetone_index[USB_SIDETONE_VOLUME_INDEX]) != -1) {
+ ctl = mixer_get_ctl_by_name(
+ card_info->usb_snd_mixer,
+ usb_sidetone_volume_str[i]);
+ if (ctl == NULL)
+ ALOGV("%s: sidetone gain mixer command is not found",
+ __func__);
+ else if (enable)
+ mixer_ctl_set_value(ctl, 0,
+ usb_get_sidetone_gain(card_info));
+ }
+ ret = 0;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
bool audio_extn_usb_is_config_supported(unsigned int *bit_width,
unsigned int *sample_rate,
unsigned int ch)
@@ -732,6 +949,7 @@
if (!usb_get_device_pb_config(usb_card_info, card)){
usb_card_info->usb_card = card;
usb_card_info->usb_device_type = AUDIO_DEVICE_OUT_USB_DEVICE;
+ usb_get_sidetone_mixer(usb_card_info);
list_add_tail(&usbmod->usb_card_conf_list, &usb_card_info->list);
goto exit;
}
@@ -810,6 +1028,7 @@
}
list_init(&usbmod->usb_card_conf_list);
usbmod->adev = (struct audio_device*)adev;
+ usbmod->sidetone_gain = usb_sidetone_gain;
exit:
return;
}
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 0703b81..b18670e 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -5323,3 +5323,26 @@
return snd_device;
}
}
+
+int platform_set_sidetone(struct audio_device *adev,
+ snd_device_t out_snd_device,
+ bool enable,
+ char *str)
+{
+ int ret;
+ if (out_snd_device == SND_DEVICE_OUT_USB_HEADSET) {
+ ret = audio_extn_usb_enable_sidetone(out_snd_device, enable);
+ if (ret)
+ ALOGI("%s: usb device %d does not support device sidetone\n",
+ __func__, out_snd_device);
+ } else {
+ ALOGV("%s: sidetone out device(%d) mixer cmd = %s\n",
+ __func__, out_snd_device, str);
+
+ if (enable)
+ audio_route_apply_and_update_path(adev->audio_route, str);
+ else
+ audio_route_reset_and_update_path(adev->audio_route, str);
+ }
+ return 0;
+}
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 2c60f3b..b35e8e9 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -1234,3 +1234,26 @@
{
return true;
}
+
+int platform_set_sidetone(struct audio_device *adev,
+ snd_device_t out_snd_device,
+ bool enable,
+ char *str)
+{
+ int ret;
+ if (out_snd_device == SND_DEVICE_OUT_USB_HEADSET) {
+ ret = audio_extn_usb_enable_sidetone(out_snd_device, enable);
+ if (ret)
+ ALOGI("%s: usb device %d does not support device sidetone\n",
+ __func__, out_snd_device);
+ } else {
+ ALOGV("%s: sidetone out device(%d) mixer cmd = %s\n",
+ __func__, out_snd_device, str);
+
+ if (enable)
+ audio_route_apply_and_update_path(adev->audio_route, str);
+ else
+ audio_route_reset_and_update_path(adev->audio_route, str);
+ }
+ return 0;
+}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index b7d326c..d60d67c 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -3567,6 +3567,7 @@
set_audiocal(platform, parms, value, len);
native_audio_set_params(platform, parms, value, len);
audio_extn_spkr_prot_set_parameters(parms, value, len);
+ audio_extn_usb_set_sidetone_gain(parms, value, len);
perf_lock_set_params(platform, parms, value, len);
done:
ALOGV("%s: exit with code(%d)", __func__, ret);
@@ -5163,4 +5164,25 @@
return ret;
}
+int platform_set_sidetone(struct audio_device *adev,
+ snd_device_t out_snd_device,
+ bool enable,
+ char *str)
+{
+ int ret;
+ if (out_snd_device == SND_DEVICE_OUT_USB_HEADSET) {
+ ret = audio_extn_usb_enable_sidetone(out_snd_device, enable);
+ if (ret)
+ ALOGI("%s: usb device %d does not support device sidetone\n",
+ __func__, out_snd_device);
+ } else {
+ ALOGV("%s: sidetone out device(%d) mixer cmd = %s\n",
+ __func__, out_snd_device, str);
+ if (enable)
+ audio_route_apply_and_update_path(adev->audio_route, str);
+ else
+ audio_route_reset_and_update_path(adev->audio_route, str);
+ }
+ return 0;
+}
diff --git a/hal/platform_api.h b/hal/platform_api.h
index cb177b6..c6f3cb3 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -148,4 +148,8 @@
snd_device_t *new_snd_devices);
bool platform_check_backends_match(snd_device_t snd_device1, snd_device_t snd_device2);
+int platform_set_sidetone(struct audio_device *adev,
+ snd_device_t out_snd_device,
+ bool enable,
+ char * str);
#endif // AUDIO_PLATFORM_API_H
diff --git a/hal/voice.c b/hal/voice.c
index 5fef205..f86483e 100644
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -72,6 +72,9 @@
is_sidetone_dev = true;
strlcpy(mixer_path, "sidetone-headphones", MIXER_PATH_MAX_LENGTH);
break;
+ case SND_DEVICE_OUT_USB_HEADSET:
+ is_sidetone_dev = true;
+ break;
default:
is_sidetone_dev = false;
break;
@@ -84,28 +87,11 @@
snd_device_t out_snd_device, bool enable)
{
char mixer_path[MIXER_PATH_MAX_LENGTH];
- bool is_sidetone_dev;
-
ALOGD("%s: %s, out_snd_device: %d\n",
__func__, (enable ? "enable" : "disable"),
out_snd_device);
-
- is_sidetone_dev = voice_is_sidetone_device(out_snd_device, mixer_path);
-
- if (!is_sidetone_dev) {
- ALOGD("%s: device %d does not support sidetone\n",
- __func__, out_snd_device);
- return;
- }
-
- ALOGD("%s: sidetone out device = %s\n",
- __func__, mixer_path);
-
- if (enable)
- audio_route_apply_and_update_path(adev->audio_route, mixer_path);
- else
- audio_route_reset_and_update_path(adev->audio_route, mixer_path);
-
+ if (voice_is_sidetone_device(out_snd_device, mixer_path))
+ platform_set_sidetone(adev, out_snd_device, enable, mixer_path);
return;
}