Skip to content

Conversation

@ranj063
Copy link
Collaborator

@ranj063 ranj063 commented Dec 2, 2025

No description provided.

@singalsu
Copy link

singalsu commented Dec 2, 2025

I tested this PR with other echo ref capture related PRs (thesofproject/sof#10329 and thesofproject/sof#10387), it works perfectly.

@ranj063 ranj063 force-pushed the fix/echo_ref_new branch 2 times, most recently from 44a47e3 to 6c97700 Compare December 2, 2025 19:48
bardliao
bardliao previously approved these changes Dec 3, 2025
Copy link
Member

@lgirdwood lgirdwood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor opens

{
struct device *dev = card->dev;
int ret;
char *name = devm_kasprintf(dev, GFP_KERNEL, "EchoRef_virtual_DAI");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this always be echo ref or can it also be a capture device for recording playback ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is set up as as capture device for recording playback by default f playback is active. If playback is not active, it produces silence

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, so could we make a more generic/meaningful name so that users will know what to do with it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks too fragile to me.
It just happens that we use a tone/signal generator (which generates 0) to feed to an EchoRef capture PCM, but the concept is defined in topology.

Do you have topology PR to see how this looks like?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you go @ujfalusi. This is what an echo ref topology looks like
sof-mtl-rt713-l0-rt1316-l12

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, so could we make a more generic/meaningful name so that users will know what to do with it.

@lgirdwood how about "LoopbackCapture_virtual_DAI"?

goto sink_prepare;

/* skip aggregated DAIs */
if(is_aggregated_dai(swidget))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Copy link
Collaborator

@ujfalusi ujfalusi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ranj063, I don't think I understand all the details and how this changes the whole walking logic, I trust that the logic is solid.

The last patch revealed (to commit message) how the direction comes to be used...

I suppose it could be possible to add a simple tone generator now:
virtual DAI -> tone generator -> Host (tone capture)
but it is not, isn't it? We would need to change the machine driver and other things to match with the topology change?

I'm not sure if there is a more dynamic, topology driven way to achieve the virtual DAI concept, which would give really nice user feature at the end.

{
struct device *dev = card->dev;
int ret;
char *name = devm_kasprintf(dev, GFP_KERNEL, "EchoRef_virtual_DAI");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks too fragile to me.
It just happens that we use a tone/signal generator (which generates 0) to feed to an EchoRef capture PCM, but the concept is defined in topology.

Do you have topology PR to see how this looks like?

ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name,
0, 1, "snd-soc-dummy-dai", "dummy",
snd_soc_dummy_dlc.name, snd_soc_dummy_dlc.dai_name,
1, NULL, NULL);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only sdw can have this feature, HDA or SSP machines never?
We cannot add to topology a tone generator for example at will, but we need to change the kernel as well?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In theory the same logic would work for all machines and yes you would need the machine driver change in order to use it. But in the case of SSP, we dont need this. We can use the Loopback mode like we've always used. So maybe just the HDA machine change would be enough

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HDA and SSP not priority.

out_fmt = &available_fmt->output_pin_fmts[0].audio_fmt;

/* copy output format */
memcpy(&process->base_config.audio_fmt, out_fmt, sizeof(*out_fmt));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what will happen if the fe_parmas and the first output_fmt of the module does not match?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll end up with an error that out format match wasnt found on line 2802 isnt it?

#include "sof-audio.h"
#include "ops.h"

/*
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does one 'start' such a tone generator playback? There is no PCM device involved, so there must be a kcontrol switch which forces the system to motion.
How?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a PCM with the tone generator pipeline. It serves the purpose of propragating the hw_params and triggers to the list of connected DAPM widgets. A kcontrol is a possibility but without a PCM, it wont be easy to know which widgets to set up or even how to the hw_params for the FE DAI and BE DAI and the codec. The PCM is a shortcut in this case to achieve that functionality

{
return (WIDGET_IS_DAI(swidget->id) &&
isdigit(swidget->widget->name[strlen(swidget->widget->name) - 1]) &&
swidget->widget->name[strlen(swidget->widget->name) - 1] != '0');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how did this worked then currently if we should not be dealing with the .[1..9] DAIs?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

today it works because we stop traversing the path when we see a virtual widget. So if you look at the aggregated DAI alh-copier-SDW1.Playback.1 in the topology I shared in another comment, it is preceded by a virtual widget. So we see that and ignore everything below it. But now for tone and echo ref we want to go down the path from either an aggregated DAI or a virtual widget to the sink components in the path.

@ranj063
Copy link
Collaborator Author

ranj063 commented Dec 10, 2025

I suppose it could be possible to add a simple tone generator now:
virtual DAI -> tone generator -> Host (tone capture)
but it is not, isn't it? We would need to change the machine driver and other things to match with the topology change?

@ujfalusi yes this is all you need in topology and it will work. No need to change anything for tone playback.

Align with the firmware and add the missing token for pipeline kcps.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Copy link

@singalsu singalsu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This patch version worked OK with firmware and topology patches to create echo reference capture PCMs.

@ranj063
Copy link
Collaborator Author

ranj063 commented Dec 19, 2025

dropped support for hostless playback for now> will be added later

@singalsu
Copy link

dropped support for hostless playback for now> will be added later

@ujfalusi @ranj063 I just tested this latest PR version, it works well.

bardliao
bardliao previously approved these changes Dec 19, 2025
Copy link
Collaborator

@ujfalusi ujfalusi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ranj063, I have few comments and I still need to rely on your word that the changes in walking are ok (and @singalsu's testing).

Now that the tone_generator -> ... -> playback DAI is removed, this looks much cleaner and better rounded.

if (ret)
return ret;

(*dai_links)++;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how this will work with existing topologies and with function topology?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldnt matter if we use function topologies right? We just have a single machine even in that case right?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the function topology parsing will fall back to monolithic when it faces with a link of unknown origin/no fragment.
We have now patch to make this not fail when there is no monolithic topology defined, but this (I think) will eventually disable the function topologies?

I'm not sure, but this is my feeling.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

best to comment what the assumption will be here regarding topology.

/* allocate BE dailinks */
num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num;
/* allocate BE dailinks, add an extra DAI link for echo reference capture */
num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num + 1;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is also a chicken and egg problem... This is purely topology construct, but we don't know if the topology have virtual DAI before we pick and parse the topology and for that we need the links in place if the topology do have this defined, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, lets capture this behavior in the comments.

struct sof_ipc4_msg msg;
bool skip_during_fe_trigger;
bool direction_valid;
u32 direction;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should it be documented what values are valid for direction, like what 0 means, what 1 means, is there a direction == 2...10?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ujfalusi these come directly from topology, so are checked for validity there.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so, the value for kernel does not matter, only they should match?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can add that context to the comment. Can complain too if out of range.

SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
out_ref_valid_bits =
SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and to add I have this PR for some time which touches the same code and fixes issue when not all parameters are changed by a process module:
#5442

ujfalusi
ujfalusi previously approved these changes Dec 19, 2025
Copy link
Member

@lgirdwood lgirdwood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, on my side it may benefit from more comments where expectations/behaviours are unclear.

ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name,
0, 1, "snd-soc-dummy-dai", "dummy",
snd_soc_dummy_dlc.name, snd_soc_dummy_dlc.dai_name,
1, NULL, NULL);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HDA and SSP not priority.

if (ret)
return ret;

(*dai_links)++;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

best to comment what the assumption will be here regarding topology.

/* allocate BE dailinks */
num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num;
/* allocate BE dailinks, add an extra DAI link for echo reference capture */
num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num + 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, lets capture this behavior in the comments.

struct sof_ipc4_msg msg;
bool skip_during_fe_trigger;
bool direction_valid;
u32 direction;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can add that context to the comment. Can complain too if out of range.

Add a DAI link for loopback capture as the last link to make sure
the other DAI link ID's remain unaffected. It serves as a dummy DAI link
to enable echo reference capture in the SDW topologies which do not have
an actual backend capture DAI.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Parse the pipeline direction from topology. The direction_valid token is
required for backward-compatibility with older topologies that may not
have the direction set for pipelines. This will be used when
setting up pipelines to check if a pipeline is in the same direction as
the requested params and skip those in the opposite direction like in
the case of echo reference capture pipelines during playback.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
…ut pins

A tone generator module can be a type of processing module with no input
pins. Adjust the logic to set the reference params for selecting output
format and the basecfg format based on the output format.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Aggregated DAI widgets exist in topology for representation and are not
actually initialized in the firmware. But in preparation for using this
as a virtual DAI for loopback capture, make sure that we can traverse
the path from an aggregated DAI widget to the host widget.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
An example of a DAI-less loopback pipeline would be the echo
reference capture in the speaker playback path. This pipeline
is set up as follows:

Host(Playback) -> mixin -> mixout -> gain -> module-copier -> DAI
						|
						V
		Host(Capture) <-  Process module <- virtual DAI

In the above example, the virtual DAI exploits the concept of an
aggregated DAI (one with a non-zero DAI ID) in topology to enable this
pipeline to work with DPCM. A virtual DAI is a DAI widget with a
non-zero DAI ID and hence is skipped when traversing the list of DAPM
widgets during widget prepare/set/up/free/unprepare. The process module
in the above pipeline generates 0's that are captured by the echo
reference PCM.  When the playback path is active, the process module acts
as a passthrough module to allow the playback samples to be passthrough
to the capture host.

In order for these pipelines to work properly, the logic for
setting/preparing/freeing/unpreparing the widgets needs to be amended to
make sure that only the widgets that are in the pipeline in the same
direction as the PCM being started are set up. For example, when the
playback PCM is started, the capture pipeline widgets also show up in
the list of connected DAPM widgets but they shouldn't be set up yet
because the echo reference capture PCM hasn't been started yet.
Alternatively, when the echo reference capture PCM is started, the
playback pipeline widgets should not be setup.

Finally, the last step needed to put this all together is the set the
routes for widgets connecting the playback and the capture pipelines
when both are active.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
@ranj063
Copy link
Collaborator Author

ranj063 commented Dec 19, 2025

SOFCI TEST

1 similar comment
@ranj063
Copy link
Collaborator Author

ranj063 commented Dec 20, 2025

SOFCI TEST

@bardliao bardliao merged commit f2701ee into thesofproject:topic/sof-dev Dec 22, 2025
11 of 16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants