diff --git a/src/audio/component.c b/src/audio/component.c index af0b9c278368..c2df4ce09123 100644 --- a/src/audio/component.c +++ b/src/audio/component.c @@ -506,7 +506,7 @@ static bool comp_check_eos(struct comp_dev *dev) enum sof_audio_buffer_state sink_state = AUDIOBUF_STATE_INITIAL; struct comp_buffer *buffer; - if (!dev->pipeline->expect_eos) + if (!dev->expect_eos) return false; comp_dev_for_each_producer(dev, buffer) { diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index a46ee5e44485..269d32cfd195 100644 --- a/src/audio/host-zephyr.c +++ b/src/audio/host-zephyr.c @@ -396,7 +396,7 @@ static inline bool host_handle_eos(struct host_data *hd, struct comp_dev *dev, struct sof_audio_buffer *buffer = &hd->local_buffer->audio_buffer; enum sof_audio_buffer_state state = audio_buffer_get_state(buffer); - if (!dev->pipeline->expect_eos) + if (!dev->expect_eos) return false; if (!avail_samples) { diff --git a/src/audio/module_adapter/module/cadence.c b/src/audio/module_adapter/module/cadence.c index 672cef86c0a2..5d997d1c6433 100644 --- a/src/audio/module_adapter/module/cadence.c +++ b/src/audio/module_adapter/module/cadence.c @@ -541,7 +541,7 @@ int cadence_codec_process_data(struct processing_module *mod, return 0; } - if (dev->pipeline->expect_eos) { + if (dev->expect_eos) { /* Signal that the stream is expected to end anytime soon */ API_CALL(cd, XA_API_CMD_INPUT_OVER, 0, NULL, ret); if (ret != LIB_NO_ERROR) { @@ -596,7 +596,7 @@ int cadence_codec_process_data(struct processing_module *mod, return ret; } - if (dev->pipeline->expect_eos) { + if (dev->expect_eos) { /* * AAC decoder cannot signal DONE, check if it stopped * producing data when EOS is expected diff --git a/src/audio/module_adapter/module/cadence_ipc4.c b/src/audio/module_adapter/module/cadence_ipc4.c index bd002ea19d9f..29dfcc8397eb 100644 --- a/src/audio/module_adapter/module/cadence_ipc4.c +++ b/src/audio/module_adapter/module/cadence_ipc4.c @@ -135,28 +135,41 @@ static int cadence_configure_mp3_enc_params(struct processing_module *mod) return 0; } +/** Configure AAC output and the external stream parameters needed for RAW input. */ static int cadence_configure_aac_dec_params(struct processing_module *mod) { struct cadence_codec_data *cd = module_get_private_data(mod); struct module_config *setup_cfg = &cd->setup_cfg; struct comp_dev *dev = mod->dev; - struct snd_codec *codec_params; - int bitstream_format = XA_AACDEC_EBITSTREAM_TYPE_AAC_ADTS; + const struct snd_codec *codec_params; + int bitstream_format; + int sample_rate; + int to_stereo; int word_size; int ret; - /* check bitstream format. Only MPEG-4 ADTS supported for now */ - if (setup_cfg->avail) { - codec_params = (struct snd_codec *)cd->setup_cfg.data; - if (codec_params->format != SND_AUDIOSTREAMFORMAT_MP4ADTS) { - comp_err(dev, "Unsupported AAC format: %d", codec_params->format); - return -EINVAL; - } - } else { + if (!setup_cfg->avail) { comp_err(dev, "No setup config available for AAC decoder"); return -EINVAL; } + codec_params = setup_cfg->data; + switch (codec_params->format) { + case SND_AUDIOSTREAMFORMAT_MP2ADTS: + case SND_AUDIOSTREAMFORMAT_MP4ADTS: + bitstream_format = XA_AACDEC_EBITSTREAM_TYPE_AAC_ADTS; + break; + case SND_AUDIOSTREAMFORMAT_ADIF: + bitstream_format = XA_AACDEC_EBITSTREAM_TYPE_AAC_ADIF; + break; + case SND_AUDIOSTREAMFORMAT_RAW: + bitstream_format = XA_AACDEC_EBITSTREAM_TYPE_AAC_RAW; + break; + default: + comp_err(dev, "Unsupported AAC format: %d", codec_params->format); + return -EINVAL; + } + /* AAC decoder module only supports 16bit or 24 bits for word size */ switch (cd->base_cfg.audio_fmt.depth) { case IPC4_DEPTH_16BIT: @@ -192,6 +205,30 @@ static int cadence_configure_aac_dec_params(struct processing_module *mod) comp_warn(dev, "applied param bitstream format return code: %#x", ret); } + if (bitstream_format == XA_AACDEC_EBITSTREAM_TYPE_AAC_RAW) { + sample_rate = codec_params->sample_rate; + API_CALL(cd, XA_API_CMD_SET_CONFIG_PARAM, + XA_AACDEC_CONFIG_PARAM_EXTERNAL_SAMPLERATE, &sample_rate, ret); + if (ret != LIB_NO_ERROR) { + if (LIB_IS_FATAL_ERROR(ret)) { + comp_err(dev, "failed to apply external sample rate: error: %#x", ret); + return ret; + } + comp_warn(dev, "applied external sample rate return code: %#x", ret); + } + + to_stereo = codec_params->ch_out == 2; + API_CALL(cd, XA_API_CMD_SET_CONFIG_PARAM, + XA_AACDEC_CONFIG_PARAM_TO_STEREO, &to_stereo, ret); + if (ret != LIB_NO_ERROR) { + if (LIB_IS_FATAL_ERROR(ret)) { + comp_err(dev, "failed to apply stereo output: error: %#x", ret); + return ret; + } + comp_warn(dev, "applied stereo output return code: %#x", ret); + } + } + return 0; } @@ -447,6 +484,26 @@ static int cadence_codec_prepare(struct processing_module *mod, return 0; } +/** Detect zero-filled host padding while draining RAW AAC. */ +static bool cadence_raw_aac_input_is_padding(struct processing_module *mod) +{ + struct cadence_codec_data *cd = module_get_private_data(mod); + struct module_data *codec = &mod->priv; + const uint8_t *input = codec->mpd.in_buff; + const struct snd_codec *codec_params = cd->setup_cfg.data; + uint32_t offset; + + if (!mod->dev->expect_eos || cd->api_id != CADENCE_CODEC_AAC_DEC_ID || + !cd->setup_cfg.avail || codec_params->format != SND_AUDIOSTREAMFORMAT_RAW) + return false; + + for (offset = 0; offset < codec->mpd.avail; offset++) + if (input[offset]) + return false; + + return true; +} + static int cadence_codec_process(struct processing_module *mod, struct sof_source **sources, int num_of_sources, struct sof_sink **sinks, int num_of_sinks) { @@ -494,6 +551,8 @@ static int cadence_codec_process(struct processing_module *mod, struct sof_sourc cadence_copy_data_from_buffer(codec->mpd.in_buff, src_ptr, codec->mpd.in_buff_size, src_bytes, source_buffer_start); codec->mpd.avail = codec->mpd.in_buff_size; + if (cadence_raw_aac_input_is_padding(mod)) + codec->mpd.avail = 0; comp_dbg(dev, "cadence_codec_process() start"); diff --git a/src/audio/pipeline/pipeline-graph.c b/src/audio/pipeline/pipeline-graph.c index e6f56eaf7096..dfefb490a09e 100644 --- a/src/audio/pipeline/pipeline-graph.c +++ b/src/audio/pipeline/pipeline-graph.c @@ -344,6 +344,42 @@ int pipeline_free(struct pipeline *p) return 0; } +static int pipeline_comp_set_eos(struct comp_dev *current, + struct comp_buffer *calling_buf, + struct pipeline_walk_context *ctx, int dir) +{ + if (ctx->comp_data != (void *)current->pipeline) + return 0; + + current->expect_eos = *(bool *)ctx->buff_data; + + return pipeline_for_each_comp(current, ctx, dir); +} + +void pipeline_set_eos(struct pipeline *p, bool eos) +{ + struct pipeline_walk_context walk_ctx = { + .comp_func = pipeline_comp_set_eos, + .comp_data = p, + .buff_data = &eos, + }; + struct comp_dev *start; + int dir; + + if (!p->source_comp || !p->sink_comp) + return; + + if (p->source_comp->direction == SOF_IPC_STREAM_PLAYBACK) { + dir = PPL_DIR_UPSTREAM; + start = p->sink_comp; + } else { + dir = PPL_DIR_DOWNSTREAM; + start = p->source_comp; + } + + walk_ctx.comp_func(start, NULL, &walk_ctx, dir); +} + static int pipeline_comp_complete(struct comp_dev *current, struct comp_buffer *calling_buf, struct pipeline_walk_context *ctx, int dir) diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index fdbe5f185eb0..560bb1a5f81c 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -647,6 +647,7 @@ struct comp_dev { /* runtime */ uint16_t state; /**< COMP_STATE_ */ uint32_t frames; /**< number of frames we copy to sink */ + bool expect_eos; /**< end of stream expected */ struct pipeline *pipeline; /**< pipeline we belong to */ struct task *task; /**< component's processing task used diff --git a/src/include/sof/audio/pipeline.h b/src/include/sof/audio/pipeline.h index b6267c47cfca..3ef8c79d7d29 100644 --- a/src/include/sof/audio/pipeline.h +++ b/src/include/sof/audio/pipeline.h @@ -70,7 +70,6 @@ struct pipeline { int32_t xrun_bytes; /* last xrun length */ uint32_t status; /* pipeline status */ struct tr_ctx tctx; /* trace settings */ - bool expect_eos; /* pipeline is expecting end of stream */ /* scheduling */ #ifdef CONFIG_IPC_MAJOR_4 @@ -225,6 +224,13 @@ void pipeline_posn_grant_access(struct k_thread *thread); */ int pipeline_reset(struct pipeline *p, struct comp_dev *host_cd); +/** + * \brief Sets End Of Stream state for all devices in the pipeline. + * \param[in] p pipeline. + * \param[in] eos End Of Stream state. + */ +void pipeline_set_eos(struct pipeline *p, bool eos); + /** * \brief Walks the pipeline graph for each component. * \param[in] current Current pipeline component. diff --git a/src/ipc/ipc4/handler-user.c b/src/ipc/ipc4/handler-user.c index 3c5479ad6105..39c2ee6cd443 100644 --- a/src/ipc/ipc4/handler-user.c +++ b/src/ipc/ipc4/handler-user.c @@ -281,7 +281,7 @@ int ipc4_pipeline_prepare(struct ipc_comp_dev *ppl_icd, uint32_t cmd) switch (cmd) { case SOF_IPC4_PIPELINE_STATE_RUNNING: - if (ppl_icd->pipeline->expect_eos) { + if (ppl_icd->pipeline->source_comp && ppl_icd->pipeline->source_comp->expect_eos) { ipc_cmd_err(&ipc_tr, "pipeline %d: Can't transition from EOS to RUNNING", ppl_icd->id); return IPC4_INVALID_REQUEST; @@ -385,7 +385,7 @@ int ipc4_pipeline_prepare(struct ipc_comp_dev *ppl_icd, uint32_t cmd) ppl_icd->id, status); return IPC4_INVALID_REQUEST; } - ppl_icd->pipeline->expect_eos = true; + pipeline_set_eos(ppl_icd->pipeline, true); return 0; /* Must return here. Any other transition clears expect_eos. */ /* special case - TODO */ case SOF_IPC4_PIPELINE_STATE_SAVED: @@ -399,7 +399,7 @@ int ipc4_pipeline_prepare(struct ipc_comp_dev *ppl_icd, uint32_t cmd) if (ret < 0) return IPC4_INVALID_REQUEST; - ppl_icd->pipeline->expect_eos = false; + pipeline_set_eos(ppl_icd->pipeline, false); return 0; } diff --git a/test/cmocka/src/audio/mux/demux_copy.c b/test/cmocka/src/audio/mux/demux_copy.c index 8e331446bbf4..cb789707306f 100644 --- a/test/cmocka/src/audio/mux/demux_copy.c +++ b/test/cmocka/src/audio/mux/demux_copy.c @@ -169,7 +169,7 @@ static int setup_test_case(void **state) dummy_pipe = test_malloc(sizeof(*dummy_pipe)); if (!dummy_pipe) return -ENOMEM; - dummy_pipe->expect_eos = false; + dev->expect_eos = false; dev->pipeline = dummy_pipe; mod = comp_mod(dev); diff --git a/test/cmocka/src/audio/mux/mux_copy.c b/test/cmocka/src/audio/mux/mux_copy.c index 66b21b0df27c..a4c42f99e94e 100644 --- a/test/cmocka/src/audio/mux/mux_copy.c +++ b/test/cmocka/src/audio/mux/mux_copy.c @@ -191,7 +191,7 @@ static int setup_test_case(void **state) dummy_pipe = test_malloc(sizeof(*dummy_pipe)); if (!dummy_pipe) return -ENOMEM; - dummy_pipe->expect_eos = false; + dev->expect_eos = false; dev->pipeline = dummy_pipe; mod = comp_mod(dev); diff --git a/tools/topology/topology2/include/formats/compr_input_audio_formats.conf b/tools/topology/topology2/include/formats/compr_input_audio_formats.conf index 8d5694400988..0f532ee105fc 100644 --- a/tools/topology/topology2/include/formats/compr_input_audio_formats.conf +++ b/tools/topology/topology2/include/formats/compr_input_audio_formats.conf @@ -1,11 +1,15 @@ # All input formats for e.g. host-copier, decoder, # and module-copier - num_input_audio_formats 40 + num_input_audio_formats 72 CombineArrays.Object.Base.input_audio_format [ { in_channels [ 1 ] in_rate [ 8000 + 16000 + 22050 + 24000 + 32000 44100 48000 96000 @@ -21,6 +25,10 @@ in_channels [ 1 ] in_rate [ 8000 + 16000 + 22050 + 24000 + 32000 44100 48000 96000 @@ -35,6 +43,10 @@ in_channels [ 1 ] in_rate [ 8000 + 16000 + 22050 + 24000 + 32000 44100 48000 96000 @@ -49,6 +61,10 @@ in_channels [ 1 ] in_rate [ 8000 + 16000 + 22050 + 24000 + 32000 44100 48000 96000 @@ -62,6 +78,10 @@ { in_rate [ 8000 + 16000 + 22050 + 24000 + 32000 44100 48000 96000 @@ -74,6 +94,10 @@ { in_rate [ 8000 + 16000 + 22050 + 24000 + 32000 44100 48000 96000 @@ -85,6 +109,10 @@ { in_rate [ 8000 + 16000 + 22050 + 24000 + 32000 44100 48000 96000 @@ -96,6 +124,10 @@ { in_rate [ 8000 + 16000 + 22050 + 24000 + 32000 44100 48000 96000 diff --git a/tools/topology/topology2/include/formats/compr_output_audio_formats.conf b/tools/topology/topology2/include/formats/compr_output_audio_formats.conf index 98d11fa51cbc..98b0a9a9ce03 100644 --- a/tools/topology/topology2/include/formats/compr_output_audio_formats.conf +++ b/tools/topology/topology2/include/formats/compr_output_audio_formats.conf @@ -1,10 +1,14 @@ # Output audio formats for e.g. host-copier and decoder - num_output_audio_formats 40 + num_output_audio_formats 72 CombineArrays.Object.Base.output_audio_format [ { out_channels [ 1 ] out_rate [ 8000 + 16000 + 22050 + 24000 + 32000 44100 48000 96000 @@ -20,6 +24,10 @@ out_channels [ 1 ] out_rate [ 8000 + 16000 + 22050 + 24000 + 32000 44100 48000 96000 @@ -34,6 +42,10 @@ out_channels [ 1 ] out_rate [ 8000 + 16000 + 22050 + 24000 + 32000 44100 48000 96000 @@ -48,6 +60,10 @@ out_channels [ 1 ] out_rate [ 8000 + 16000 + 22050 + 24000 + 32000 44100 48000 96000 @@ -61,6 +77,10 @@ { out_rate [ 8000 + 16000 + 22050 + 24000 + 32000 44100 48000 96000 @@ -73,6 +93,10 @@ { out_rate [ 8000 + 16000 + 22050 + 24000 + 32000 44100 48000 96000 @@ -84,6 +108,10 @@ { out_rate [ 8000 + 16000 + 22050 + 24000 + 32000 44100 48000 96000 @@ -95,6 +123,10 @@ { out_rate [ 8000 + 16000 + 22050 + 24000 + 32000 44100 48000 96000 diff --git a/tools/topology/topology2/include/formats/compr_output_audio_formats_s32.conf b/tools/topology/topology2/include/formats/compr_output_audio_formats_s32.conf index e377afa38687..9d5d4325e6b0 100644 --- a/tools/topology/topology2/include/formats/compr_output_audio_formats_s32.conf +++ b/tools/topology/topology2/include/formats/compr_output_audio_formats_s32.conf @@ -1,10 +1,14 @@ # Output audio formats e.g. module-copier - num_output_audio_formats 10 + num_output_audio_formats 18 CombineArrays.Object.Base.output_audio_format [ { out_channels [ 1 ] out_rate [ 8000 + 16000 + 22050 + 24000 + 32000 44100 48000 96000 @@ -18,6 +22,10 @@ { out_rate [ 8000 + 16000 + 22050 + 24000 + 32000 44100 48000 96000