diff --git a/test-case/volume-basic-test.sh b/test-case/volume-basic-test.sh index 79e29043..1f013b2c 100755 --- a/test-case/volume-basic-test.sh +++ b/test-case/volume-basic-test.sh @@ -16,7 +16,9 @@ # source from the relative path of current folder # shellcheck source=case-lib/lib.sh -source "$(dirname "${BASH_SOURCE[0]}")"/../case-lib/lib.sh +TOPDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")"/.. && pwd) +source "$TOPDIR/case-lib/lib.sh" + volume_array=("0%" "10%" "20%" "30%" "40%" "50%" "60%" "70%" "80%" "90%" "100%") OPT_NAME['t']='tplg' OPT_DESC['t']="tplg file, default value is env TPLG: $TPLG" @@ -62,7 +64,10 @@ sleep 1 [[ ! $(pidof aplay) ]] && die "aplay process is terminated too early" sofcard=${SOFCARD:-0} -readarray -t pgalist < <(amixer -c"$sofcard" controls | awk -Fname= 'toupper($2) ~ /PGA/ { print $2 }') + +# https://mywiki.wooledge.org/BashFAQ/024 why cant I pipe data to read? +readarray -t pgalist < <("$TOPDIR"/tools/topo_vol_kcontrols.py "$tplg") + # This (1) provides some logging (2) avoids skip_test if amixer fails amixer -c"$sofcard" controls dlogi "pgalist number = ${#pgalist[@]}" diff --git a/tools/topo_vol_kcontrols.py b/tools/topo_vol_kcontrols.py new file mode 100755 index 00000000..1f1c5cc5 --- /dev/null +++ b/tools/topo_vol_kcontrols.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 + +"""Parses the .tplg file argument and returns a list of volume +kcontrols, one per line. + +Pro tip: try using these commands _interactively_ with ipython3 +""" + +# Keep this script short and simple. If you want to get something else +# from .tplg files, create another script. + +import sys +from tplgtool2 import TplgBinaryFormat, TplgType, DapmType, SofVendorToken + +TPLG_FORMAT = TplgBinaryFormat() + + +def main(): + "Main" + + parsed_tplg = TPLG_FORMAT.parse_file(sys.argv[1]) + + # pylint: disable=invalid-name + DAPMs = [ + item for item in parsed_tplg if item.header.type == TplgType.DAPM_WIDGET.name + ] + + for dapm in DAPMs: + gain_blocks = [b for b in dapm.blocks if b.widget.id == DapmType.PGA.name] + + for gb in gain_blocks: + # debug + # print(f"{gb.widget.id}: {gb.widget.name}") + print_volume_kcontrols(gb) + + +def print_volume_kcontrols(gain_block): + "Print volume kcontrols" + + # Either 1 volume kcontrol, or 1 volume + 1 switch + assert gain_block.widget.num_kcontrols in (1, 2) + + # A switch is either a DapmType.SWITCH, or DapmType.MIXER + # with a max "volume" = 1. Don't include switches here. + volume_kcontrols = [ + kc + for kc in gain_block.kcontrols + if kc.hdr.type == DapmType.MIXER.name and kc.body.max != 1 + ] + + assert len(volume_kcontrols) == 1 + + wname_prefix = ( + f"{gain_block.widget.name} " if has_wname_prefix(gain_block.widget) else "" + ) + + for vkc in volume_kcontrols: + print(wname_prefix + vkc.hdr.name) + + +# This could probably be moved to tplgtool2.py? +def has_wname_prefix(widget): + """Is the kcontrol name prefixed with the widget name? ("PGAxx" or "Dmicxx") + Check SOF_TKN_COMP_NO_WNAME_IN_KCONTROL_NAME""" + + wname_elems = [ + prv.elems + for prv in widget.priv + if prv.elems[0].token + == SofVendorToken.SOF_TKN_COMP_NO_WNAME_IN_KCONTROL_NAME.name + ] + + if len(wname_elems) == 0: # typically: topo v1 + no_wname_prefix = 0 + elif len(wname_elems) == 1: # typically: topo v2 + assert len(wname_elems[0]) == 1 + no_wname_prefix = wname_elems[0][0].value + else: + assert False, f"Unexpected len of wname_elems={wname_elems}" + + assert no_wname_prefix in (0, 1) + + # Double-negation: "no_wname false" => prefix + return not no_wname_prefix + + +if __name__ == "__main__": + main() diff --git a/tools/tplgtool2.py b/tools/tplgtool2.py index b72915b4..698f9e8b 100755 --- a/tools/tplgtool2.py +++ b/tools/tplgtool2.py @@ -198,7 +198,7 @@ class PcmFormatsFlag(enum.IntFlag): class SofVendorToken(enum.IntEnum): r"""SOF vendor tokens - See `tools/topology1/sof/tokens.m4` in SOF. + Duplicates Linux' `include/uapi/sound/sof/tokens.h` """ # sof_buffer_tokens SOF_TKN_BUF_SIZE = 100 @@ -235,6 +235,7 @@ class SofVendorToken(enum.IntEnum): SOF_TKN_COMP_CORE_ID = 404 SOF_TKN_COMP_UUID = 405 SOF_TKN_COMP_CPC = 406 + SOF_TKN_COMP_NO_WNAME_IN_KCONTROL_NAME = 417 # sof_ssp_tokens SOF_TKN_INTEL_SSP_CLKS_CONTROL = 500 SOF_TKN_INTEL_SSP_MCLK_ID = 501 @@ -1330,6 +1331,7 @@ def main(): errors = 0 for f in files: tplg = GroupedTplg(tplgFormat.parse_file(f)) + assert set(dump_types) <= set(supported_dump), f"unsupported type in {dump_types}" if 'pcm' in dump_types: tplg.print_pcm_info() if 'graph' in dump_types: