From cf12420286b5da0cb754f3d87ef4409c2ba9eabf Mon Sep 17 00:00:00 2001 From: Eddy Hsu Date: Wed, 11 Sep 2024 21:26:15 +0000 Subject: [PATCH] CRAS: add UCM controls for spatial audio. Add UCM controls to enable/disable spatial audio. Configure spatial audio when opening devices to enable the switch of spatial audio ability. BUG=b:317748801 TEST=FEATURES=test USE=asan emerge-${BOARD} adhd, bazel test //... Change-Id: I128b6e5af413e7116a92abd414de7e5bed0a7c4f Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/adhd/+/5854773 Commit-Queue: Eddy Hsu Reviewed-by: Li-Yu Yu Tested-by: Li-Yu Yu --- cras/src/server/cras_alsa_io.c | 20 ++++++++++++++++++++ cras/src/server/cras_alsa_ucm.c | 10 ++++++++++ cras/src/server/cras_alsa_ucm.h | 20 ++++++++++++++++++++ cras/src/server/cras_dbus_control.c | 1 + cras/src/server/cras_iodev.h | 3 +++ cras/src/server/cras_iodev_list.c | 13 +++++++++++++ cras/src/server/cras_iodev_list.h | 4 ++++ cras/src/tests/BUILD.bazel | 1 + cras/src/tests/alsa_io_unittest.cc | 12 ++++++++++++ cras/src/tests/cras_alsa_usb_io_unittest.cc | 12 ++++++++++++ cras/src/tests/dbus_control_unittest.cc | 3 +++ 11 files changed, 99 insertions(+) diff --git a/cras/src/server/cras_alsa_io.c b/cras/src/server/cras_alsa_io.c index b9c1f1278..aa6b8ca94 100644 --- a/cras/src/server/cras_alsa_io.c +++ b/cras/src/server/cras_alsa_io.c @@ -22,6 +22,7 @@ #include "cras/common/check.h" #include "cras/server/cras_trace.h" +#include "cras/server/s2/s2.h" #include "cras/src/common/cras_alsa_card_info.h" #include "cras/src/common/cras_log.h" #include "cras/src/common/cras_string.h" @@ -85,6 +86,8 @@ struct alsa_io { bool dsp_noise_suppression_enabled; // If gain control is enabled in DSP bool dsp_gain_control_enabled; + // If spatial audio is enabled in DSP + bool dsp_spatial_audio_enabled; // Use case of this device according to UCM. enum CRAS_USE_CASE use_case; // Pointer to the shared group info. NULL if the device is not in a group. @@ -2128,6 +2131,18 @@ static void cras_iodev_update_speaker_rotation(struct cras_iodev* iodev) { cras_iodev_update_dsp(iodev); } +static void cras_iodev_update_spatial_audio(struct cras_iodev* iodev) { + struct alsa_io* aio = (struct alsa_io*)iodev; + struct cras_use_case_mgr* ucm = aio->common.ucm; + + if (iodev->active_node && ucm_node_spatial_audio_exists(ucm)) { + bool enable_dsp_spatial_audio = cras_s2_get_spatial_audio_enabled(); + + ucm_enable_node_spatial_audio(ucm, enable_dsp_spatial_audio); + aio->dsp_spatial_audio_enabled = enable_dsp_spatial_audio; + } +} + /* * Exported Interface. */ @@ -2297,6 +2312,11 @@ struct cras_iodev* alsa_iodev_create( iodev->software_volume_needed = 1; } + // Only internal speaker supports spatial audio. + if (direction == CRAS_STREAM_OUTPUT && strstr(dev_name, INTERNAL_SPEAKER)) { + iodev->spatial_audio_changed = cras_iodev_update_spatial_audio; + } + /* Add this now so that cleanup of the iodev (in case of error or card * card removal will function as expected. */ cras_iodev_list_add(&aio->common.base); diff --git a/cras/src/server/cras_alsa_ucm.c b/cras/src/server/cras_alsa_ucm.c index 5eb79ec72..368aef65c 100644 --- a/cras/src/server/cras_alsa_ucm.c +++ b/cras/src/server/cras_alsa_ucm.c @@ -65,6 +65,7 @@ static const char rtc_proc_echo_cancellation_modifier[] = static const char rtc_proc_noise_suppression_modifier[] = "RTC Proc Noise Suppression"; static const char rtc_proc_gain_control_modifier[] = "RTC Proc Gain Control"; +static const char spatial_audio_modifier[] = "Internal Speaker Spatial Audio"; // SectionModifier prefixes and suffixes. static const char hotword_model_prefix[] = "Hotword Model"; @@ -631,6 +632,15 @@ int ucm_enable_node_noise_cancellation(struct cras_use_case_mgr* mgr, return ucm_modifier_try_enable(mgr, enable, node_modifier_name); } +int inline ucm_node_spatial_audio_exists(struct cras_use_case_mgr* mgr) { + return ucm_mod_exists_with_name(mgr, spatial_audio_modifier); +} + +int inline ucm_enable_node_spatial_audio(struct cras_use_case_mgr* mgr, + int enable) { + return ucm_modifier_try_enable(mgr, enable, spatial_audio_modifier); +} + int ucm_set_enabled(struct cras_use_case_mgr* mgr, const char* dev, int enable) { diff --git a/cras/src/server/cras_alsa_ucm.h b/cras/src/server/cras_alsa_ucm.h index 47b808ea5..52696ce2b 100644 --- a/cras/src/server/cras_alsa_ucm.h +++ b/cras/src/server/cras_alsa_ucm.h @@ -194,6 +194,26 @@ int ucm_enable_node_noise_cancellation(struct cras_use_case_mgr* mgr, const char* node_name, int enable); +/* Checks if modifier of spatial audio in ucm. + * Args: + * mgr - The cras_use_case_mgr pointer returned from alsa_ucm_create. + * node_name - The node name. + * Returns: + * 1 if it exists, 0 otherwise. + */ +int ucm_node_spatial_audio_exists(struct cras_use_case_mgr* mgr); + +/* Enables or disables spatial audio. First checks if the modifier is + * already enabled or disabled. + * Args: + * mgr - The cras_use_case_mgr pointer returned from alsa_ucm_create. + * node_name - The node name. + * enable - Enable device if non-zero. + * Returns: + * 0 on success or negative error code on failure. + */ +int ucm_enable_node_spatial_audio(struct cras_use_case_mgr* mgr, int enable); + /* Enables or disables a UCM device. First checks if the device is already * enabled or disabled. * Args: diff --git a/cras/src/server/cras_dbus_control.c b/cras/src/server/cras_dbus_control.c index 48b83b11f..6e7f3ccb0 100644 --- a/cras/src/server/cras_dbus_control.c +++ b/cras/src/server/cras_dbus_control.c @@ -1531,6 +1531,7 @@ static DBusHandlerResult handle_set_spatial_audio_enabled(DBusConnection* conn, } cras_s2_set_spatial_audio_enabled(enabled); + cras_iodev_list_update_for_spatial_audio(); return send_empty_reply(conn, message); } diff --git a/cras/src/server/cras_iodev.h b/cras/src/server/cras_iodev.h index 24a35d45b..948fce899 100644 --- a/cras/src/server/cras_iodev.h +++ b/cras/src/server/cras_iodev.h @@ -327,6 +327,9 @@ struct cras_iodev { // time with MONOTONIC_RAW clock as the timestamp. int (*get_htimestamp)(const struct cras_iodev* iodev, struct timespec* ts); + // Callback when spatial audio is changed in system state + void (*spatial_audio_changed)(struct cras_iodev* iodev); + // The audio format being rendered or captured to hardware. struct cras_audio_format* format; // Rate estimator to estimate the actual device rate. diff --git a/cras/src/server/cras_iodev_list.c b/cras/src/server/cras_iodev_list.c index 642ec52b0..a04326a89 100644 --- a/cras/src/server/cras_iodev_list.c +++ b/cras/src/server/cras_iodev_list.c @@ -2929,3 +2929,16 @@ bool cras_iodev_list_is_floop_dev(int dev_idx) { return dev && dev->active_node && dev->active_node->type == CRAS_NODE_TYPE_FLOOP; } + +static inline void update_spatial_audio_inner(struct cras_iodev* iodev) { + if (iodev->spatial_audio_changed) { + iodev->spatial_audio_changed(iodev); + } +} + +void cras_iodev_list_update_for_spatial_audio() { + struct cras_iodev* iodev; + + FOR_ALL_DEVS(devs, CRAS_STREAM_OUTPUT, iodev, + update_spatial_audio_inner(iodev)); +} diff --git a/cras/src/server/cras_iodev_list.h b/cras/src/server/cras_iodev_list.h index 111b115c9..188555e97 100644 --- a/cras/src/server/cras_iodev_list.h +++ b/cras/src/server/cras_iodev_list.h @@ -359,6 +359,10 @@ bool cras_iodev_list_is_utility_stream(const struct cras_rstream* stream); /* Returns true if a given dev_idx is a floop device */ bool cras_iodev_list_is_floop_dev(int dev_idx); +/* Sets the state of spatial audio for output devices. + */ +void cras_iodev_list_update_for_spatial_audio(); + #ifdef __cplusplus } // extern "C" #endif diff --git a/cras/src/tests/BUILD.bazel b/cras/src/tests/BUILD.bazel index 4d4af05a7..216c6e5e5 100644 --- a/cras/src/tests/BUILD.bazel +++ b/cras/src/tests/BUILD.bazel @@ -193,6 +193,7 @@ cc_test( "//cras/common:check", "//cras/server:cras_trace", "//cras/server/platform/dlc:cc", + "//cras/server/s2:cc", "//cras/src/common:all_headers", "//cras/src/common:cras_log", "//cras/src/server:all_headers", diff --git a/cras/src/tests/alsa_io_unittest.cc b/cras/src/tests/alsa_io_unittest.cc index 85d8f4a8d..ac02900fe 100644 --- a/cras/src/tests/alsa_io_unittest.cc +++ b/cras/src/tests/alsa_io_unittest.cc @@ -2772,6 +2772,10 @@ int cras_system_get_using_default_volume_curve_for_usb_audio_device() { return sys_using_default_volume_curve_for_usb_audio_device_value; } +bool cras_system_get_spatial_audio_enabled() { + return false; +} + // From cras_alsa_mixer. void cras_alsa_mixer_set_dBFS(struct cras_alsa_mixer* m, long dB_level, @@ -3050,6 +3054,14 @@ int ucm_node_echo_cancellation_exists(struct cras_use_case_mgr* mgr) { return ucm_node_echo_cancellation_exists_ret_value; } +int ucm_node_spatial_audio_exists(struct cras_use_case_mgr* mgr) { + return 0; +} + +int ucm_enable_node_spatial_audio(struct cras_use_case_mgr* mgr, int enable) { + return 0; +} + struct cras_volume_curve* cras_volume_curve_create_simple_step(long max_volume, long range) { cras_volume_curve_create_simple_step_called++; diff --git a/cras/src/tests/cras_alsa_usb_io_unittest.cc b/cras/src/tests/cras_alsa_usb_io_unittest.cc index 3ddecdf14..3ad46ad6a 100644 --- a/cras/src/tests/cras_alsa_usb_io_unittest.cc +++ b/cras/src/tests/cras_alsa_usb_io_unittest.cc @@ -1204,6 +1204,10 @@ int cras_system_aec_on_dsp_supported() { return sys_aec_on_dsp_supported_return_value; } +bool cras_system_get_spatial_audio_enabled() { + return false; +} + // From cras_alsa_mixer. void cras_alsa_mixer_set_dBFS(struct cras_alsa_mixer* m, long dB_level, @@ -1487,6 +1491,14 @@ int ucm_node_echo_cancellation_exists(struct cras_use_case_mgr* mgr) { return ucm_node_echo_cancellation_exists_ret_value; } +int ucm_node_spatial_audio_exists(struct cras_use_case_mgr* mgr) { + return 0; +} + +int ucm_enable_node_spatial_audio(struct cras_use_case_mgr* mgr, int enable) { + return 0; +} + struct cras_volume_curve* cras_volume_curve_create_simple_step(long max_volume, long range) { cras_volume_curve_create_simple_step_called++; diff --git a/cras/src/tests/dbus_control_unittest.cc b/cras/src/tests/dbus_control_unittest.cc index 934879adc..a87e8a4c4 100644 --- a/cras/src/tests/dbus_control_unittest.cc +++ b/cras/src/tests/dbus_control_unittest.cc @@ -323,4 +323,7 @@ void cras_observer_remove(struct cras_observer_client* client) { void cras_system_set_force_respect_ui_gains_enabled(bool enabled) { return; } +void cras_iodev_list_update_for_spatial_audio() { + return; +} } // extern "C"