From b3ce029bd56f0333e27f478fd8b3916061400ddc Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 23 Oct 2024 10:59:42 -0700 Subject: [PATCH 1/3] tools: plugin: pcm: Use hw_params when config is not provided In preparation for simplifying the command line for the plugin, add an option to use the hw_params when the config name is not specified in the command line to configure the endpoint. Signed-off-by: Ranjani Sridharan --- tools/plugin/alsaplug/pcm.c | 41 ++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/tools/plugin/alsaplug/pcm.c b/tools/plugin/alsaplug/pcm.c index f8be6b348d95..4a352f839998 100644 --- a/tools/plugin/alsaplug/pcm.c +++ b/tools/plugin/alsaplug/pcm.c @@ -449,7 +449,7 @@ static int plug_pcm_prepare(snd_pcm_ioplug_t *io) return err; } -static int plug_init_shm_ctx(snd_sof_plug_t *plug); +static int plug_init_shm_ctx(snd_sof_plug_t *plug, snd_pcm_hw_params_t *params); static int plug_pcm_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params) { @@ -565,7 +565,7 @@ static int plug_pcm_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params) } /* set up the endpoint configs */ - err = plug_init_shm_ctx(plug); + err = plug_init_shm_ctx(plug, params); if (err < 0) { SNDERR("error: failed to init sof-pipe ep context: %s:%s", pcm->shm_pcm.name, strerror(err)); @@ -838,7 +838,7 @@ static int plug_create(snd_sof_plug_t *plug, snd_pcm_t **pcmp, const char *name, return 0; } -static int plug_init_shm_ctx(snd_sof_plug_t *plug) +static int plug_init_shm_ctx(snd_sof_plug_t *plug, snd_pcm_hw_params_t *params) { struct plug_shm_glb_state *glb = plug->glb_ctx.addr; struct endpoint_hw_config *ep; @@ -871,21 +871,38 @@ static int plug_init_shm_ctx(snd_sof_plug_t *plug) ep->period_frames = pc->period_frames; ep->period_time = pc->period_time; ep->rate = pc->rate; - ep->pipeline = ci->pcm; - strncpy(ep->card_name, ci->card_name, - sizeof(ep->card_name)); - strncpy(ep->dev_name, ci->dev_name, - sizeof(ep->dev_name)); - strncpy(ep->config_name, ci->config_name, - sizeof(ep->config_name)); + strncpy(ep->config_name, ci->config_name, sizeof(ep->config_name)); found = true; break; } + /* use hw_params if no matching config found or config missing in command line */ if (!found) { - SNDERR("error: config %s not found\n", ci->config_name); - return -EINVAL; + unsigned int channels, rate, dir, buffer_time, period_time; + snd_pcm_uframes_t buffer_size, period_size; + snd_pcm_format_t format; + + snd_pcm_hw_params_get_channels(params, &channels); + snd_pcm_hw_params_get_rate(params, &rate, &dir); + snd_pcm_hw_params_get_buffer_size(params, &buffer_size); + snd_pcm_hw_params_get_period_size(params, &period_size, &dir); + snd_pcm_hw_params_get_buffer_time(params, &buffer_time, &dir); + snd_pcm_hw_params_get_period_time(params, &period_time, &dir); + snd_pcm_hw_params_get_format(params, &format); + + ep = &glb->ep_config[glb->num_ep_configs++]; + ep->buffer_frames = buffer_size; + ep->buffer_time = buffer_time; + ep->channels = channels; + ep->format = format; + ep->period_frames = period_size; + ep->period_time = period_time; + ep->rate = rate; } + + ep->pipeline = ci->pcm; + strncpy(ep->card_name, ci->card_name, sizeof(ep->card_name)); + strncpy(ep->dev_name, ci->dev_name, sizeof(ep->dev_name)); } return 0; From 06121d05b1b7effe4e587f6db95c4fb0a3df6d81 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 23 Oct 2024 11:04:13 -0700 Subject: [PATCH 2/3] tools: plugin: tplg: Use hw_params to pick widget audio format When choosing the audio format during prepare, use the hw_params for matching against the available topology formats. This is in preparation to simplify the command line for the plugin to drop the config name. Signed-off-by: Ranjani Sridharan --- tools/plugin/alsaplug/pcm.c | 2 +- tools/plugin/alsaplug/plugin.h | 2 +- tools/plugin/alsaplug/tplg.c | 75 +++++++++++++++------------------- 3 files changed, 36 insertions(+), 43 deletions(-) diff --git a/tools/plugin/alsaplug/pcm.c b/tools/plugin/alsaplug/pcm.c index 4a352f839998..5ed7d832eaa8 100644 --- a/tools/plugin/alsaplug/pcm.c +++ b/tools/plugin/alsaplug/pcm.c @@ -467,7 +467,7 @@ static int plug_pcm_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params) pcm->frame_us = ceil(1000000.0 / io->rate); /* now send IPCs to set up widgets */ - err = plug_set_up_pipelines(plug, pcm->capture); + err = plug_set_up_pipelines(plug, pcm->capture, params); if (err < 0) { fprintf(stderr, "error setting up pipelines\n"); return err; diff --git a/tools/plugin/alsaplug/plugin.h b/tools/plugin/alsaplug/plugin.h index 37d93cc82701..dcc6f550ff53 100644 --- a/tools/plugin/alsaplug/plugin.h +++ b/tools/plugin/alsaplug/plugin.h @@ -61,7 +61,7 @@ int sofplug_load_hook(snd_config_t *root, snd_config_t *config, int plug_parse_conf(snd_sof_plug_t *plug, const char *name, snd_config_t *root, snd_config_t *conf, bool just_tplg); int plug_parse_topology(snd_sof_plug_t *plug); -int plug_set_up_pipelines(snd_sof_plug_t *plug, int dir); +int plug_set_up_pipelines(snd_sof_plug_t *plug, int dir, snd_pcm_hw_params_t *params); int plug_free_pipelines(snd_sof_plug_t *plug, struct tplg_pipeline_list *pipeline_list, int dir); void plug_free_topology(snd_sof_plug_t *plug); int plug_kcontrol_cb_new(struct snd_soc_tplg_ctl_hdr *tplg_ctl, void *_comp, void *arg, int index); diff --git a/tools/plugin/alsaplug/tplg.c b/tools/plugin/alsaplug/tplg.c index cbd8ba0cddf1..b3f04f4ee456 100644 --- a/tools/plugin/alsaplug/tplg.c +++ b/tools/plugin/alsaplug/tplg.c @@ -688,23 +688,29 @@ static int plug_is_single_format(struct sof_ipc4_pin_format *fmts, int num_forma } static int plug_match_audio_format(snd_sof_plug_t *plug, struct tplg_comp_info *comp_info, - struct plug_config *config) + snd_pcm_hw_params_t *params) { struct sof_ipc4_available_audio_format *available_fmt = &comp_info->available_fmt; struct ipc4_base_module_cfg *base_cfg = &comp_info->basecfg; struct sof_ipc4_pin_format *fmt; - int config_valid_bits; + snd_pcm_format_t params_format; + unsigned int params_channels, params_rate, dir; + int params_valid_bits; int i; - switch (config->format) { + snd_pcm_hw_params_get_channels(params, ¶ms_channels); + snd_pcm_hw_params_get_rate(params, ¶ms_rate, &dir); + snd_pcm_hw_params_get_format(params, ¶ms_format); + + switch (params_format) { case SND_PCM_FORMAT_S16_LE: - config_valid_bits = 16; + params_valid_bits = 16; break; case SND_PCM_FORMAT_S32_LE: - config_valid_bits = 32; + params_valid_bits = 32; break; case SND_PCM_FORMAT_S24_LE: - config_valid_bits = 24; + params_valid_bits = 24; break; default: break; @@ -725,14 +731,14 @@ static int plug_match_audio_format(snd_sof_plug_t *plug, struct tplg_comp_info * channels = fmt->audio_fmt.fmt_cfg & MASK(7, 0); valid_bits = (fmt->audio_fmt.fmt_cfg & MASK(15, 8)) >> 8; - if (rate == config->rate && channels == config->channels && - valid_bits == config_valid_bits) + if (rate == params_rate && channels == params_channels && + valid_bits == params_valid_bits) break; } if (i == available_fmt->num_input_formats) { SNDERR("Cannot find matching format for rate %d channels %d valid_bits %d for %s\n", - config->rate, config->channels, config_valid_bits, comp_info->name); + params_rate, params_channels, params_valid_bits, comp_info->name); return -EINVAL; } out: @@ -755,29 +761,13 @@ static int plug_match_audio_format(snd_sof_plug_t *plug, struct tplg_comp_info * return 0; } -static int plug_set_up_widget_base_config(snd_sof_plug_t *plug, struct tplg_comp_info *comp_info) +static int plug_set_up_widget_base_config(snd_sof_plug_t *plug, struct tplg_comp_info *comp_info, + snd_pcm_hw_params_t *params) { - struct plug_cmdline_item *cmd_item = &plug->cmdline[0]; - struct plug_config *config; - bool config_found = false; int ret, i; - for (i < 0; i < plug->num_configs; i++) { - config = &plug->config[i]; - - if (!strcmp(config->name, cmd_item->config_name)) { - config_found = true; - break; - } - } - - if (!config_found) { - SNDERR("unsupported config requested %s\n", cmd_item->config_name); - return -ENOTSUP; - } - /* match audio formats and populate base config */ - ret = plug_match_audio_format(plug, comp_info, config); + ret = plug_match_audio_format(plug, comp_info, params); if (ret < 0) return ret; @@ -985,7 +975,8 @@ static int plug_set_up_pipeline(snd_sof_plug_t *plug, struct tplg_pipeline_info } static int plug_prepare_widget(snd_sof_plug_t *plug, struct tplg_pcm_info *pcm_info, - struct tplg_comp_info *comp_info, int dir) + struct tplg_comp_info *comp_info, int dir, + snd_pcm_hw_params_t *params) { struct tplg_pipeline_list *pipeline_list; int ret, i; @@ -996,7 +987,7 @@ static int plug_prepare_widget(snd_sof_plug_t *plug, struct tplg_pcm_info *pcm_i pipeline_list = &pcm_info->playback_pipeline_list; /* populate base config */ - ret = plug_set_up_widget_base_config(plug, comp_info); + ret = plug_set_up_widget_base_config(plug, comp_info, params); if (ret < 0) return ret; @@ -1021,7 +1012,8 @@ static int plug_prepare_widget(snd_sof_plug_t *plug, struct tplg_pcm_info *pcm_i static int plug_prepare_widgets(snd_sof_plug_t *plug, struct tplg_pcm_info *pcm_info, struct tplg_comp_info *starting_comp_info, - struct tplg_comp_info *current_comp_info) + struct tplg_comp_info *current_comp_info, + snd_pcm_hw_params_t *params) { struct list_item *item; int ret; @@ -1036,13 +1028,13 @@ static int plug_prepare_widgets(snd_sof_plug_t *plug, struct tplg_pcm_info *pcm_ /* set up source widget if it is the starting widget */ if (starting_comp_info == current_comp_info) { - ret = plug_prepare_widget(plug, pcm_info, current_comp_info, 0); + ret = plug_prepare_widget(plug, pcm_info, current_comp_info, 0, params); if (ret < 0) return ret; } /* set up the sink widget */ - ret = plug_prepare_widget(plug, pcm_info, route_info->sink, 0); + ret = plug_prepare_widget(plug, pcm_info, route_info->sink, 0, params); if (ret < 0) return ret; @@ -1050,7 +1042,7 @@ static int plug_prepare_widgets(snd_sof_plug_t *plug, struct tplg_pcm_info *pcm_ if (route_info->sink->type != SND_SOC_TPLG_DAPM_DAI_IN || route_info->sink->type != SND_SOC_TPLG_DAPM_DAI_OUT) { ret = plug_prepare_widgets(plug, pcm_info, starting_comp_info, - route_info->sink); + route_info->sink, params); if (ret < 0) return ret; } @@ -1061,7 +1053,8 @@ static int plug_prepare_widgets(snd_sof_plug_t *plug, struct tplg_pcm_info *pcm_ static int plug_prepare_widgets_capture(snd_sof_plug_t *plug, struct tplg_pcm_info *pcm_info, struct tplg_comp_info *starting_comp_info, - struct tplg_comp_info *current_comp_info) + struct tplg_comp_info *current_comp_info, + snd_pcm_hw_params_t *params) { struct list_item *item; int ret; @@ -1076,13 +1069,13 @@ static int plug_prepare_widgets_capture(snd_sof_plug_t *plug, struct tplg_pcm_in /* set up sink widget if it is the starting widget */ if (starting_comp_info == current_comp_info) { - ret = plug_prepare_widget(plug, pcm_info, current_comp_info, 1); + ret = plug_prepare_widget(plug, pcm_info, current_comp_info, 1, params); if (ret < 0) return ret; } /* set up the source widget */ - ret = plug_prepare_widget(plug, pcm_info, route_info->source, 1); + ret = plug_prepare_widget(plug, pcm_info, route_info->source, 1, params); if (ret < 0) return ret; @@ -1090,7 +1083,7 @@ static int plug_prepare_widgets_capture(snd_sof_plug_t *plug, struct tplg_pcm_in if (route_info->source->type != SND_SOC_TPLG_DAPM_DAI_IN && route_info->source->type != SND_SOC_TPLG_DAPM_DAI_OUT) { ret = plug_prepare_widgets_capture(plug, pcm_info, starting_comp_info, - route_info->source); + route_info->source, params); if (ret < 0) return ret; } @@ -1282,7 +1275,7 @@ static int plug_set_up_widgets_capture(snd_sof_plug_t *plug, return 0; } -int plug_set_up_pipelines(snd_sof_plug_t *plug, int dir) +int plug_set_up_pipelines(snd_sof_plug_t *plug, int dir, snd_pcm_hw_params_t *params) { struct tplg_comp_info *host = NULL; struct tplg_pcm_info *pcm_info; @@ -1309,7 +1302,7 @@ int plug_set_up_pipelines(snd_sof_plug_t *plug, int dir) plug->pcm_info = pcm_info; if (dir) { - ret = plug_prepare_widgets_capture(plug, pcm_info, host, host); + ret = plug_prepare_widgets_capture(plug, pcm_info, host, host, params); if (ret < 0) return ret; @@ -1322,7 +1315,7 @@ int plug_set_up_pipelines(snd_sof_plug_t *plug, int dir) return 0; } - ret = plug_prepare_widgets(plug, pcm_info, host, host); + ret = plug_prepare_widgets(plug, pcm_info, host, host, params); if (ret < 0) return ret; From e41910914a77bac33cabf075dc4b5177ba5876ac Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 23 Oct 2024 11:07:47 -0700 Subject: [PATCH 3/3] tools: plugin: Simplify the command line Make the card/dev names and config names optional in the command line. This will simplify the command line to just pass the PCM ID to start playback using the default device as follows: aplay -Dsof:plugin:1 Signed-off-by: Ranjani Sridharan --- tools/plugin/README.md | 13 ++++++++++++ tools/plugin/alsaplug/plugin.c | 37 +++++++++++++++++----------------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/tools/plugin/README.md b/tools/plugin/README.md index 673cbceb08ff..ce0cad4ea4cd 100644 --- a/tools/plugin/README.md +++ b/tools/plugin/README.md @@ -60,6 +60,19 @@ The command line is parsed as follows: - "default": The second default is the device name - "48k2c16b" is the config name for 48K, stereo, 16bit +Config name is optional in the command line. When it is not provided, hw_params will be used to +configure the endpoint. In this case, the command line can be simplified to: + +``` +aplay -Dsof:plugin:1:default:default +``` + +When using the default device, the command line can be further simplified to: + +``` +aplay -Dsof:plugin:1 +``` + This renders audio to the sof-pipe daemon using the sof-plugin topology playback PCM ID 1. The above example needs to be 48k as example pipe has no SRC/ASRC. diff --git a/tools/plugin/alsaplug/plugin.c b/tools/plugin/alsaplug/plugin.c index be5ff0e69f2b..deb767a4133f 100644 --- a/tools/plugin/alsaplug/plugin.c +++ b/tools/plugin/alsaplug/plugin.c @@ -270,28 +270,29 @@ static int parse_client_cmdline(snd_sof_plug_t *plug, char *cmdline, bool just_t cmd_item = &plug->cmdline[plug->num_cmdline]; card = strtok_r(next, ":", &next); + /* card/dev names and config are all optional */ if (!card) { - SNDERR("Invalid card name\n"); - return -EINVAL; - } - dev = strtok_r(next, ":", &next); - if (!dev) { - SNDERR("Invalid dev name\n"); - return -EINVAL; - } - config = strtok_r(next, ":", &next); - - /* tuple needs all three, any missing ? */ - if (!config) { - SNDERR("invalid cmdline, expected pcm(%s):card(%s):dev(%s):config(%s) from %s", - pcm, card, dev, config, tplg); - return -EINVAL; + strncpy(cmd_item->card_name, "default", sizeof(cmd_item->card_name)); + strncpy(cmd_item->dev_name, "default", sizeof(cmd_item->dev_name)); + fprintf(stdout, "no config name provided, will use hw_params\n"); + } else { + strncpy(cmd_item->card_name, card, sizeof(cmd_item->card_name)); + dev = strtok_r(next, ":", &next); + /* dev name must be provided along with card name */ + if (!dev) { + SNDERR("Invalid dev name\n"); + return -EINVAL; + } + strncpy(cmd_item->dev_name, dev, sizeof(cmd_item->dev_name)); + config = strtok_r(next, ":", &next); + /* config name is optional */ + if (!config) + fprintf(stdout, "no config name provided, will use hw_params\n"); + else + strncpy(cmd_item->config_name, config, sizeof(cmd_item->config_name)); } cmd_item->pcm = atoi(pcm); - strncpy(cmd_item->card_name, card, sizeof(cmd_item->card_name)); - strncpy(cmd_item->dev_name, dev, sizeof(cmd_item->dev_name)); - strncpy(cmd_item->config_name, config, sizeof(cmd_item->config_name)); /* * dev name is special, we cant use "," in the command line