summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCheng-Yi Chiang <cychiang@chromium.org>2017-01-24 17:54:23 +0800
committerchrome-bot <chrome-bot@chromium.org>2017-02-27 12:03:18 -0800
commite26a4a19c1e4d8e6b3f285eb6ea9233635a01093 (patch)
treedf8b8b33b0b0b70d1e8cccfd194e2e0cf92592ee
parent2d7d73485680f773eef56676995729216a6ae47f (diff)
downloadadhd-e26a4a19c1e4d8e6b3f285eb6ea9233635a01093.tar.gz
CRAS: alsa_io - Specify default node gain in UCM
Some boards require different default gain rather than 2000 dBm defined in cras_system_state. Now we expose a new UCM config DefaultNodeGain so we can use different default node gain for board customization. Note that user can still change gain after the node is selected, so AGC still works either on system gain or on node gain. BUG=chrome-os-partner:60744 TEST=make check TEST=On chell, add DefaultNodeGain to "Mic" and "Internal Mic" section. Select active input node and see recorded audio gain is changed. TEST=On chell, switch active node, goto appr.tc and append ?debug=loopback in the URL, and check AGC in WebRTC works. Change-Id: Ibf8ad7a1252d4a53ba700e5dc355efa7ce3e70f1 Reviewed-on: https://chromium-review.googlesource.com/430528 Commit-Ready: Cheng-Yi Chiang <cychiang@chromium.org> Tested-by: Cheng-Yi Chiang <cychiang@chromium.org> Reviewed-by: Cheng-Yi Chiang <cychiang@chromium.org>
-rw-r--r--cras/src/server/cras_alsa_io.c39
-rw-r--r--cras/src/server/cras_alsa_ucm.c15
-rw-r--r--cras/src/server/cras_alsa_ucm.h11
-rw-r--r--cras/src/tests/alsa_io_unittest.cc83
-rw-r--r--cras/src/tests/alsa_ucm_unittest.cc25
5 files changed, 165 insertions, 8 deletions
diff --git a/cras/src/server/cras_alsa_io.c b/cras/src/server/cras_alsa_io.c
index c0434d6b..59cfd182 100644
--- a/cras/src/server/cras_alsa_io.c
+++ b/cras/src/server/cras_alsa_io.c
@@ -708,9 +708,11 @@ static void set_alsa_mute(struct cras_iodev *iodev)
set_alsa_mute_control(aio, cras_system_get_mute());
}
-/* Sets the capture gain to the current system input gain level, given in dBFS.
+/*
+ * Sets the capture gain to the current system input gain level, given in dBFS.
* Set mute based on the system mute state. This gain can be positive or
- * negative and might be adjusted often if and app is running an AGC. */
+ * negative and might be adjusted often if an app is running an AGC.
+ */
static void set_alsa_capture_gain(struct cras_iodev *iodev)
{
const struct alsa_io *aio = (const struct alsa_io *)iodev;
@@ -724,14 +726,15 @@ static void set_alsa_capture_gain(struct cras_iodev *iodev)
/* Only set the volume if the dev is active. */
if (!has_handle(aio))
return;
+ gain = cras_iodev_adjust_active_node_gain(
+ iodev, cras_system_get_capture_gain());
- gain = cras_system_get_capture_gain();
- ain = get_active_input(aio);
- if (ain)
- gain += ain->base.capture_gain;
/* Set hardware gain to 0dB if software gain is needed. */
if (cras_iodev_software_volume_needed(iodev))
gain = 0;
+
+ ain = get_active_input(aio);
+
cras_alsa_mixer_set_capture_dBFS(
aio->mixer,
gain,
@@ -750,8 +753,10 @@ static int set_alsa_node_swapped(struct cras_iodev *iodev,
return ucm_enable_swap_mode(aio->ucm, node->name, enable);
}
-/* Initializes the device settings and registers for callbacks when system
- * settings have been changed.
+/*
+ * Initializes the device settings according to system volume, mute, gain
+ * settings.
+ * Updates system capture gain limits based on current active device/node.
*/
static void init_device_settings(struct alsa_io *aio)
{
@@ -1030,6 +1035,23 @@ static void set_input_node_software_volume_needed(
" in UCM", input->base.name, max_software_gain);
}
+static void set_input_default_node_gain(struct alsa_input_node *input,
+ struct alsa_io *aio)
+{
+ long default_node_gain;
+ int rc;
+
+ if (!aio->ucm)
+ return;
+
+ rc = ucm_get_default_node_gain(aio->ucm, input->base.name,
+ &default_node_gain);
+ if (rc)
+ return;
+
+ input->base.capture_gain = default_node_gain;
+}
+
static void check_auto_unplug_output_node(struct alsa_io *aio,
struct cras_ionode *node,
int plugged)
@@ -1170,6 +1192,7 @@ static struct alsa_input_node *new_input(struct alsa_io *aio,
strncpy(input->base.name, name, sizeof(input->base.name) - 1);
set_node_initial_state(&input->base, aio->card_type);
set_input_node_software_volume_needed(input, aio);
+ set_input_default_node_gain(input, aio);
if (aio->ucm) {
/* Check mic positions only for internal mic. */
diff --git a/cras/src/server/cras_alsa_ucm.c b/cras/src/server/cras_alsa_ucm.c
index ed332f04..8aa4891a 100644
--- a/cras/src/server/cras_alsa_ucm.c
+++ b/cras/src/server/cras_alsa_ucm.c
@@ -35,6 +35,8 @@ static const char coupled_mixers[] = "CoupledMixers";
/* Set this value in a SectionDevice to specify the maximum software gain in dBm
* and enable software gain on this node. */
static const char max_software_gain[] = "MaxSoftwareGain";
+/* Set this value in a SectionDevice to specify the default node gain in dBm. */
+static const char default_node_gain[] = "DefaultNodeGain";
static const char hotword_model_prefix[] = "Hotword Model";
static const char fully_specified_ucm_var[] = "FullySpecifiedUCM";
static const char main_volume_names[] = "MainVolumeNames";
@@ -649,6 +651,19 @@ int ucm_get_max_software_gain(struct cras_use_case_mgr *mgr, const char *dev,
return 0;
}
+int ucm_get_default_node_gain(struct cras_use_case_mgr *mgr, const char *dev,
+ long *gain)
+{
+ int value;
+ int rc;
+
+ rc = get_int(mgr, default_node_gain, dev, uc_verb(mgr), &value);
+ if (rc)
+ return rc;
+ *gain = value;
+ return 0;
+}
+
const char *ucm_get_device_name_for_dev(
struct cras_use_case_mgr *mgr, const char *dev,
enum CRAS_STREAM_DIRECTION direction)
diff --git a/cras/src/server/cras_alsa_ucm.h b/cras/src/server/cras_alsa_ucm.h
index 50563af8..622bbf85 100644
--- a/cras/src/server/cras_alsa_ucm.h
+++ b/cras/src/server/cras_alsa_ucm.h
@@ -204,6 +204,17 @@ unsigned int ucm_get_disable_software_volume(struct cras_use_case_mgr *mgr);
int ucm_get_max_software_gain(struct cras_use_case_mgr *mgr, const char *dev,
long *gain);
+/* Gets the value for default node gain.
+ * Args:
+ * mgr - The cras_use_case_mgr pointer returned from alsa_ucm_create.
+ * dev - The device to check for default node gain.
+ * gain - The pointer to the returned value;
+ * Returns:
+ * 0 on success, other error codes on failure.
+ */
+int ucm_get_default_node_gain(struct cras_use_case_mgr *mgr, const char *dev,
+ long *gain);
+
/* Gets the device name of this device on the card..
*
* Args:
diff --git a/cras/src/tests/alsa_io_unittest.cc b/cras/src/tests/alsa_io_unittest.cc
index 82a39dd6..5a0d0e86 100644
--- a/cras/src/tests/alsa_io_unittest.cc
+++ b/cras/src/tests/alsa_io_unittest.cc
@@ -146,6 +146,7 @@ static int cras_alsa_resume_appl_ptr_ahead;
static int ucm_get_enable_htimestamp_flag_ret;
static const struct cras_volume_curve *fake_get_dBFS_volume_curve_val;
static int cras_iodev_dsp_set_swap_mode_for_node_called;
+static std::map<std::string, long> ucm_get_default_node_gain_values;
void ResetStubData() {
cras_alsa_open_called = 0;
@@ -231,6 +232,7 @@ void ResetStubData() {
ucm_get_enable_htimestamp_flag_ret = 0;
fake_get_dBFS_volume_curve_val = NULL;
cras_iodev_dsp_set_swap_mode_for_node_called = 0;
+ ucm_get_default_node_gain_values.clear();
}
static long fake_get_dBFS(const struct cras_volume_curve *curve, size_t volume)
@@ -520,6 +522,40 @@ TEST(AlsaIoInit, UseSoftwareGain) {
alsa_iodev_destroy(iodev);
}
+TEST(AlsaIoInit, SoftwareGainWithDefaultNodeGain) {
+ struct cras_iodev *iodev;
+ struct cras_use_case_mgr * const fake_ucm = (struct cras_use_case_mgr*)3;
+ long system_gain = 500;
+ long default_node_gain = -1000;
+
+ ResetStubData();
+
+ // Use software gain.
+ ucm_get_max_software_gain_ret_value = 0;
+ ucm_get_max_software_gain_value = 2000;
+
+ // Set default node gain to -1000 dBm.
+ ucm_get_default_node_gain_values["Internal Mic"] = default_node_gain;
+
+ // Assume this is the first device so it gets internal mic node name.
+ iodev = alsa_iodev_create_with_default_parameters(0, NULL,
+ ALSA_CARD_TYPE_INTERNAL, 1,
+ fake_mixer, fake_config,
+ fake_ucm,
+ CRAS_STREAM_INPUT);
+ ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev));
+
+ // Gain on node is 300 dBm.
+ iodev->active_node->capture_gain = default_node_gain;
+
+ // cras_iodev will call cras_iodev_adjust_active_node_gain to get gain for
+ // software gain.
+ ASSERT_EQ(system_gain + default_node_gain,
+ cras_iodev_adjust_active_node_gain(iodev, system_gain));
+
+ alsa_iodev_destroy(iodev);
+}
+
TEST(AlsaIoInit, RouteBasedOnJackCallback) {
struct alsa_io *aio;
struct cras_alsa_mixer * const fake_mixer = (struct cras_alsa_mixer*)2;
@@ -631,6 +667,42 @@ TEST(AlsaIoInit, OpenCapture) {
free(fake_format);
}
+TEST(AlsaIoInit, OpenCaptureSetCaptureGainWithDefaultNodeGain) {
+ struct cras_iodev *iodev;
+ struct cras_audio_format format;
+ struct cras_use_case_mgr * const fake_ucm = (struct cras_use_case_mgr*)3;
+ long system_gain = 2000;
+ long default_node_gain = -1000;
+
+ ResetStubData();
+ // Set default node gain to -1000 dBm.
+ ucm_get_default_node_gain_values["Internal Mic"] = default_node_gain;
+
+ // Assume this is the first device so it gets internal mic node name.
+ iodev = alsa_iodev_create_with_default_parameters(0, NULL,
+ ALSA_CARD_TYPE_INTERNAL, 1,
+ fake_mixer, fake_config,
+ fake_ucm,
+ CRAS_STREAM_INPUT);
+ ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev));
+
+ cras_iodev_set_format(iodev, &format);
+
+ // Check the default node gain is the same as what specified in UCM.
+ EXPECT_EQ(default_node_gain, iodev->active_node->capture_gain);
+ // System gain is set to 2000 dBm.
+ sys_get_capture_gain_return_value = system_gain;
+
+ iodev->open_dev(iodev);
+ iodev->close_dev(iodev);
+
+ // Hardware gain is set to 2000 - 1000 dBm.
+ EXPECT_EQ(system_gain + default_node_gain, alsa_mixer_set_capture_dBFS_value);
+
+ alsa_iodev_destroy(iodev);
+ free(fake_format);
+}
+
TEST(AlsaIoInit, OpenCaptureSetCaptureGainWithSoftwareGain) {
struct cras_iodev *iodev;
struct cras_audio_format format;
@@ -2640,6 +2712,17 @@ const char *cras_alsa_jack_get_ucm_device(const struct cras_alsa_jack *jack)
return NULL;
}
+int ucm_get_default_node_gain(struct cras_use_case_mgr *mgr, const char *dev,
+ long *gain)
+{
+ if (ucm_get_default_node_gain_values.find(dev) ==
+ ucm_get_default_node_gain_values.end())
+ return 1;
+
+ *gain = ucm_get_default_node_gain_values[dev];
+ return 0;
+}
+
void cras_iodev_init_audio_area(struct cras_iodev *iodev,
int num_channels) {
}
diff --git a/cras/src/tests/alsa_ucm_unittest.cc b/cras/src/tests/alsa_ucm_unittest.cc
index c3e31512..822ef9eb 100644
--- a/cras/src/tests/alsa_ucm_unittest.cc
+++ b/cras/src/tests/alsa_ucm_unittest.cc
@@ -784,6 +784,31 @@ TEST(AlsaUcm, MaxSoftwareGain) {
ASSERT_TRUE(ret);
}
+TEST(AlsaUcm, DefaultNodeGain) {
+ struct cras_use_case_mgr *mgr = &cras_ucm_mgr;
+ long default_node_gain;
+ int ret;
+ std::string id = "=DefaultNodeGain/Internal Mic/HiFi";
+ std::string value = "-2000";
+
+ ResetStubData();
+
+ /* Value can be found in UCM. */
+ snd_use_case_get_value[id] = value;
+
+ ret = ucm_get_default_node_gain(mgr, "Internal Mic", &default_node_gain);
+
+ EXPECT_EQ(0, ret);
+ EXPECT_EQ(-2000, default_node_gain);
+
+ ResetStubData();
+
+ /* Value can not be found in UCM. */
+ ret = ucm_get_default_node_gain(mgr, "Internal Mic", &default_node_gain);
+
+ ASSERT_TRUE(ret);
+}
+
TEST(AlsaUcm, UseFullySpecifiedUCMConfig) {
struct cras_use_case_mgr *mgr = &cras_ucm_mgr;
int fully_specified_flag;