Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 31 additions & 26 deletions src/audio/component.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ void comp_unregister(struct comp_driver_info *drv)
int comp_set_state(struct comp_dev *dev, int cmd)
{
int requested_state = comp_get_requested_state(cmd);
int ret = 0;

if (dev->state == requested_state) {
comp_info(dev, "comp_set_state(), state already set to %u",
Expand All @@ -66,41 +65,33 @@ int comp_set_state(struct comp_dev *dev, int cmd)

switch (cmd) {
case COMP_TRIGGER_START:
if (dev->state == COMP_STATE_PREPARE) {
dev->state = COMP_STATE_ACTIVE;
} else {
if (dev->state != COMP_STATE_PRE_ACTIVE) {
comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_START",
dev->state);
ret = -EINVAL;
return -EINVAL;
}
break;
case COMP_TRIGGER_RELEASE:
if (dev->state == COMP_STATE_PAUSED) {
dev->state = COMP_STATE_ACTIVE;
} else {
if (dev->state != COMP_STATE_PRE_ACTIVE) {
comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_RELEASE",
dev->state);
ret = -EINVAL;
return -EINVAL;
}
break;
case COMP_TRIGGER_STOP:
if (dev->state == COMP_STATE_ACTIVE ||
dev->state == COMP_STATE_PAUSED) {
dev->state = COMP_STATE_PREPARE;
} else {
if (dev->state != COMP_STATE_ACTIVE &&
dev->state != COMP_STATE_PAUSED) {
comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_STOP",
dev->state);
ret = -EINVAL;
return -EINVAL;
}
break;
case COMP_TRIGGER_PAUSE:
/* only support pausing for running */
if (dev->state == COMP_STATE_ACTIVE) {
dev->state = COMP_STATE_PAUSED;
} else {
if (dev->state != COMP_STATE_ACTIVE) {
comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_PAUSE",
dev->state);
ret = -EINVAL;
return -EINVAL;
}
break;
case COMP_TRIGGER_RESET:
Expand All @@ -109,26 +100,40 @@ int comp_set_state(struct comp_dev *dev, int cmd)
dev->state == COMP_STATE_PAUSED) {
comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_RESET",
dev->state);
ret = 0;
}
dev->state = COMP_STATE_READY;
break;
case COMP_TRIGGER_PREPARE:
if (dev->state == COMP_STATE_READY) {
dev->state = COMP_STATE_PREPARE;
} else {
if (dev->state != COMP_STATE_READY) {
comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_PREPARE",
dev->state);
ret = -EINVAL;
return -EINVAL;
}
break;
default:
case COMP_TRIGGER_PRE_START:
if (dev->state != COMP_STATE_PREPARE) {
comp_err(dev,
"comp_set_state(): wrong state = %u, COMP_TRIGGER_PRE_START",
dev->state);
return -EINVAL;
}
break;
case COMP_TRIGGER_PRE_RELEASE:
if (dev->state != COMP_STATE_PAUSED) {
comp_err(dev,
"comp_set_state(): wrong state = %u, COMP_TRIGGER_PRE_RELEASE",
dev->state);
return -EINVAL;
}
break;
default:
return 0;
}

dev->state = requested_state;

comp_writeback(dev);

return ret;
return 0;
}

void sys_comp_init(struct sof *sof)
Expand Down
12 changes: 9 additions & 3 deletions src/audio/dai.c
Original file line number Diff line number Diff line change
Expand Up @@ -594,12 +594,12 @@ static int dai_config_prepare(struct comp_dev *dev)
/* allocate DMA channel */
dd->chan = dma_channel_get(dd->dma, channel);
if (!dd->chan) {
comp_err(dev, "dai_config(): dma_channel_get() failed");
comp_err(dev, "dai_config_prepare(): dma_channel_get() failed");
dd->chan = NULL;
return -EIO;
}

comp_info(dev, "dai_config(): new configured dma channel index %d",
comp_info(dev, "dai_config_prepare(): new configured dma channel index %d",
dd->chan->index);

/* setup callback */
Expand Down Expand Up @@ -804,7 +804,13 @@ static int dai_comp_trigger_internal(struct comp_dev *dev, int cmd)
ret = dma_pause(dd->chan);
dai_trigger(dd->dai, cmd, dev->direction);
break;
default:
case COMP_TRIGGER_PRE_START:
case COMP_TRIGGER_PRE_RELEASE:
/* only start the DAI if we are not XRUN handling */
if (dd->xrun)
dd->xrun = 0;
else
dai_trigger(dd->dai, cmd, dev->direction);
break;
}

Expand Down
25 changes: 25 additions & 0 deletions src/audio/mixer.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,30 @@ static int mixer_trigger(struct comp_dev *dev, int cmd)

comp_dbg(dev, "mixer_trigger()");

/*
* This works around an unclear and apparently needlessly complicated
* mixer state machine.
*/
if (dir == SOF_IPC_STREAM_PLAYBACK) {
switch (cmd) {
case COMP_TRIGGER_PRE_RELEASE:
/* Mixer and everything downstream is active */
dev->state = COMP_STATE_PRE_ACTIVE;
break;
case COMP_TRIGGER_RELEASE:
/* Mixer and everything downstream is active */
dev->state = COMP_STATE_ACTIVE;
break;
case COMP_TRIGGER_PRE_START:
/* Mixer and downstream components might or might not be active */
if (mixer_source_status_count(dev, COMP_STATE_ACTIVE) ||
mixer_source_status_count(dev, COMP_STATE_PAUSED))
return PPL_STATUS_PATH_STOP;
}

comp_writeback(dev);
}

