From c56485f6128f69668cc092047b5acdd692beef44 Mon Sep 17 00:00:00 2001 From: ArturX Kloniecki Date: Tue, 7 May 2019 12:00:35 +0200 Subject: [PATCH] pipeline: Limit propagation of params, prepare and reset. In order to handle complex topologies, we need more precise control over connected pipelines behaviour and propagation of events. Better control is accomplished by limiting propagation of events in case of mismatch between starting and desination pipelines that are connected, for example when propagating from playback pipeline to branch which endpoint is Host component, or reversely, when propagating from capture pipeline to one with Dai endpoint. Signed-off-by: ArturX Kloniecki --- src/audio/pipeline.c | 80 ++++++++++++++++++++++++++++++- src/include/sof/audio/component.h | 20 ++++++++ 2 files changed, 98 insertions(+), 2 deletions(-) diff --git a/src/audio/pipeline.c b/src/audio/pipeline.c index a3d36ccf9b95..833b184e8f69 100644 --- a/src/audio/pipeline.c +++ b/src/audio/pipeline.c @@ -275,11 +275,35 @@ int pipeline_free(struct pipeline *p) static int pipeline_comp_params(struct comp_dev *current, void *data, int dir) { struct pipeline_data *ppl_data = data; + int stream_direction = ppl_data->params->params.direction; + int end_type; int err = 0; tracev_pipe("pipeline_comp_params(), current->comp.id = %u, dir = %u", current->comp.id, dir); + if (!comp_is_single_pipeline(current, ppl_data->start)) { + /* If pipeline connected to the starting one is in improper + * direction (CAPTURE towards DAI, PLAYBACK towards HOST), + * stop propagation of parameters not to override their config. + * Direction param of the pipeline can not be trusted at this + * point, as it might not be configured yet, hence checking + * for endpoint component type. + */ + end_type = comp_get_endpoint_type(current->pipeline->sink_comp); + if (stream_direction == SOF_IPC_STREAM_PLAYBACK) { + if (end_type == COMP_ENDPOINT_HOST || + end_type == COMP_ENDPOINT_NODE) + return 0; + } + + if (stream_direction == SOF_IPC_STREAM_CAPTURE) { + if (end_type == COMP_ENDPOINT_DAI || + end_type == COMP_ENDPOINT_NODE) + return 0; + } + } + /* don't do any params if current is running */ if (current->state == COMP_STATE_ACTIVE) return 0; @@ -320,6 +344,7 @@ int pipeline_params(struct pipeline *p, struct comp_dev *host, trace_pipe_with_ids(p, "pipeline_params()"); data.params = params; + data.start = host; spin_lock_irq(&p->lock, flags); @@ -337,10 +362,34 @@ int pipeline_params(struct pipeline *p, struct comp_dev *host, static int pipeline_comp_prepare(struct comp_dev *current, void *data, int dir) { int err = 0; + struct pipeline_data *ppl_data = data; + int stream_direction = ppl_data->start->params.direction; + int end_type; tracev_pipe("pipeline_comp_prepare(), current->comp.id = %u, dir = %u", current->comp.id, dir); + if (!comp_is_single_pipeline(current, ppl_data->start)) { + /* If pipeline connected to the starting one is in improper + * direction (CAPTURE towards DAI, PLAYBACK towards HOST), + * stop propagation. Direction param of the pipeline can not be + * trusted at this point, as it might not be configured yet, + * hence checking for endpoint component type. + */ + end_type = comp_get_endpoint_type(current->pipeline->sink_comp); + if (stream_direction == SOF_IPC_STREAM_PLAYBACK) { + if (end_type == COMP_ENDPOINT_HOST || + end_type == COMP_ENDPOINT_NODE) + return 0; + } + + if (stream_direction == SOF_IPC_STREAM_CAPTURE) { + if (end_type == COMP_ENDPOINT_DAI || + end_type == COMP_ENDPOINT_NODE) + return 0; + } + } + err = comp_prepare(current); if (err < 0 || err == PPL_STATUS_PATH_STOP) return err; @@ -352,14 +401,17 @@ static int pipeline_comp_prepare(struct comp_dev *current, void *data, int dir) /* prepare the pipeline for usage - preload host buffers here */ int pipeline_prepare(struct pipeline *p, struct comp_dev *dev) { + struct pipeline_data ppl_data; int ret = 0; uint32_t flags; trace_pipe_with_ids(p, "pipeline_prepare()"); + ppl_data.start = dev; + spin_lock_irq(&p->lock, flags); - ret = pipeline_comp_prepare(dev, NULL, dev->params.direction); + ret = pipeline_comp_prepare(dev, &ppl_data, dev->params.direction); if (ret < 0) { trace_pipe_error("pipeline_prepare() error: ret = %d," "dev->comp.id = %u", ret, dev->comp.id); @@ -618,11 +670,35 @@ int pipeline_trigger(struct pipeline *p, struct comp_dev *host, int cmd) static int pipeline_comp_reset(struct comp_dev *current, void *data, int dir) { + struct pipeline *p = data; + int stream_direction = p->source_comp->params.direction; + int end_type; int err = 0; tracev_pipe("pipeline_comp_reset(), current->comp.id = %u, dir = %u", current->comp.id, dir); + if (!comp_is_single_pipeline(current, p->source_comp)) { + /* If pipeline connected to the starting one is in improper + * direction (CAPTURE towards DAI, PLAYBACK towards HOST), + * stop propagation. Direction param of the pipeline can not be + * trusted at this point, as it might not be configured yet, + * hence checking for endpoint component type. + */ + end_type = comp_get_endpoint_type(current->pipeline->sink_comp); + if (stream_direction == SOF_IPC_STREAM_PLAYBACK) { + if (end_type == COMP_ENDPOINT_HOST || + end_type == COMP_ENDPOINT_NODE) + return 0; + } + + if (stream_direction == SOF_IPC_STREAM_CAPTURE) { + if (end_type == COMP_ENDPOINT_DAI || + end_type == COMP_ENDPOINT_NODE) + return 0; + } + } + err = comp_reset(current); if (err < 0 || err == PPL_STATUS_PATH_STOP) return err; @@ -641,7 +717,7 @@ int pipeline_reset(struct pipeline *p, struct comp_dev *host) spin_lock_irq(&p->lock, flags); - ret = pipeline_comp_reset(host, NULL, host->params.direction); + ret = pipeline_comp_reset(host, p, host->params.direction); if (ret < 0) { trace_ipc_error("pipeline_reset() error: ret = %d, host->comp." "id = %u", ret, host->comp.id); diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index 3eacd5512b14..7a7e4f18046f 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -164,6 +164,13 @@ #define tracev_comp(__e, ...) tracev_event(TRACE_CLASS_COMP, __e, ##__VA_ARGS__) /** @}*/ +/* \brief Type of endpoint this component is connected to in a pipeline */ +enum comp_endpoint_type { + COMP_ENDPOINT_HOST, + COMP_ENDPOINT_DAI, + COMP_ENDPOINT_NODE +}; + struct comp_dev; struct comp_buffer; struct dai_config; @@ -684,6 +691,19 @@ static inline int comp_get_requested_state(int cmd) return state; } +/* \brief Returns comp_endpoint_type of given component */ +static inline int comp_get_endpoint_type(struct comp_dev *dev) +{ + switch (dev->comp.type) { + case SOF_COMP_HOST: + return COMP_ENDPOINT_HOST; + case SOF_COMP_DAI: + return COMP_ENDPOINT_DAI; + default: + return COMP_ENDPOINT_NODE; + } +} + /** @}*/ /** \name XRUN handling.