Skip to content

Commit

Permalink
mic_privacy: initial implementation
Browse files Browse the repository at this point in the history
Audio privacy feature allows end user to directly
control if user space applications receive actual
data from input devices (microphones). The control
is bypassing application level settings or operating
system controls (like audio endpoint volume).

Signed-off-by: Michal Bukowski <[email protected]>
  • Loading branch information
mbukowsk authored and abonislawski committed Feb 8, 2025
1 parent bcdc190 commit f266ba7
Show file tree
Hide file tree
Showing 22 changed files with 522 additions and 30 deletions.
1 change: 1 addition & 0 deletions app/boards/intel_adsp_ace30_ptl.conf
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ CONFIG_INTEL_ADSP_IPC=y
CONFIG_INTEL_ADSP_TIMER=y
CONFIG_MM_DRV_INTEL_ADSP_TLB_REMAP_UNUSED_RAM=y
CONFIG_SYS_CLOCK_TICKS_PER_SEC=12000
CONFIG_MICROPHONE_PRIVACY=y

# Zephyr / power settings
CONFIG_ADSP_IMR_CONTEXT_SAVE=y
Expand Down
5 changes: 4 additions & 1 deletion posix/include/sof/lib/dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <rtos/atomic.h>
#include <rtos/bit.h>
#include <rtos/alloc.h>
#include <sof/audio/component.h>
#include <sof/lib/io.h>
#include <sof/lib/memory.h>
#include <rtos/sof.h>
Expand All @@ -34,6 +35,7 @@
#endif

struct comp_buffer;
struct comp_dev;

/** \addtogroup sof_dma_drivers DMA Drivers
* DMA Drivers API specification.
Expand Down Expand Up @@ -550,7 +552,8 @@ int dma_buffer_copy_to(struct comp_buffer __sparse_cache *source,
* conversion function. DMA buffer consume should be performed after the data has been copied
* to all sinks.
*/
int stream_copy_from_no_consume(struct comp_buffer __sparse_cache *source,
int stream_copy_from_no_consume(struct comp_dev *dev,
struct comp_buffer __sparse_cache *source,
struct comp_buffer __sparse_cache *sink,
dma_process_func process,
uint32_t source_bytes, uint32_t chmap);
Expand Down
3 changes: 3 additions & 0 deletions src/audio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ if(NOT CONFIG_COMP_MODULE_SHARED_LIBRARY_BUILD)
if(CONFIG_COMP_VOLUME)
add_subdirectory(volume)
endif()
if(CONFIG_MICROPHONE_PRIVACY)
add_subdirectory(mic_privacy_manager)
endif()
subdirs(pipeline)
add_subdirectory(google)
if(CONFIG_COMP_CHAIN_DMA)
Expand Down
10 changes: 10 additions & 0 deletions src/audio/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@ config IPC4_GATEWAY
host and DSP without using DMA: via memory window (audio payload) and
IPC4 messages (set/get/flush commands).

config MICROPHONE_PRIVACY
bool "Microphone privacy"
default n
depends on IPC_MAJOR_4
help
Audio privacy feature allows end user to directly control if user space
applications receive actual data from input devices (microphones).
The control is bypassing application level settings or operating system
controls (like audio endpoint volume).

rsource "up_down_mixer/Kconfig"

config COMP_BLOB
Expand Down
14 changes: 14 additions & 0 deletions src/audio/base_fw.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
#include <sof/debug/telemetry/performance_monitor.h>
#include <sof/debug/telemetry/telemetry.h>
#include <sof/debug/telemetry/performance_monitor.h>
#if CONFIG_MICROPHONE_PRIVACY
#include <sof/audio/mic_privacy_manager.h>
#endif
/* FIXME:
* Builds for some platforms like tgl fail because their defines related to memory windows are
* already defined somewhere else. Remove this ifdef after it's cleaned up
Expand All @@ -49,6 +52,7 @@ static int basefw_config(uint32_t *data_offset, char *data)
uint16_t version[4] = {SOF_MAJOR, SOF_MINOR, SOF_MICRO, SOF_BUILD};
struct sof_tlv *tuple = (struct sof_tlv *)data;
struct ipc4_scheduler_config sche_cfg;
struct privacy_capabilities priv_caps;
uint32_t plat_data_offset = 0;
uint32_t log_bytes_size = 0;

Expand Down Expand Up @@ -120,6 +124,16 @@ static int basefw_config(uint32_t *data_offset, char *data)
tlv_value_uint32_set(tuple, IPC4_FW_CONTEXT_SAVE,
IS_ENABLED(CONFIG_ADSP_IMR_CONTEXT_SAVE));

#if CONFIG_MICROPHONE_PRIVACY
tuple = tlv_next(tuple);

priv_caps.privacy_version = 1;
priv_caps.capabilities_length = 1;
priv_caps.capabilities[0] = mic_privacy_get_policy_register();

tlv_value_set(tuple, IPC4_PRIVACY_CAPS_HW_CFG, sizeof(priv_caps), &priv_caps);
#endif

tuple = tlv_next(tuple);

/* add platform specific tuples */
Expand Down
84 changes: 83 additions & 1 deletion src/audio/copier/copier.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
#include "host_copier.h"
#include "dai_copier.h"
#include "ipcgtw_copier.h"
#if CONFIG_MICROPHONE_PRIVACY
#include <zephyr/drivers/mic_privacy.h>
#endif

#if CONFIG_ZEPHYR_NATIVE_DRIVERS
#include <zephyr/drivers/dai.h>
Expand All @@ -51,6 +54,8 @@ SOF_DEFINE_REG_UUID(copier);

DECLARE_TR_CTX(copier_comp_tr, SOF_UUID(copier_uuid), LOG_LEVEL_INFO);

static int mic_privacy_configure(struct comp_dev *dev, struct copier_data *cd);

static int copier_init(struct processing_module *mod)
{
union ipc4_connector_node_id node_id;
Expand Down Expand Up @@ -131,6 +136,15 @@ static int copier_init(struct processing_module *mod)
comp_err(dev, "unable to create host");
goto error;
}
#if CONFIG_MICROPHONE_PRIVACY
if (cd->direction == SOF_IPC_STREAM_CAPTURE && node_id.f.dma_type == ipc4_hda_host_output_class) {
ret = mic_privacy_configure(dev, cd);
if (ret < 0) {
comp_err(dev, "unable to configure mic privacy");
goto error;
}
}
#endif
break;
case ipc4_hda_link_output_class:
case ipc4_hda_link_input_class:
Expand All @@ -144,6 +158,15 @@ static int copier_init(struct processing_module *mod)
comp_err(dev, "unable to create dai");
goto error;
}
#if CONFIG_MICROPHONE_PRIVACY
if (cd->direction == SOF_IPC_STREAM_CAPTURE) {
ret = mic_privacy_configure(dev, cd);
if (ret < 0) {
comp_err(dev, "unable to configure mic privacy");
goto error;
}
}
#endif
break;
#if CONFIG_IPC4_GATEWAY
case ipc4_ipc_output_class:
Expand Down Expand Up @@ -198,7 +221,10 @@ static int copier_free(struct processing_module *mod)
default:
break;
}

#if CONFIG_MICROPHONE_PRIVACY
if (cd->mic_priv)
rfree(cd->mic_priv);
#endif
if (cd)
rfree(cd->gtw_cfg);
rfree(cd);
Expand Down Expand Up @@ -1098,6 +1124,62 @@ static int copier_unbind(struct processing_module *mod, void *data)
return 0;
}

#if CONFIG_MICROPHONE_PRIVACY
static void mic_privacy_event(void *arg, enum notify_id type, void *data)
{
struct mic_privacy_data *mic_priv_data = arg;
struct mic_privacy_settings *mic_privacy_settings = data;

if (type == NOTIFIER_ID_MIC_PRIVACY_STATE_CHANGE) {
LOG_INF("mic_privacy_event, state1 = %d, state2 = %d ", mic_privacy_settings->mic_privacy_state, mic_priv_data->mic_privacy_state);

if (mic_privacy_settings->mic_privacy_state == MIC_PRIV_UNMUTED) {
if (mic_priv_data->mic_privacy_state == MIC_PRIV_MUTED) {
mic_priv_data->mic_privacy_state = MIC_PRIV_FADE_IN;
LOG_INF("mic_privacy_event switch to FADE_IN");
}
} else {
/* In case when mute would be triggered before copier instantiation. */
if (mic_priv_data->mic_privacy_state != MIC_PRIV_MUTED) {
mic_priv_data->mic_privacy_state = MIC_PRIV_FADE_OUT;
LOG_INF("mic_privacy_event switch to FADE_OUT");
}
}
mic_priv_data->max_ramp_time_in_ms = (mic_privacy_settings->max_ramp_time * 1000) / ADSP_RTC_FREQUENCY;
}
}

static int mic_privacy_configure(struct comp_dev *dev, struct copier_data *cd)
{
struct mic_privacy_data *mic_priv_data;
int ret;

mic_priv_data = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(struct mic_privacy_data));
if (!mic_priv_data) {
return -ENOMEM;
}

mic_priv_data->audio_freq = cd->config.base.audio_fmt.sampling_frequency;

uint32_t zeroing_wait_time = (get_dma_zeroing_wait_time() * 1000) / ADSP_RTC_FREQUENCY;

ret = copier_gain_set_params(dev, &mic_priv_data->mic_priv_gain_params, zeroing_wait_time, SOF_DAI_INTEL_NONE);
if (ret != 0) {
rfree(mic_priv_data);
return ret;
}

cd->mic_priv = mic_priv_data;

ret = notifier_register(cd->mic_priv, NULL, NOTIFIER_ID_MIC_PRIVACY_STATE_CHANGE,
mic_privacy_event, 0);
if (ret != 0) {
rfree(mic_priv_data);

return ret;
}
#endif

static struct module_endpoint_ops copier_endpoint_ops = {
.get_total_data_processed = copier_get_processed_data,
.position = copier_position,
Expand Down
11 changes: 11 additions & 0 deletions src/audio/copier/copier.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
#include <sof/compiler_attributes.h>
#include <sof/audio/buffer.h>
#include <sof/audio/pcm_converter.h>
#if CONFIG_MICROPHONE_PRIVACY
#include <sof/lib/notifier.h>
#include <sof/audio/mic_privacy_manager.h>
#endif

static const uint32_t INVALID_QUEUE_ID = 0xFFFFFFFF;

Expand Down Expand Up @@ -270,6 +274,9 @@ struct copier_data {
uint32_t channels[IPC4_ALH_MAX_NUMBER_OF_GTW];
uint32_t chan_map[IPC4_ALH_MAX_NUMBER_OF_GTW];
struct ipcgtw_data *ipcgtw_data;
#if CONFIG_MICROPHONE_PRIVACY
struct mic_privacy_data *mic_priv;
#endif
};

int apply_attenuation(struct comp_dev *dev, struct copier_data *cd,
Expand All @@ -291,4 +298,8 @@ enum sof_ipc_stream_direction

void copier_update_params(struct copier_data *cd, struct comp_dev *dev,
struct sof_ipc_stream_params *params);

#if CONFIG_MICROPHONE_PRIVACY
void mic_privacy_event(void *arg, enum notify_id type, void *data);
#endif
#endif
3 changes: 2 additions & 1 deletion src/audio/copier/copier_dai.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,8 @@ static int copier_dai_init(struct comp_dev *dev,
}
cd->dd[index]->gain_data = gain_data;

ret = copier_gain_set_params(dev, cd->dd[index]->gain_data, GAIN_DEFAULT_FADE_PERIOD);
ret = copier_gain_set_params(dev, cd->dd[index]->gain_data, GAIN_DEFAULT_FADE_PERIOD,
cd->dd[index]->dai->type);
if (ret < 0) {
comp_err(dev, "Failed to set gain params!");
goto gain_free;
Expand Down
25 changes: 14 additions & 11 deletions src/audio/copier/copier_gain.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@

LOG_MODULE_DECLARE(copier, CONFIG_SOF_LOG_LEVEL);

int copier_gain_set_params(struct comp_dev *dev, struct copier_gain_params *gain_params, uint32_t fade_period)
int copier_gain_set_params(struct comp_dev *dev,
struct copier_gain_params *gain_params,
uint32_t fade_period,
enum sof_ipc_dai_type dai_type)
{
struct processing_module *mod = comp_mod(dev);
struct copier_data *cd = module_get_private_data(mod);
Expand All @@ -27,7 +30,7 @@ int copier_gain_set_params(struct comp_dev *dev, struct copier_gain_params *gain
/* Set basic gain parameters */
copier_gain_set_basic_params(dev, gain_params, ipc4_cfg);

switch (dd->dai->type) {
switch (dai_type) {
case SOF_DAI_INTEL_DMIC:
{
struct dmic_config_data *dmic_cfg = cd->gtw_cfg;
Expand All @@ -42,13 +45,13 @@ int copier_gain_set_params(struct comp_dev *dev, struct copier_gain_params *gain
/* Get fade period from DMIC blob */
fade_period = dmic_glb_cfg->ext_global_cfg.fade_in_period;
/* Convert and assign silence and fade length values */
dd->gain_data->silence_sg_length =
gain_params->silence_sg_length =
frames * dmic_glb_cfg->ext_global_cfg.silence_period;
dd->gain_data->fade_sg_length = frames * fade_period;
gain_params->fade_sg_length = frames * fade_period;
}
break;
default:
comp_info(dev, "Apply default fade period for dai type %d", dd->dai->type);
comp_info(dev, "Apply default fade period for dai type %d", dai_type);
break;
}

Expand Down Expand Up @@ -149,7 +152,10 @@ int copier_gain_dma_control(union ipc4_connector_node_id node, const char *confi
break;
}

ret = copier_set_gain(dev, cd->dd[0], gain_data);
struct ipc4_copier_module_cfg *copier_cfg = cd->dd[0]->dai_spec_config;
const int channels = copier_cfg->base.audio_fmt.channels_count;

ret = copier_set_gain(dev, cd->dd[0]->gain_data, gain_data, channels);
if (ret)
comp_err(dev, "Gain DMA control: failed to set gain");
return ret;
Expand All @@ -158,12 +164,9 @@ int copier_gain_dma_control(union ipc4_connector_node_id node, const char *confi
return -ENODEV;
}

int copier_set_gain(struct comp_dev *dev, struct dai_data *dd,
struct gain_dma_control_data *gain_data)
int copier_set_gain(struct comp_dev *dev, struct copier_gain_params *gain_params,
struct gain_dma_control_data *gain_data, int channels)
{
struct copier_gain_params *gain_params = dd->gain_data;
struct ipc4_copier_module_cfg *copier_cfg = dd->dai_spec_config;
const int channels = copier_cfg->base.audio_fmt.channels_count;
uint16_t static_gain[MAX_GAIN_COEFFS_CNT];
int ret;

Expand Down
11 changes: 7 additions & 4 deletions src/audio/copier/copier_gain.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,11 @@ struct gain_dma_control_data {
* @param dev The pointer to the component device structure.
* @param gain_params The pointer to gain params structure.
* @param fade_period The fade period in milliseconds.
* @param dai_type DAI type
* @return 0 on success, negative error code on failure.
*/
int copier_gain_set_params(struct comp_dev *dev, struct copier_gain_params *gain_params, uint32_t fade_period);
int copier_gain_set_params(struct comp_dev *dev, struct copier_gain_params *gain_params, uint32_t fade_period,
enum sof_ipc_dai_type dai_type);

/**
* @brief Sets the basic gain parameters.
Expand Down Expand Up @@ -210,12 +212,13 @@ enum copier_gain_state copier_gain_eval_state(struct copier_gain_params *gain_pa
* Sets/modify gain for a copier module in runtime.
*
* @param dev The copier device structure.
* @param dd The DAI data structure.
* @param gain_params The pointer to the copier_gain_params structure.
* @param gain_data The gain control data structure.
* @param channels Number of audio channels.
* @return 0 on success, otherwise a negative error code.
*/
int copier_set_gain(struct comp_dev *dev, struct dai_data *dd,
struct gain_dma_control_data *gain_data);
int copier_set_gain(struct comp_dev *dev, struct copier_gain_params *gain_params,
struct gain_dma_control_data *gain_data, int channels);

/**
* Checks for unity gain mode.
Expand Down
4 changes: 4 additions & 0 deletions src/audio/copier/copier_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,10 @@ void copier_host_dma_cb(struct comp_dev *dev, size_t bytes)

buffer_stream_writeback(cd->hd->local_buffer, bytes);
}
#if CONFIG_MICROPHONE_PRIVACY
if (cd->mic_priv)
mic_privacy_process(dev, cd->mic_priv, cd->hd->local_buffer, bytes);
#endif
}

static void copier_notifier_cb(void *arg, enum notify_id type, void *data)
Expand Down
Loading

0 comments on commit f266ba7

Please sign in to comment.