From a3b36b1019c7392e666b2705b5e79a80452949fb Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Tue, 15 Dec 2020 18:13:24 +0200 Subject: [PATCH] mux: enable playback of multiple simultaneous streams Currently you can't play multiple simultaneous streams at the same time into mux. Fix this by copying the trigger and reset mechanism from audio mixer. Signed-off-by: Jaska Uimonen --- src/audio/mux/mux.c | 94 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 81 insertions(+), 13 deletions(-) diff --git a/src/audio/mux/mux.c b/src/audio/mux/mux.c index 7be529c1824b..829644792f46 100644 --- a/src/audio/mux/mux.c +++ b/src/audio/mux/mux.c @@ -610,48 +610,116 @@ static int mux_copy(struct comp_dev *dev) static int mux_reset(struct comp_dev *dev) { + int dir = dev->pipeline->source_comp->direction; + struct list_item *blist; + struct comp_buffer *source; + comp_info(dev, "mux_reset()"); - return comp_set_state(dev, COMP_TRIGGER_RESET); + if (dir == SOF_IPC_STREAM_PLAYBACK) { + list_for_item(blist, &dev->bsource_list) { + source = container_of(blist, struct comp_buffer, + sink_list); + /* only mux the sources with the same state with mux */ + if (source->source->state > COMP_STATE_READY) + /* should not reset the downstream components */ + return PPL_STATUS_PATH_STOP; + } + } + + comp_set_state(dev, COMP_TRIGGER_RESET); + return 0; } static int mux_prepare(struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); + struct list_item *blist; + struct comp_buffer *source; + int downstream = 0; int ret; comp_info(dev, "mux_prepare()"); - if (dev->comp.type == SOF_COMP_MUX) - cd->mux = mux_get_processing_function(dev); - else - cd->demux = demux_get_processing_function(dev); + if (dev->state != COMP_STATE_ACTIVE) { + if (dev->comp.type == SOF_COMP_MUX) + cd->mux = mux_get_processing_function(dev); + else + cd->demux = demux_get_processing_function(dev); - if (!cd->mux && !cd->demux) { - comp_err(dev, "mux_prepare(): Invalid configuration, couldn't find suitable processing function."); - return -EINVAL; + if (!cd->mux && !cd->demux) { + comp_err(dev, "mux_prepare(): Invalid configuration, couldn't find suitable processing function."); + return -EINVAL; + } + + ret = comp_set_state(dev, COMP_TRIGGER_PREPARE); + if (ret) { + comp_info(dev, "mux_prepare() comp_set_state() returned non-zero."); + return ret; + } } - ret = comp_set_state(dev, COMP_TRIGGER_PREPARE); - if (ret) { - comp_info(dev, "mux_prepare() comp_set_state() returned non-zero."); - return ret; + /* check each mux source state */ + list_for_item(blist, &dev->bsource_list) { + source = container_of(blist, struct comp_buffer, sink_list); + + /* only prepare downstream if we have no active sources */ + if (source->source->state == COMP_STATE_PAUSED || + source->source->state == COMP_STATE_ACTIVE) { + downstream = 1; + } } - return 0; + /* prepare downstream */ + return downstream; +} + +static int mux_source_status_count(struct comp_dev *mux, uint32_t status) +{ + struct comp_buffer *source; + struct list_item *blist; + int count = 0; + + /* count source with state == status */ + list_for_item(blist, &mux->bsource_list) { + source = container_of(blist, struct comp_buffer, sink_list); + if (source->source->state == status) + count++; + } + + return count; } static int mux_trigger(struct comp_dev *dev, int cmd) { + int dir = dev->pipeline->source_comp->direction; int ret = 0; comp_info(dev, "mux_trigger(), command = %u", cmd); ret = comp_set_state(dev, cmd); + if (ret < 0) + return ret; if (ret == COMP_STATUS_STATE_ALREADY_SET) ret = PPL_STATUS_PATH_STOP; + /* nothing else to check for capture streams */ + if (dir == SOF_IPC_STREAM_CAPTURE) + return ret; + + /* don't stop mux if at least one source is active */ + if (mux_source_status_count(dev, COMP_STATE_ACTIVE) && + (cmd == COMP_TRIGGER_PAUSE || cmd == COMP_TRIGGER_STOP)) { + dev->state = COMP_STATE_ACTIVE; + ret = PPL_STATUS_PATH_STOP; + /* don't stop mux if at least one source is paused */ + } else if (mux_source_status_count(dev, COMP_STATE_PAUSED) && + cmd == COMP_TRIGGER_STOP) { + dev->state = COMP_STATE_PAUSED; + ret = PPL_STATUS_PATH_STOP; + } + return ret; }