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
64 changes: 64 additions & 0 deletions src/audio/pipeline.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,10 @@ static int pipeline_for_each_comp(struct comp_dev *current,
list_for_item(clist, buffer_list) {
buffer = buffer_from_list(clist, struct comp_buffer, dir);

/* don't go back to the buffer which already walked */
if (buffer->walking)
continue;

/* execute operation on buffer */
if (ctx->buff_func)
ctx->buff_func(buffer, ctx->buff_data);
Expand All @@ -182,8 +186,10 @@ static int pipeline_for_each_comp(struct comp_dev *current,

/* continue further */
if (ctx->comp_func) {
buffer->walking = true;
int err = ctx->comp_func(buffer_comp, buffer,
ctx, dir);
buffer->walking = false;
if (err < 0)
return err;
}
Expand Down Expand Up @@ -383,11 +389,64 @@ static int pipeline_comp_hw_params(struct comp_dev *current,
return 0;
}

static int pipeline_comp_params_neg(struct comp_dev *current,
struct comp_buffer *calling_buf,
struct pipeline_walk_context *ctx,
int dir)
{
struct pipeline_data *ppl_data = ctx->comp_data;
uint32_t flags = 0;
int err = 0;

pipe_dbg(ppl_data->p, "pipeline_comp_params_neg(), current->comp.id = %u, dir = %u",
dev_comp_id(current), dir);

/* check if 'current' is already configured */
if (current->state != COMP_STATE_INIT &&
current->state != COMP_STATE_READY) {
/* return 0 if params matches */
if (buffer_params_match(calling_buf,
&ppl_data->params->params,
BUFF_PARAMS_FRAME_FMT |
BUFF_PARAMS_RATE))
return 0;
/*
* the param is conflict with an active pipeline,
* drop an error and reject the .params() command.
*/
pipe_err(ppl_data->p, "pipeline_comp_params_neg(): params conflict with existed active pipeline!");
return -EINVAL;
}

/*
* Negotiation only happen when the current component has > 1
* source or sink, we are propagating the params to branched
* buffers, and the subsequent component's .params() or .prepare()
* should be responsible for calibrating if needed. For example,
* a component who has different channels input/output buffers
* should explicitly configure the channels of the branched buffers.
*/
if (calling_buf) {
buffer_lock(calling_buf, &flags);
err = buffer_set_params(calling_buf,
&ppl_data->params->params,
BUFFER_UPDATE_FORCE);
buffer_unlock(calling_buf, flags);
}

return err;
}

static int pipeline_comp_params(struct comp_dev *current,
struct comp_buffer *calling_buf,
struct pipeline_walk_context *ctx, int dir)
{
struct pipeline_data *ppl_data = ctx->comp_data;
struct pipeline_walk_context param_neg_ctx = {
.comp_func = pipeline_comp_params_neg,
.comp_data = ppl_data,
.skip_incomplete = true,
};
int stream_direction = ppl_data->params->params.direction;
int end_type;
int err;
Expand Down Expand Up @@ -421,6 +480,11 @@ static int pipeline_comp_params(struct comp_dev *current,
if (current->state == COMP_STATE_ACTIVE)
return 0;

/* do params negotiation with other branches(opposite direction) */
err = pipeline_for_each_comp(current, &param_neg_ctx, !dir);
if (err < 0 || err == PPL_STATUS_PATH_STOP)
return err;

/* set comp direction */
current->direction = ppl_data->params->params.direction;

Expand Down
22 changes: 22 additions & 0 deletions src/include/sof/audio/buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ struct comp_buffer {
uint16_t chmap[SOF_IPC_MAX_CHANNELS]; /**< channel map - SOF_CHMAP_ */

bool hw_params_configured; /**< indicates whether hw params were set */
bool walking; /**< indicates if the buffer is being walking */
};

struct buffer_cb_transact {
Expand Down Expand Up @@ -295,4 +296,25 @@ static inline int buffer_set_params(struct comp_buffer *buffer,
return 0;
}

static inline bool buffer_params_match(struct comp_buffer *buffer,
struct sof_ipc_stream_params *params,
uint32_t flag)
{
assert(params && buffer);

if ((flag & BUFF_PARAMS_FRAME_FMT) &&
buffer->stream.frame_fmt != params->frame_fmt)
return false;

if ((flag & BUFF_PARAMS_RATE) &&
buffer->stream.rate != params->rate)
return false;

if ((flag & BUFF_PARAMS_CHANNELS) &&
buffer->stream.channels != params->channels)
return false;

return true;
}

#endif /* __SOF_AUDIO_BUFFER_H__ */