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 21, 2025
1 parent 40415a3 commit 07dd799
Show file tree
Hide file tree
Showing 17 changed files with 481 additions and 11 deletions.
4 changes: 3 additions & 1 deletion posix/include/sof/lib/dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#endif

struct comp_buffer;
struct comp_dev;

/** \addtogroup sof_dma_drivers DMA Drivers
* DMA Drivers API specification.
Expand Down Expand Up @@ -550,7 +551,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_INTEL_ADSP_MIC_PRIVACY)
add_subdirectory(mic_privacy_manager)
endif()
subdirs(pipeline)
add_subdirectory(google)
if(CONFIG_COMP_CHAIN_DMA)
Expand Down
16 changes: 16 additions & 0 deletions src/audio/base_fw_intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
#include <rimage/sof/user/manifest.h>
#include "copier/copier_gain.h"

#if CONFIG_INTEL_ADSP_MIC_PRIVACY
#include <sof/audio/mic_privacy_manager.h>
#endif

struct ipc4_modules_info {
uint32_t modules_count;
struct sof_man_module modules[0];
Expand Down Expand Up @@ -100,6 +104,18 @@ int basefw_vendor_hw_config(uint32_t *data_offset, char *data)
tlv_value_uint32_set(tuple, IPC4_I2S_CAPS_HW_CFG, I2S_VER_30_PTL);
#endif

#if CONFIG_INTEL_ADSP_MIC_PRIVACY
struct privacy_capabilities priv_caps;

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_INTEL_MIC_PRIVACY_CAPS_HW_CFG, sizeof(priv_caps), &priv_caps);
#endif

tuple = tlv_next(tuple);
*data_offset = (int)((char *)tuple - data);

Expand Down
99 changes: 99 additions & 0 deletions 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_INTEL_ADSP_MIC_PRIVACY
#include <zephyr/drivers/mic_privacy/intel/mic_privacy.h>
#endif

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

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

#if CONFIG_INTEL_ADSP_MIC_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;

if (cd->gtw_type == ipc4_gtw_dmic)
mic_privacy_enable_dmic_irq(true);

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

uint32_t zeroing_wait_time = (mic_privacy_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;
}

static void mic_privacy_free(struct copier_data *cd)
{
if (cd->gtw_type == ipc4_gtw_dmic)
mic_privacy_enable_dmic_irq(false);

notifier_unregister(cd->mic_priv, NULL, NOTIFIER_ID_MIC_PRIVACY_STATE_CHANGE);

rfree(cd->mic_priv);
}
#endif

static int copier_init(struct processing_module *mod)
{
union ipc4_connector_node_id node_id;
Expand Down Expand Up @@ -131,6 +207,16 @@ static int copier_init(struct processing_module *mod)
comp_err(dev, "unable to create host");
goto error;
}
#if CONFIG_INTEL_ADSP_MIC_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 +230,15 @@ static int copier_init(struct processing_module *mod)
comp_err(dev, "unable to create dai");
goto error;
}
#if CONFIG_INTEL_ADSP_MIC_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 @@ -184,6 +279,10 @@ static int copier_free(struct processing_module *mod)
struct copier_data *cd = module_get_private_data(mod);
struct comp_dev *dev = mod->dev;

#if CONFIG_INTEL_ADSP_MIC_PRIVACY
mic_privacy_free(cd);
#endif

switch (dev->ipc_config.type) {
case SOF_COMP_HOST:
if (!cd->ipc_gtw)
Expand Down
7 changes: 7 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_INTEL_ADSP_MIC_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_INTEL_ADSP_MIC_PRIVACY
struct mic_privacy_data *mic_priv;
#endif
};

int apply_attenuation(struct comp_dev *dev, struct copier_data *cd,
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_INTEL_ADSP_MIC_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
7 changes: 4 additions & 3 deletions src/audio/dai-zephyr.c
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes,

if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE &&
audio_buffer_hw_params_configured(&sink->audio_buffer)) {
ret = stream_copy_from_no_consume(dd->local_buffer, sink,
ret = stream_copy_from_no_consume(dev, dd->local_buffer, sink,
converter[j], bytes, dd->chmap);
}
}
Expand All @@ -322,7 +322,8 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes,
* The PCM converter functions used during DMA buffer copy can never fail,
* so no need to check the return value of stream_copy_from_no_consume().
*/
ret = stream_copy_from_no_consume(dd->dma_buffer, dd->local_buffer,

ret = stream_copy_from_no_consume(dev, dd->dma_buffer, dd->local_buffer,
dd->process, bytes, dd->chmap);
#if CONFIG_IPC_MAJOR_4
/* Apply gain to the local buffer */
Expand Down Expand Up @@ -369,7 +370,7 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes,

if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE &&
audio_buffer_hw_params_configured(&sink->audio_buffer))
ret = stream_copy_from_no_consume(dd->dma_buffer,
ret = stream_copy_from_no_consume(dev, dd->dma_buffer,
sink, converter[j],
bytes, dd->chmap);
}
Expand Down
3 changes: 3 additions & 0 deletions src/audio/mic_privacy_manager/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: BSD-3-Clause

add_local_sources(sof mic_privacy_manager_intel.c)
Loading

0 comments on commit 07dd799

Please sign in to comment.