Skip to content
Closed
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
27 changes: 27 additions & 0 deletions src/audio/pipeline/pipeline-schedule.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <ipc/header.h>
#include <ipc/stream.h>
#include <ipc/topology.h>
#include <sof/ipc/common.h>
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
Expand Down Expand Up @@ -201,6 +202,25 @@ static enum task_state pipeline_task(void *arg)
* copying below.
*/
err = pipeline_copy(p);
if (p->status == COMP_STATE_DRAINING) {
/* check the return value of the copy operation.
*
* if it's <= 0 then the draining opearation is over
* and we need to send a notification to the host
*/
if (err <= 0) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what cases of err > 0 are possible here and what should be done then? Do any .copy methods return PPL_STATUS_PATH_STOP? I haven't found any such cases

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason I was under the wrong impression that pipeline_copy would return >0 in case of success and <=0 otherwise (=0 meaning it couldn't copy data) but that's not really the case.

/* set pipeline status back to ACTIVE */
p->status = COMP_STATE_ACTIVE;

/* notify host that draining is over */
err = ipc_stream_drain_notify();

if (err < 0) {
pipe_err(p, "pipeline_task(): failed drain notify");
return SOF_TASK_STATE_COMPLETED;
}
}
}
if (err < 0) {
/* try to recover */
err = pipeline_xrun_recover(p);
Expand Down Expand Up @@ -320,6 +340,13 @@ void pipeline_schedule_triggered(struct pipeline_walk_context *ctx,
*/
p->xrun_bytes = 1;
}
break;
case COMP_TRIGGER_DRAIN:
list_for_item(tlist, &ctx->pipelines) {
p = container_of(tlist, struct pipeline, list);
p->xrun_bytes = 0;
p->status = COMP_STATE_DRAINING;
}
}

irq_local_enable(flags);
Expand Down
22 changes: 15 additions & 7 deletions src/audio/pipeline/pipeline-stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ static int pipeline_comp_trigger(struct comp_dev *current,
case COMP_TRIGGER_STOP:
case COMP_TRIGGER_RELEASE:
case COMP_TRIGGER_START:
case COMP_TRIGGER_DRAIN:
break;
}

Expand All @@ -349,14 +350,21 @@ static int pipeline_comp_trigger(struct comp_dev *current,

current->pipeline->trigger.pending = false;

/* send command to the component and update pipeline state */
err = comp_trigger(current, ppl_data->cmd);
if (err < 0)
return err;
/* send command to the component and update pipeline state.
*
* if we're dealing with DRAIN trigger we don't want to update
* the state of the components since we're not using that
* information
*/
if (ppl_data->cmd != COMP_TRIGGER_DRAIN) {
err = comp_trigger(current, ppl_data->cmd);
if (err < 0)
return err;

if (err == PPL_STATUS_PATH_STOP) {
current->pipeline->trigger.aborted = true;
return err;
if (err == PPL_STATUS_PATH_STOP) {
current->pipeline->trigger.aborted = true;
return err;
}
}

switch (ppl_data->cmd) {
Expand Down
5 changes: 5 additions & 0 deletions src/include/ipc/stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,9 @@ struct sof_ipc_stream_posn {
int32_t xrun_size; /**< XRUN size in bytes */
} __attribute__((packed, aligned(4)));

/* drain information */
struct sof_ipc_stream_drain {
struct sof_ipc_reply rhdr;
} __attribute__((packed, aligned(4)));

#endif /* __IPC_STREAM_H__ */
2 changes: 2 additions & 0 deletions src/include/sof/audio/component.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ struct timestamp_data;
#define COMP_STATE_PAUSED 4 /**< Component paused */
#define COMP_STATE_ACTIVE 5 /**< Component active */
#define COMP_STATE_PRE_ACTIVE 6 /**< Component after early initialisation */
#define COMP_STATE_DRAINING 7 /**< Component draining */
/** @}*/

/** \name Standard Component Stream Commands
Expand All @@ -91,6 +92,7 @@ enum {
COMP_TRIGGER_POST_STOP, /**< Finalize stop component stream */
COMP_TRIGGER_POST_PAUSE, /**< Finalize pause component stream */
COMP_TRIGGER_NO_ACTION, /**< No action required */
COMP_TRIGGER_DRAIN, /**< Start drain operation */
};
/** @}*/

Expand Down
5 changes: 5 additions & 0 deletions src/include/sof/ipc/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,4 +197,9 @@ void ipc_msg_reply(struct sof_ipc_reply *reply);
*/
void ipc_complete_cmd(struct ipc *ipc);

/**
* \brief Notify host that the drain operation is done.
*/
int ipc_stream_drain_notify(void);

#endif /* __SOF_DRIVERS_IPC_H__ */
48 changes: 48 additions & 0 deletions src/ipc/ipc3/handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,51 @@ static int ipc_stream_position(uint32_t header)
return 1;
}

int ipc_stream_drain_notify(void)
{
struct ipc *ipc = ipc_get();
struct sof_ipc_stream stream;
struct sof_ipc_stream_drain drain;
struct ipc_comp_dev *pcm_dev;

/* copy message with ABI safe method */
IPC_COPY_CMD(stream, ipc->comp_data);

/* get the pcm dev */
pcm_dev = ipc_get_comp_by_id(ipc, stream.comp_id);
if (!pcm_dev) {
tr_err(&ipc_tr, "ipc: comp %d not found", stream.comp_id);
return -ENODEV;
}

/* check core */
if (!cpu_is_me(pcm_dev->core))
return ipc_process_on_core(pcm_dev->core, false);

/* prepare message */
memset(&drain, 0, sizeof(drain));
drain.rhdr.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_TRIG_DRAIN |
stream.comp_id;
drain.rhdr.hdr.size = sizeof(drain);

if (!pcm_dev->cd->pipeline) {
tr_err(&ipc_tr, "ipc: comp %d pipeline not found",
stream.comp_id);
return -EINVAL;
}

/* write message */
mailbox_stream_write(pcm_dev->cd->pipeline->posn_offset, &drain,
sizeof(drain));

/* send IPC notification */
struct ipc_msg *msg = ipc_msg_init(drain.rhdr.hdr.cmd, drain.rhdr.hdr.size);

ipc_msg_send(msg, &drain, false);

return 0;
}

static int ipc_stream_trigger(uint32_t header)
{
struct ipc *ipc = ipc_get();
Expand Down Expand Up @@ -461,6 +506,9 @@ static int ipc_stream_trigger(uint32_t header)
case SOF_IPC_STREAM_TRIG_RELEASE:
cmd = COMP_TRIGGER_PRE_RELEASE;
break;
case SOF_IPC_STREAM_TRIG_DRAIN:
cmd = COMP_TRIGGER_DRAIN;
break;
/* XRUN is special case- TODO */
case SOF_IPC_STREAM_TRIG_XRUN:
return 0;
Expand Down