Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions app/boards/intel_adsp_cavs25.conf
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ CONFIG_COMP_DRC=y
CONFIG_COMP_MFCC=y
CONFIG_COMP_MULTIBAND_DRC=y
CONFIG_COMP_VOLUME_WINDOWS_FADE=y
CONFIG_COMP_WOV_ARBITER=y
CONFIG_COMP_VAD_GATE=y
CONFIG_COMP_KPB=y
CONFIG_SAMPLES=y
CONFIG_SAMPLE_KEYPHRASE=y
CONFIG_FORMAT_CONVERT_HIFI3=n
CONFIG_PCM_CONVERTER_FORMAT_S16LE=y
CONFIG_PCM_CONVERTER_FORMAT_S24LE=y
Expand Down
5 changes: 5 additions & 0 deletions app/debug_overlay.conf
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,8 @@ CONFIG_GDBSTUB_ENTER_IMMEDIATELY=n
# Testing with runtime filtering enabled ensures the same feature set is validated.
# Note: This setting has no effect if CONFIG_LOG_RUNTIME_FILTERING is disabled.
CONFIG_LOG_RUNTIME_DEFAULT_LEVEL=3

# Record fatal exception breadcrumbs (PC/cause/vaddr) in HP-SRAM window0 so the
# crash is visible in the host dmesg "Firmware state" line when no console or
# mtrace output is available.
CONFIG_XTENSA_ADSP_FATAL_BREADCRUMB=y
2 changes: 2 additions & 0 deletions app/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,5 @@ CONFIG_SCHED_CPU_MASK=y
CONFIG_SYS_CLOCK_TICKS_PER_SEC=15000
CONFIG_DAI=y
CONFIG_HEAP_MEM_POOL_SIZE=2048
CONFIG_SAMPLES=y
CONFIG_SAMPLE_KEYPHRASE=y
6 changes: 6 additions & 0 deletions src/audio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,15 @@ if(NOT CONFIG_COMP_MODULE_SHARED_LIBRARY_BUILD)
if(CONFIG_COMP_UP_DOWN_MIXER)
add_subdirectory(up_down_mixer)
endif()
if(CONFIG_COMP_VAD_GATE)
add_subdirectory(vad_gate)
endif()
if(CONFIG_COMP_VOLUME)
add_subdirectory(volume)
endif()
if(CONFIG_COMP_WOV_ARBITER)
add_subdirectory(wov_arbiter)
endif()
if(CONFIG_DTS_CODEC)
add_subdirectory(codec)
endif()
Expand Down
13 changes: 13 additions & 0 deletions src/audio/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,18 @@ config COMP_STUBS
Select to force all 3P blocks to link against stubs rather than their libraries. This
should only be used in testing environments like fuzzers or CI.

config COMP_WOV_ARBITER
bool "WOV arbiter component"
depends on COMP_KPB
depends on IPC_MAJOR_4
select AMS
help
Select to build the WOV (Wake-on-Voice) arbiter. The arbiter sits
between multiple KPB host-drain outputs and a single host PCM copier.
When a keyword is detected by one of the WOV detectors the arbiter
routes that KPB's drain stream to the host and instructs the remaining
detectors to pause.

config COMP_KPB
bool "KPB component"
default y
Expand Down Expand Up @@ -160,6 +172,7 @@ rsource "template/Kconfig"
rsource "tensorflow/Kconfig"
rsource "tone/Kconfig"
rsource "up_down_mixer/Kconfig"
rsource "vad_gate/Kconfig"
rsource "volume/Kconfig"
# --- End Kconfig Sources (alphabetical order) ---

Expand Down
85 changes: 78 additions & 7 deletions src/audio/kpb.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@
#include <sof/audio/component_ext.h>
#include <sof/audio/pipeline.h>
#include <sof/audio/kpb.h>
#define SOF_MODULE_API_PRIVATE
#include <sof/audio/module_adapter/module/generic.h>
#include <module/module/base.h>
#include <sof/audio/ipc-config.h>
#include <sof/common.h>
#include <rtos/panic.h>
#include <sof/ipc/msg.h>
#include <sof/ipc/topology.h>
#include <rtos/timer.h>
#include <rtos/alloc.h>
#include <rtos/clk.h>
Expand Down Expand Up @@ -369,6 +373,9 @@ static int kpb_bind(struct comp_dev *dev, struct bind_info *bind_data)
sink_buf_id = buf_get_id(sink);

if (sink_buf_id == buf_id) {
struct comp_dev *sc = comp_buffer_get_sink_component(sink);
comp_err(dev, "kpb_bind: buf_id=%d sink_comp=0x%x -> %s",
buf_id, sc ? dev_comp_id(sc) : 0, sink_buf_id == 0 ? "sel_sink" : "host_sink");
if (sink_buf_id == 0)
kpb->sel_sink = sink;
else
Expand Down Expand Up @@ -887,6 +894,38 @@ static int kpb_prepare(struct comp_dev *dev)
return -ENOMEM;
}

struct comp_buffer *sink;
comp_dev_for_each_consumer(dev, sink) {
struct comp_dev *sc = comp_buffer_get_sink_component(sink);
if (sc) {
comp_err(dev, "kpb consumer in bsink_list: comp_id=0x%x type=%d sink_buf=%p",
dev_comp_id(sc), sc->drv ? sc->drv->type : -1, sink);
if (dev_comp_id(sc) != 0x10)
kpb->sel_sink = sink;
else
kpb->host_sink = sink;
}
}
comp_err(dev, "kpb_params result: sel_sink=%p host_sink=%p",
kpb->sel_sink, kpb->host_sink);

if (kpb->sel_sink) {
struct comp_dev *sink_comp = comp_buffer_get_sink_component(kpb->sel_sink);
if (sink_comp && sink_comp->state == COMP_STATE_INIT) {
struct sof_ipc_stream_params sink_params;
memset_s(&sink_params, sizeof(sink_params), 0, sizeof(sink_params));
sink_params.channels = kpb->config.channels ? kpb->config.channels : 2;
sink_params.rate = kpb->config.sampling_freq ? kpb->config.sampling_freq : 16000;
sink_params.sample_container_bytes = 4;
sink_params.sample_valid_bytes = 4;
sink_params.frame_fmt = SOF_IPC_FRAME_S32_LE;
comp_params(sink_comp, &sink_params);
comp_prepare(sink_comp);
}
}

kpb_change_state(kpb, KPB_STATE_RUN);

#ifndef CONFIG_IPC_MAJOR_4
/* Search for KPB related sinks.
* NOTE! We assume here that channel selector component device
Expand Down Expand Up @@ -936,10 +975,36 @@ static int kpb_prepare(struct comp_dev *dev)
}
#endif /* CONFIG_IPC_MAJOR_4 */

if (!kpb->sel_sink || !kpb->host_sink) {
struct comp_buffer *sink;

comp_dev_for_each_consumer(dev, sink) {
if (!kpb->sel_sink)
kpb->sel_sink = sink;
else if (!kpb->host_sink)
kpb->host_sink = sink;
}
}

if (!kpb->sel_sink) {
comp_err(dev, "could not find sink: sel_sink %p",
kpb->sel_sink);
ret = -EIO;
} else {
struct comp_dev *sink_comp = comp_buffer_get_sink_component(kpb->sel_sink);
if (sink_comp && sink_comp->state == COMP_STATE_INIT) {
struct sof_ipc_stream_params sink_params;
memset_s(&sink_params, sizeof(sink_params), 0, sizeof(sink_params));
sink_params.channels = kpb->config.channels ? kpb->config.channels : 2;
sink_params.rate = kpb->config.sampling_freq ? kpb->config.sampling_freq : 16000;
sink_params.sample_container_bytes = 4;
sink_params.sample_valid_bytes = 4;
sink_params.frame_fmt = SOF_IPC_FRAME_S32_LE;
comp_params(sink_comp, &sink_params);
comp_prepare(sink_comp);
comp_info(dev, "kpb_prepare: prepared downstream sink_comp %d in state %d",
dev_comp_id(sink_comp), sink_comp->state);
}
}

kpb->sync_draining_mode = true;
Expand Down Expand Up @@ -1234,19 +1299,16 @@ static int kpb_copy(struct comp_dev *dev)
sink = kpb->sel_sink;
ret = PPL_STATUS_PATH_STOP;

comp_err(dev, "kpb_copy: source_buf=%p sel_sink=%p avail=%u",
source, sink, audio_stream_get_avail_bytes(&source->stream));

if (!sink) {
comp_err(dev, "no sink.");
ret = -EINVAL;
break;
}

/* Discard data if sink is not active */
if (comp_buffer_get_sink_component(sink)->state != COMP_STATE_ACTIVE) {
copy_bytes = audio_stream_get_avail_bytes(&source->stream);
comp_update_buffer_consume(source, copy_bytes);
comp_dbg(dev, "KD not active, dropping %zu bytes...", copy_bytes);
break;
}
/* Allow downstream WOV detector copy regardless of state */

/* Validate sink */
if (!audio_stream_get_wptr(&sink->stream)) {
Expand Down Expand Up @@ -1313,6 +1375,15 @@ static int kpb_copy(struct comp_dev *dev)
else
comp_update_buffer_produce(sink, produced_bytes);

struct comp_dev *wov_comp = sink ? comp_buffer_get_sink_component(sink) : NULL;
if (wov_comp) {
comp_err(dev, "kpb_copy: produced=%u bytes, triggering wov=0x%x",
copy_bytes, dev_comp_id(wov_comp));
comp_copy(wov_comp);
} else {
comp_err(dev, "kpb_copy: downstream sink_comp returned NULL!");
}

comp_update_buffer_consume(source, copy_bytes);

break;
Expand Down
2 changes: 1 addition & 1 deletion src/audio/kpb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "KPB"
uuid = UUIDREG_STR_KPB4
affinity_mask = "0x1"
instance_count = "1"
instance_count = "4"
domain_types = "0"
load_type = "0"
module_type = "0xB"
Expand Down
34 changes: 24 additions & 10 deletions src/audio/mixin_mixout/mixin_mixout.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <sof/audio/buffer.h>
#include <sof/audio/component.h>
#include <sof/audio/component_ext.h>
#include <sof/audio/format.h>
#include <sof/audio/module_adapter/module/generic.h>
#include <sof/audio/pipeline.h>
Expand Down Expand Up @@ -309,7 +310,9 @@ static int mixin_process(struct processing_module *mod,
int i, ret;
struct cir_buf_ptr source_ptr;

comp_dbg(dev, "entry");
source_avail_frames = source_get_data_frames_available(sources[0]);
comp_err(dev, "mixin_process entry: num_sinks=%d sources=%d avail=%u",
num_of_sinks, num_of_sources, source_avail_frames);

source_avail_frames = source_get_data_frames_available(sources[0]);
sinks_free_frames = INT32_MAX;
Expand Down Expand Up @@ -342,14 +345,8 @@ static int mixin_process(struct processing_module *mod,
unused_in_between_buf = comp_buffer_get_from_sink(sinks[i]);
mixout = comp_buffer_get_sink_component(unused_in_between_buf);

/* Skip non-active mixout like it is not connected so it does not
* block other possibly connected mixouts. In addition, non-active
* mixouts might have their sink buffer/interface not yet configured.
*/
if (mixout->state != COMP_STATE_ACTIVE) {
active_mixouts[i] = NULL;
continue;
}
if (mixout->state != COMP_STATE_ACTIVE)
mixout->state = COMP_STATE_ACTIVE;

mixout_mod = comp_mod(mixout);
active_mixouts[i] = mixout_mod;
Expand Down Expand Up @@ -394,8 +391,10 @@ static int mixin_process(struct processing_module *mod,
sinks_free_frames = MIN(sinks_free_frames, free_frames - pending_frames->frames);
}

if (sinks_free_frames == 0 || sinks_free_frames == INT32_MAX)
if (sinks_free_frames == 0 || sinks_free_frames == INT32_MAX) {
comp_err(dev, "mixin_process early return 0: sinks_free=%u", sinks_free_frames);
return 0;
}

#if CONFIG_XRUN_NOTIFICATIONS_ENABLE
frame_bytes = source_get_frame_bytes(sources[0]);
Expand Down Expand Up @@ -502,6 +501,9 @@ static int mixin_process(struct processing_module *mod,

if (frames_to_copy + start_frame > mixout_data->mixed_frames)
mixout_data->mixed_frames = frames_to_copy + start_frame;

if (mixout_mod && mixout_mod->dev)
comp_copy(mixout_mod->dev);
}

if (bytes_to_consume)
Expand Down Expand Up @@ -596,6 +598,18 @@ static int mixout_process(struct processing_module *mod,
sink_commit_buffer(sinks[0], bytes_to_produce);
md->acquired_buf.ptr = NULL;

if (bytes_to_produce > 0) {
struct comp_buffer *sink_buf = comp_buffer_get_from_sink(sinks[0]);
if (sink_buf && comp_buffer_get_sink_component(sink_buf)) {
struct comp_dev *sink_comp = comp_buffer_get_sink_component(sink_buf);
comp_err(dev, "mixout_process: sink_buf=0x%x produced=%u bytes, triggering kpb=0x%x",
sink_buf, bytes_to_produce, dev_comp_id(sink_comp));
comp_copy(sink_comp);
} else {
comp_err(dev, "mixout_process: produced=%u bytes, BUT sink_buf/comp NULL", bytes_to_produce);
}
}

return 0;
}

Expand Down
2 changes: 2 additions & 0 deletions src/audio/vad_gate/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# SPDX-License-Identifier: BSD-3-Clause
add_local_sources(sof vad_gate.c)
12 changes: 12 additions & 0 deletions src/audio/vad_gate/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# SPDX-License-Identifier: BSD-3-Clause

config COMP_VAD_GATE
bool "VAD gate component"
depends on IPC_MAJOR_4
help
Select to build the VAD (Voice Activity Detection) gate component.
The gate sits between the DMIC copier and the downstream Mixin in
a WOV capture pipeline. During silence it drains the DMIC input
and returns PPL_STATUS_PATH_STOP so KPB and WOV detectors idle.
When voice onset is detected audio flows through and the downstream
chain wakes and begins buffering.
Loading
Loading