From f8e89cfae03f0e5a65a1760ea05d64e2ab5af692 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Tue, 15 Oct 2019 16:03:11 +0300 Subject: [PATCH 1/3] SRC: Fix sink and source PCM formats handling in prepare() This patch avoids wrong configuration for PCM format and audio corruption in capture pipelines usage if the pipeline requires format conversion. Signed-off-by: Seppo Ingalsuo --- src/audio/src/src.c | 60 ++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/src/audio/src/src.c b/src/audio/src/src.c index 6efad8fcdf47..a5cf8d7d4021 100644 --- a/src/audio/src/src.c +++ b/src/audio/src/src.c @@ -803,31 +803,6 @@ static int src_prepare(struct comp_dev *dev) if (ret == COMP_STATUS_STATE_ALREADY_SET) return PPL_STATUS_PATH_STOP; - /* SRC supports S16_LE, S24_4LE and S32_LE formats */ - switch (dev->params.frame_fmt) { - case SOF_IPC_FRAME_S16_LE: - cd->data_shift = 0; - cd->polyphase_func = src_polyphase_stage_cir_s16; - /* Copy function is set by default in params() for 32 bit - * data. Change it to 16 bit version here if source and sink - * rates are equal. - */ - if (cd->source_rate == cd->sink_rate) - cd->src_func = src_copy_s16; - break; - case SOF_IPC_FRAME_S24_4LE: - cd->data_shift = 8; - cd->polyphase_func = src_polyphase_stage_cir; - break; - case SOF_IPC_FRAME_S32_LE: - cd->data_shift = 0; - cd->polyphase_func = src_polyphase_stage_cir; - break; - default: - trace_src_error("src_prepare() error: invalid dev->frame_fmt"); - return -EINVAL; - } - /* SRC component will only ever have 1 source and 1 sink buffer */ sourceb = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); @@ -871,6 +846,41 @@ static int src_prepare(struct comp_dev *dev) goto err; } + /* SRC supports S16_LE, S24_4LE and S32_LE formats */ + if (cd->source_format != cd->sink_format) { + trace_src_error("src_prepare() error: " + "Source fmt %d and sink fmt %d are different.", + cd->source_format, cd->sink_format); + ret = -EINVAL; + goto err; + } + + switch (cd->source_format) { + case SOF_IPC_FRAME_S16_LE: + cd->data_shift = 0; + cd->polyphase_func = src_polyphase_stage_cir_s16; + /* Copy function is set by default in params() for 32 bit + * data. Change it to 16 bit version here if source and sink + * rates are equal. + */ + if (cd->source_rate == cd->sink_rate) + cd->src_func = src_copy_s16; + break; + case SOF_IPC_FRAME_S24_4LE: + cd->data_shift = 8; + cd->polyphase_func = src_polyphase_stage_cir; + break; + case SOF_IPC_FRAME_S32_LE: + cd->data_shift = 0; + cd->polyphase_func = src_polyphase_stage_cir; + break; + default: + trace_src_error("src_prepare() error: invalid format %d", + cd->source_format); + ret = -EINVAL; + goto err; + } + return 0; err: From fba66a24a340e7532e127d17c437ac8c9d7a16aa Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Tue, 15 Oct 2019 16:07:05 +0300 Subject: [PATCH 2/3] SRC: Report properly the non-supported rates combination error The earlier error message was hard to understand and could be mistaken as internal fail. A redundant trace message about block sizes is removed because the block sizes are set in each copy() in current SRC version. Signed-off-by: Seppo Ingalsuo --- src/audio/src/src.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/audio/src/src.c b/src/audio/src/src.c index a5cf8d7d4021..741106e5923e 100644 --- a/src/audio/src/src.c +++ b/src/audio/src/src.c @@ -128,8 +128,8 @@ int src_buffer_lengths(struct src_param *a, int fs_in, int fs_out, int nch, /* Check from stage1 parameter for a deleted in/out rate combination.*/ if (stage1->filter_length < 1) { trace_src_error("src_buffer_lengths() error: " - "stage1->filter_length <" - " 1, fs_in: %u, fs_out: %u", fs_in, fs_out); + "Non-supported combination " + "fs_in = %d, fs_out = %d", fs_in, fs_out); return -EINVAL; } @@ -603,9 +603,6 @@ static int src_params(struct comp_dev *dev) return err; } - trace_src("src_params(), blk_in = %u, blk_out = %u", - cd->param.blk_in, cd->param.blk_out); - delay_lines_size = sizeof(int32_t) * cd->param.total; if (delay_lines_size == 0) { trace_src_error("src_params() error: delay_lines_size = 0"); From 65fb06edd18e38cefac6b7db3393d63879836f73 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Tue, 15 Oct 2019 16:11:07 +0300 Subject: [PATCH 3/3] Topology: Add topology to test capture SRC This patch adds topology sof-apl-src-dmic.m4 to test capture SRC. The topology instantiates SRCs for 48 -> 8-48 kHz and 16 -> 8-48 kHz capture. The volume component in pipeline handles PCM format conversion from the fixed S32_LE DMIC DAI format. Also the bugs in the earlier non-used pipeline macro are fixed. The macro pipe-src-capture.m4 is renamed to pipe-src-volume-capture.m4 since it contains a volume component. A new macro pipe-src-capture.m4 is created to provide pipeline building block without volume. Signed-off-by: Seppo Ingalsuo --- tools/topology/CMakeLists.txt | 1 + tools/topology/sof-apl-src-dmic.m4 | 104 ++++++++++++++++ tools/topology/sof/pipe-src-capture.m4 | 50 +++++--- tools/topology/sof/pipe-src-volume-capture.m4 | 114 ++++++++++++++++++ 4 files changed, 252 insertions(+), 17 deletions(-) create mode 100644 tools/topology/sof-apl-src-dmic.m4 create mode 100644 tools/topology/sof/pipe-src-volume-capture.m4 diff --git a/tools/topology/CMakeLists.txt b/tools/topology/CMakeLists.txt index bb8dbe95667f..6f4ea54e1015 100644 --- a/tools/topology/CMakeLists.txt +++ b/tools/topology/CMakeLists.txt @@ -52,6 +52,7 @@ set(TPLGS "sof-icl-nocodec\;sof-icl-nocodec" "sof-apl-eq-pcm512x\;sof-apl-eq-pcm512x" "sof-apl-eq-dmic\;sof-apl-eq-dmic" + "sof-apl-src-dmic\;sof-apl-src-dmic" "sof-apl-dmic-a2ch\;sof-apl-dmic-a2ch" "sof-apl-dmic-b2ch\;sof-apl-dmic-b2ch" "sof-apl-dmic-a2ch-b2ch\;sof-apl-dmic-a2ch-b2ch" diff --git a/tools/topology/sof-apl-src-dmic.m4 b/tools/topology/sof-apl-src-dmic.m4 new file mode 100644 index 000000000000..de6cd1c7552b --- /dev/null +++ b/tools/topology/sof-apl-src-dmic.m4 @@ -0,0 +1,104 @@ +# +# Topology for Apollo Lake with direct attach digital microphones array +# + +# Capture configuration +# DAI0 2ch 32b mic1-2 +# DAI1 2ch 32b mic1-2 + +# Include topology builder +include(`utils.m4') +include(`dai.m4') +include(`pipeline.m4') + +# Include TLV library +include(`common/tlv.m4') + +# Include Token library +include(`sof/tokens.m4') + +# Include Apollolake DSP configuration +include(`platform/intel/bxt.m4') +include(`platform/intel/dmic.m4') + +DEBUG_START + +# +# Define the pipelines +# +# PCM6 <--- Volume <--- SRC <--- DMIC6 (DMIC01) +# PCM7 <--- Volume <--- SRC <--- DMIC7 (DMIC16k) +# + +dnl PIPELINE_PCM_DAI_ADD(pipeline, +dnl pipe id, pcm, max channels, format, +dnl period, priority, core, +dnl dai type, dai_index, dai format, +dnl dai periods, pcm_min_rate, pcm_max_rate, +dnl pipeline_rate, time_domain) + +# SRC capture pipeline 6 on PCM 6 using max channels 2. +# Set 1000us deadline on core 0 with priority 0 +PIPELINE_PCM_DAI_ADD(sof/pipe-src-volume-capture.m4, + 6, 6, 2, s32le, + 1000, 0, 0, DMIC, 0, s32le, 3, + 8000, 48000, 48000) + +# SRC capture pipeline 7 on PCM 7 using max channels 2. +# Set 1000us deadline on core 0 with priority 0 +PIPELINE_PCM_DAI_ADD(sof/pipe-src-volume-capture.m4, + 7, 7, 2, s32le, + 1000, 0, 0, DMIC, 1, s32le, 3, + 8000, 48000, 16000) + +# +# DAIs configuration +# + +dnl DAI_ADD(pipeline, +dnl pipe id, dai type, dai_index, dai_be, +dnl buffer, periods, format, +dnl deadline, priority, core, time_domain) + +# capture DAI is DMIC 0 using 3 periods +# Buffers use s32le format, 1000us deadline on core 0 with priority 0 +DAI_ADD(sof/pipe-dai-capture.m4, + 6, DMIC, 0, NoCodec-6, + PIPELINE_SINK_6, 3, s32le, + 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +# capture DAI is DMIC 1 using 3 periods +# Buffers use s32le format, 1000us deadline on core 0 with priority 0 +DAI_ADD(sof/pipe-dai-capture.m4, + 7, DMIC, 1, NoCodec-7, + PIPELINE_SINK_7, 3, s32le, + 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +dnl PCM_DUPLEX_ADD(name, pcm_id, playback, capture) +dnl PCM_CAPTURE_ADD(name, pipeline, capture) +PCM_CAPTURE_ADD(DMIC01, 6, PIPELINE_PCM_6) +PCM_CAPTURE_ADD(DMIC16k, 7, PIPELINE_PCM_7) + +# +# BE configurations - overrides config in ACPI if present +# + +dnl DAI_CONFIG(type, dai_index, link_id, name, ssp_config/dmic_config) + +DAI_CONFIG(DMIC, 0, 6, NoCodec-6, + dnl DMIC_CONFIG(driver_version, clk_min, clk_mac, duty_min, duty_max, + dnl sample_rate, fifo word length, unmute time, type, + dnl dai_index, pdm controller config) + DMIC_CONFIG(1, 500000, 4800000, 40, 60, 48000, + DMIC_WORD_LENGTH(s32le), 400, DMIC, 0, + PDM_CONFIG(DMIC, 0, STEREO_PDM0))) + +DAI_CONFIG(DMIC, 1, 7, NoCodec-7, + dnl DMIC_CONFIG(driver_version, clk_min, clk_mac, duty_min, duty_max, + dnl sample_rate, fifo word length, unmute time, type, + dnl dai_index, pdm controller config) + DMIC_CONFIG(1, 500000, 4800000, 40, 60, 16000, + DMIC_WORD_LENGTH(s32le), 400, DMIC, 1, + PDM_CONFIG(DMIC, 1, STEREO_PDM0))) + +DEBUG_END diff --git a/tools/topology/sof/pipe-src-capture.m4 b/tools/topology/sof/pipe-src-capture.m4 index 4878da4a73c3..9700f40104ff 100644 --- a/tools/topology/sof/pipe-src-capture.m4 +++ b/tools/topology/sof/pipe-src-capture.m4 @@ -1,48 +1,58 @@ -# Low Latency Passthrough with volume Pipeline and PCM +# Capture pipeline with SRC and PCM # # Pipeline Endpoints for connection are :- # -# host PCM_P --> SRC --> sink DAI0 +# host PCM_C <-- B0 <-- SRC <-- B1 <-- sink DAI0 # Include topology builder +include(`pipeline.m4') +include(`buffer.m4') include(`utils.m4') include(`src.m4') -include(`buffer.m4') include(`pcm.m4') include(`dai.m4') -include(`pipeline.m4') + +# +# Controls +# # # Components and Buffers # # Host "Passthrough Capture" PCM -# with 4 sink and 0 source periods -W_PCM_CAPTURE(PCM_ID, Passthrough Capture, 4, 0) +# with 0 sink and 3 source periods +W_PCM_CAPTURE(PCM_ID, SRC Capture, 0, 3) # # SRC Configuration # -W_VENDORTUPLES(media_src_tokens, sof_src_tokens, LIST(` ', `SOF_TKN_SRC_RATE_IN "PIPELINE_RATE"')) +# Create unique names for data to allow several different input rate instances +define(MY_SRC_TOKENS, concat(`src_tokens_', PIPELINE_ID)) +define(MY_SRC_CONF, concat(`src_conf_', PIPELINE_ID)) +W_VENDORTUPLES(MY_SRC_TOKENS, sof_src_tokens, + LIST(` ', `SOF_TKN_SRC_RATE_IN "PIPELINE_RATE"')) -W_DATA(media_src_conf, media_src_tokens) +W_DATA(MY_SRC_CONF, MY_SRC_TOKENS) -# "SRC" has 4 source and 4 sink periods -W_SRC(0, PIPELINE_FORMAT, 4, 4, media_src_conf) +# "SRC" has x source and 3 sink periods +W_SRC(0, PIPELINE_FORMAT, DAI_PERIODS, 3, MY_SRC_CONF) # Capture Buffers -W_BUFFER(0, COMP_BUFFER_SIZE(4, - COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)), +W_BUFFER(0, COMP_BUFFER_SIZE(3, + COMP_SAMPLE_SIZE(PIPELINE_FORMAT), + PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)), PLATFORM_HOST_MEM_CAP) -W_BUFFER(1, COMP_BUFFER_SIZE(4, - COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)), +W_BUFFER(1, COMP_BUFFER_SIZE(DAI_PERIODS, + COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, + COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)), PLATFORM_DAI_MEM_CAP) # # Pipeline Graph # -# host PCM_P <-- B0 <-- SRC 0 <-- B1 <-- sink DAI0 +# host PCM_C <-- B0 <-- SRC <-- B1 <-- sink DAI0 P_GRAPH(pipe-pass-src-capture-PIPELINE_ID, PIPELINE_ID, LIST(` ', @@ -54,10 +64,16 @@ P_GRAPH(pipe-pass-src-capture-PIPELINE_ID, PIPELINE_ID, # Pipeline Source and Sinks # indir(`define', concat(`PIPELINE_SINK_', PIPELINE_ID), N_BUFFER(1)) -indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Passthrough Capture PCM_ID) +indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), + SRC Capture PCM_ID) # # PCM Configuration # -PCM_CAPABILITIES(Passthrough Capture PCM_ID, `S32_LE,S24_LE,S16_LE', PCM_MIN_RATE, PCM_MAX_RATE, 2, PIPELINE_CHANNELS, 2, 16, 192, 16384, 65536, 65536) +PCM_CAPABILITIES(SRC Capture PCM_ID, `S32_LE,S24_LE,S16_LE', + PCM_MIN_RATE, PCM_MAX_RATE, 2, PIPELINE_CHANNELS, + 2, 16, 192, 16384, 65536, 65536) + +undefine(`MY_SRC_TOKENS') +undefine(`MY_SRC_CONF') diff --git a/tools/topology/sof/pipe-src-volume-capture.m4 b/tools/topology/sof/pipe-src-volume-capture.m4 new file mode 100644 index 000000000000..9be2d22d6aec --- /dev/null +++ b/tools/topology/sof/pipe-src-volume-capture.m4 @@ -0,0 +1,114 @@ +# Capture pipeline with volume, SRC, and PCM +# +# Pipeline Endpoints for connection are :- +# +# host PCM_C <-- B0 <-- SRC <-- B1 <-- PGA <-- B2 <-- sink DAI0 + +# Include topology builder +include(`mixercontrol.m4') +include(`pipeline.m4') +include(`buffer.m4') +include(`utils.m4') +include(`src.m4') +include(`pcm.m4') +include(`dai.m4') +include(`pga.m4') + +# +# Controls +# + +# Volume Mixer control with max value of 32 +C_CONTROLMIXER(Master Capture Volume, PIPELINE_ID, + CONTROLMIXER_OPS(volsw, + 256 binds the mixer control to volume get/put handlers, + 256, 256), + CONTROLMIXER_MAX(, 80), + false, + CONTROLMIXER_TLV(TLV 80 steps from -50dB to +30dB for 1dB, vtlv_m50s1), + Channel register and shift for Front Left/Right, + LIST(` ', KCONTROL_CHANNEL(FL, 1, 0), KCONTROL_CHANNEL(FR, 1, 1))) + +# Volume Configuration +define(MY_PGA_TOKENS, concat(`pga_tokens_', PIPELINE_ID)) +define(MY_PGA_CONF, concat(`pga_conf_', PIPELINE_ID)) +W_VENDORTUPLES(MY_PGA_TOKENS, sof_volume_tokens, +LIST(` ', `SOF_TKN_VOLUME_RAMP_STEP_TYPE "0"' + ` ', `SOF_TKN_VOLUME_RAMP_STEP_MS "250"')) + +W_DATA(MY_PGA_CONF, MY_PGA_TOKENS) + +# +# Components and Buffers +# + +# Host "Passthrough Capture" PCM +# with 0 sink and 3 source periods +W_PCM_CAPTURE(PCM_ID, SRC Capture, 0, 3) + +# +# SRC Configuration +# + +# Create unique names for data to allow several different input rate instances +define(MY_SRC_TOKENS, concat(`src_tokens_', PIPELINE_ID)) +define(MY_SRC_CONF, concat(`src_conf_', PIPELINE_ID)) + +W_VENDORTUPLES(MY_SRC_TOKENS, sof_src_tokens, + LIST(` ', `SOF_TKN_SRC_RATE_IN "PIPELINE_RATE"')) + +W_DATA(MY_SRC_CONF, MY_SRC_TOKENS) + +# "SRC" has 3 source and 3 sink periods +W_SRC(0, PIPELINE_FORMAT, 3, 3, MY_SRC_CONF) + +# "Volume" has x source and 3 sink periods +W_PGA(0, PIPELINE_FORMAT, DAI_PERIODS, 3, MY_PGA_CONF, + LIST(` ', "PIPELINE_ID Master Capture Volume")) + +# Capture Buffers +W_BUFFER(0, COMP_BUFFER_SIZE(3, + COMP_SAMPLE_SIZE(PIPELINE_FORMAT), + PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)), + PLATFORM_HOST_MEM_CAP) +W_BUFFER(1, COMP_BUFFER_SIZE(3, + COMP_SAMPLE_SIZE(PIPELINE_FORMAT), + PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)), + PLATFORM_HOST_MEM_CAP) +W_BUFFER(2, COMP_BUFFER_SIZE(DAI_PERIODS, + COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, + COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)), + PLATFORM_DAI_MEM_CAP) + +# +# Pipeline Graph +# +# host PCM_C <-- B0 <-- SRC <-- B1 <-- PGA <-- B2 <-- sink DAI0 + +P_GRAPH(pipe-pass-src-capture-PIPELINE_ID, PIPELINE_ID, + LIST(` ', + `dapm(N_PCMC(PCM_ID), N_BUFFER(0))', + `dapm(N_BUFFER(0), N_SRC(0))', + `dapm(N_SRC(0), N_BUFFER(1))', + `dapm(N_BUFFER(1), N_PGA(0))', + `dapm(N_PGA(0), N_BUFFER(2))')) + +# +# Pipeline Source and Sinks +# +indir(`define', concat(`PIPELINE_SINK_', PIPELINE_ID), N_BUFFER(2)) +indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), + SRC Capture PCM_ID) + +# +# PCM Configuration +# + +PCM_CAPABILITIES(SRC Capture PCM_ID, `S32_LE,S24_LE,S16_LE', + PCM_MIN_RATE, PCM_MAX_RATE, 2, PIPELINE_CHANNELS, + 2, 16, 192, 16384, 65536, 65536) + +undefine(`MY_PGA_TOKENS') +undefine(`MY_PGA_CONF') +undefine(`MY_SRC_TOKENS') +undefine(`MY_SRC_CONF')