ret = comp_set_state(dev, cmd);
if (ret < 0)
return ret;
Expand All @@ -241,6 +265,7 @@ static int mixer_trigger(struct comp_dev *dev, int cmd)
(mixer_source_status_count(dev, COMP_STATE_ACTIVE) ||
mixer_source_status_count(dev, COMP_STATE_PAUSED)))) {
dev->state = COMP_STATE_ACTIVE;
comp_writeback(dev);
ret = PPL_STATUS_PATH_STOP;
}

Expand Down
7 changes: 7 additions & 0 deletions src/audio/mux/mux.c
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,13 @@ static int mux_trigger(struct comp_dev *dev, int cmd)

comp_info(dev, "mux_trigger(), command = %u", cmd);

switch (cmd) {
case COMP_TRIGGER_PRE_START:
if (mux_source_status_count(dev, COMP_STATE_ACTIVE) ||
mux_source_status_count(dev, COMP_STATE_PAUSED))
return PPL_STATUS_PATH_STOP;
}

ret = comp_set_state(dev, cmd);
if (ret < 0)
return ret;
Expand Down
1 change: 1 addition & 0 deletions src/audio/pipeline/pipeline-graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ struct pipeline *pipeline_new(uint32_t pipeline_id, uint32_t priority, uint32_t
p->priority = priority;
p->pipeline_id = pipeline_id;
p->status = COMP_STATE_INIT;
p->trigger.cmd = -EINVAL;
ret = memcpy_s(&p->tctx, sizeof(struct tr_ctx), &pipe_tr,
sizeof(struct tr_ctx));
assert(!ret);
Expand Down
85 changes: 68 additions & 17 deletions src/audio/pipeline/pipeline-schedule.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,55 @@ static enum task_state pipeline_task(void *arg)
return SOF_TASK_STATE_COMPLETED;
}

if (p->trigger.delay) {
p->trigger.delay--;
return SOF_TASK_STATE_RESCHEDULE;
}

if (p->trigger.cmd >= 0) {
/* First pipeline task run for either START or RELEASE: PRE stage */
struct sof_ipc_reply reply = {
.hdr.cmd = SOF_IPC_GLB_REPLY,
.hdr.size = sizeof(reply),
};
int cmd = p->trigger.cmd;

err = pipeline_trigger_run(p, p->trigger.host, cmd);
if (err < 0) {
pipe_err(p, "pipeline_task(): failed to trigger components: %d", err);
reply.error = err;
err = SOF_TASK_STATE_COMPLETED;
} else if (err == PPL_STATUS_PATH_STOP) {
pipe_warn(p, "pipeline_task(): stopping for xrun");
err = SOF_TASK_STATE_COMPLETED;
} else if (p->trigger.cmd != cmd) {
/* PRE stage completed */
if (p->trigger.delay)
return SOF_TASK_STATE_RESCHEDULE;
/* No delay: the final stage has already run too */
} else {
p->status = COMP_STATE_ACTIVE;
err = SOF_TASK_STATE_RESCHEDULE;
}

p->trigger.cmd = -EINVAL;

ipc_msg_reply(&reply);

return err;
}

/*
* The first execution of the pipeline task above has triggered all
* pipeline components. Subsequent iterations actually perform data
* copying below.
*/
err = pipeline_copy(p);
if (err < 0) {
/* try to recover */
err = pipeline_xrun_recover(p);
if (err < 0) {
pipe_err(p, "pipeline_task(): xrun recover failed! pipeline will be stopped!");
pipe_err(p, "pipeline_task(): xrun recovery failed! pipeline is stopped.");
/* failed - host will stop this pipeline */
return SOF_TASK_STATE_COMPLETED;
}
Expand Down Expand Up @@ -107,9 +150,11 @@ int pipeline_schedule_config(struct pipeline *p, uint32_t sched_id,
return 0;
}

/* trigger connected pipelines: either immediately or schedule them */
void pipeline_schedule_triggered(struct pipeline_walk_context *ctx,
int cmd)
{
struct pipeline_data *ppl_data = ctx->comp_data;
struct list_item *tlist;
struct pipeline *p;
uint32_t flags;
Expand All @@ -121,25 +166,31 @@ void pipeline_schedule_triggered(struct pipeline_walk_context *ctx,
*/
irq_local_disable(flags);

list_for_item(tlist, &ctx->pipelines) {
p = container_of(tlist, struct pipeline, list);

switch (cmd) {
case COMP_TRIGGER_PAUSE:
case COMP_TRIGGER_STOP:
switch (cmd) {
case COMP_TRIGGER_PAUSE:
case COMP_TRIGGER_STOP:
list_for_item(tlist, &ctx->pipelines) {
p = container_of(tlist, struct pipeline, list);
pipeline_schedule_cancel(p);
p->status = COMP_STATE_PAUSED;
break;
case COMP_TRIGGER_RELEASE:
case COMP_TRIGGER_START:
}
break;
case COMP_TRIGGER_PRE_RELEASE:
case COMP_TRIGGER_PRE_START:
list_for_item(tlist, &ctx->pipelines) {
p = container_of(tlist, struct pipeline, list);
if (pipeline_is_timer_driven(p)) {
/* Use the first of connected pipelines to trigger */
if (cmd >= 0) {
p->trigger.cmd = cmd;
p->trigger.host = ppl_data->start;
cmd = -EINVAL;
}
} else {
p->xrun_bytes = 0;
p->status = COMP_STATE_ACTIVE;
}
pipeline_schedule_copy(p, 0);
p->xrun_bytes = 0;
p->status = COMP_STATE_ACTIVE;
break;
case COMP_TRIGGER_SUSPEND:
case COMP_TRIGGER_RESUME:
default:
break;
}
}

Expand Down
Loading