mirror of https://github.com/thesofproject/sof.git
pipeline: refactor whole pipeline component
Refactor the whole pipeline component: - one method to handle both upstream and downstream walk across the pipeline graph, - code deduplication, - cuts pipeline implementation size by half. Signed-off-by: Tomasz Lauda <tomasz.lauda@linux.intel.com>
This commit is contained in:
parent
e300861d4a
commit
d918f1b3d0
1375
src/audio/pipeline.c
1375
src/audio/pipeline.c
File diff suppressed because it is too large
Load Diff
|
@ -40,6 +40,7 @@
|
|||
#include <sof/audio/component.h>
|
||||
#include <sof/trace.h>
|
||||
#include <sof/schedule.h>
|
||||
#include <sof/cache.h>
|
||||
#include <uapi/ipc/topology.h>
|
||||
|
||||
/* pipeline tracing */
|
||||
|
@ -78,6 +79,15 @@ struct comp_buffer {
|
|||
((dir) == PPL_DIR_DOWNSTREAM ? &buffer->source_list : \
|
||||
&buffer->sink_list)
|
||||
|
||||
#define buffer_from_list(ptr, type, dir) \
|
||||
((dir) == PPL_DIR_DOWNSTREAM ? \
|
||||
container_of(ptr, type, source_list) : \
|
||||
container_of(ptr, type, sink_list))
|
||||
|
||||
#define buffer_get_comp(buffer, dir) \
|
||||
((dir) == PPL_DIR_DOWNSTREAM ? buffer->sink : \
|
||||
buffer->source)
|
||||
|
||||
#define buffer_set_comp(buffer, comp, dir) \
|
||||
do { \
|
||||
if (dir == PPL_CONN_DIR_COMP_TO_BUFFER) \
|
||||
|
@ -86,6 +96,8 @@ struct comp_buffer {
|
|||
buffer->sink = comp; \
|
||||
} while (0) \
|
||||
|
||||
typedef void (*cache_buff_op)(struct comp_buffer *);
|
||||
|
||||
/* pipeline buffer creation and destruction */
|
||||
struct comp_buffer *buffer_new(struct sof_ipc_buffer *desc);
|
||||
void buffer_free(struct comp_buffer *buffer);
|
||||
|
@ -131,6 +143,30 @@ static inline uint32_t comp_buffer_get_copy_bytes(struct comp_buffer *source,
|
|||
return source->avail;
|
||||
}
|
||||
|
||||
static inline void comp_buffer_cache_wtb_inv(struct comp_buffer *buffer)
|
||||
{
|
||||
dcache_writeback_invalidate_region(buffer, sizeof(*buffer));
|
||||
}
|
||||
|
||||
static inline void comp_buffer_cache_inv(struct comp_buffer *buffer)
|
||||
{
|
||||
dcache_invalidate_region(buffer, sizeof(*buffer));
|
||||
}
|
||||
|
||||
static inline cache_buff_op comp_buffer_cache_op(int cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
case CACHE_WRITEBACK_INV:
|
||||
return &comp_buffer_cache_wtb_inv;
|
||||
case CACHE_INVALIDATE:
|
||||
return &comp_buffer_cache_inv;
|
||||
default:
|
||||
trace_buffer_error("comp_buffer_cache_op() error: "
|
||||
"invalid cmd = %u", cmd);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void buffer_reset_pos(struct comp_buffer *buffer)
|
||||
{
|
||||
/* reset read and write pointer to buffer bas */
|
||||
|
|
|
@ -118,15 +118,6 @@
|
|||
|
||||
#define COMP_CMD_IPC_MMAP_VOL(chan) (216 + chan) /* Volume */
|
||||
|
||||
/* component operations */
|
||||
#define COMP_OPS_PARAMS 0
|
||||
#define COMP_OPS_TRIGGER 1
|
||||
#define COMP_OPS_PREPARE 2
|
||||
#define COMP_OPS_COPY 3
|
||||
#define COMP_OPS_BUFFER 4
|
||||
#define COMP_OPS_RESET 5
|
||||
#define COMP_OPS_CACHE 6
|
||||
|
||||
#define trace_comp(__e, ...) trace_event(TRACE_CLASS_COMP, __e, ##__VA_ARGS__)
|
||||
#define trace_comp_error(__e, ...) trace_error(TRACE_CLASS_COMP, __e, ##__VA_ARGS__)
|
||||
#define tracev_comp(__e, ...) tracev_event(TRACE_CLASS_COMP, __e, ##__VA_ARGS__)
|
||||
|
@ -241,8 +232,6 @@ struct comp_dev {
|
|||
((dir) == PPL_DIR_DOWNSTREAM ? &comp->bsink_list : \
|
||||
&comp->bsource_list)
|
||||
|
||||
typedef void (*cache_command)(void *, size_t);
|
||||
|
||||
void sys_comp_init(void);
|
||||
|
||||
/* component registration */
|
||||
|
@ -359,18 +348,15 @@ void sys_comp_tone_init(void);
|
|||
void sys_comp_eq_iir_init(void);
|
||||
void sys_comp_eq_fir_init(void);
|
||||
|
||||
/*
|
||||
* Convenience functions to install upstream/downstream common params. Only
|
||||
* applicable to single upstream source. Components with > 1 source or sink
|
||||
* must do this manually.
|
||||
*
|
||||
* This allows params to propagate from the host PCM component downstream on
|
||||
* playback and upstream on capture.
|
||||
*/
|
||||
static inline void comp_install_params(struct comp_dev *dev,
|
||||
struct comp_dev *previous)
|
||||
static inline int comp_is_single_pipeline(struct comp_dev *current,
|
||||
struct comp_dev *previous)
|
||||
{
|
||||
dev->params = previous->params;
|
||||
return current->comp.pipeline_id == previous->comp.pipeline_id;
|
||||
}
|
||||
|
||||
static inline int comp_is_active(struct comp_dev *current)
|
||||
{
|
||||
return current->state == COMP_STATE_ACTIVE;
|
||||
}
|
||||
|
||||
static inline uint32_t comp_frame_bytes(struct comp_dev *dev)
|
||||
|
@ -426,18 +412,4 @@ static inline void comp_overrun(struct comp_dev *dev, struct comp_buffer *sink,
|
|||
pipeline_xrun(dev->pipeline, dev, (int32_t)copy_bytes - sink->free);
|
||||
}
|
||||
|
||||
static inline cache_command comp_get_cache_command(int cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
case CACHE_WRITEBACK_INV:
|
||||
return &dcache_writeback_invalidate_region;
|
||||
case CACHE_INVALIDATE:
|
||||
return &dcache_invalidate_region;
|
||||
default:
|
||||
trace_comp_error("comp_get_cache_command() error: "
|
||||
"invalid cmd = %u", cmd);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -61,7 +61,7 @@ static void test_audio_pipeline_complete_wrong_status(void **state)
|
|||
result.status = COMP_STATE_READY;
|
||||
|
||||
/*Testing component*/
|
||||
int error_code = pipeline_complete(&result);
|
||||
int error_code = pipeline_complete(&result, test_data->first);
|
||||
|
||||
assert_int_equal(error_code, -EINVAL);
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ static void test_audio_pipeline_complete_ready_state(void **state)
|
|||
cleanup_test_data(test_data);
|
||||
|
||||
/*Testing component*/
|
||||
int error_code = pipeline_complete(&result);
|
||||
int error_code = pipeline_complete(&result, test_data->first);
|
||||
|
||||
assert_int_equal(error_code, 0);
|
||||
assert_int_equal(result.status, COMP_STATE_READY);
|
||||
|
@ -89,10 +89,10 @@ static void test_audio_pipeline_complete_connect_is_endpoint(void **state)
|
|||
cleanup_test_data(test_data);
|
||||
|
||||
/*Testing component*/
|
||||
pipeline_complete(&result);
|
||||
pipeline_complete(&result, test_data->first);
|
||||
|
||||
/*Was not marked as endpoint (bsink and bsource lists empty)*/
|
||||
assert_int_equal(result.sched_comp->is_endpoint, 1);
|
||||
assert_true(list_is_empty(&result.sched_comp->bsource_list));
|
||||
}
|
||||
|
||||
static void test_audio_pipeline_complete_connect_downstream_variable_set
|
||||
|
@ -104,7 +104,7 @@ static void test_audio_pipeline_complete_connect_downstream_variable_set
|
|||
cleanup_test_data(test_data);
|
||||
|
||||
/*Testing component*/
|
||||
pipeline_complete(&result);
|
||||
pipeline_complete(&result, test_data->first);
|
||||
|
||||
assert_int_equal
|
||||
(
|
||||
|
@ -125,8 +125,6 @@ static void test_audio_pipeline_complete_connect_downstream_ignore_sink
|
|||
/*Connecting first comp to second while second is from other pipeline
|
||||
*and first has no upstream components
|
||||
*/
|
||||
test_data->first->is_endpoint = 0;
|
||||
test_data->second->is_endpoint = 0;
|
||||
list_item_append(&result.sched_comp->bsink_list,
|
||||
&test_data->b1->source_list);
|
||||
list_item_append(&test_data->b1->source_list,
|
||||
|
@ -135,10 +133,10 @@ static void test_audio_pipeline_complete_connect_downstream_ignore_sink
|
|||
&test_data->second->bsource_list);
|
||||
|
||||
/*Testing component*/
|
||||
pipeline_complete(&result);
|
||||
pipeline_complete(&result, test_data->first);
|
||||
|
||||
assert_int_equal(test_data->first->is_endpoint, 1);
|
||||
assert_int_equal(test_data->second->is_endpoint, 0);
|
||||
assert_true(list_is_empty(&test_data->first->bsource_list));
|
||||
assert_false(list_is_empty(&test_data->second->bsource_list));
|
||||
}
|
||||
|
||||
/*Test going downstream ignoring source from other pipeline*/
|
||||
|
@ -153,8 +151,6 @@ static void test_audio_pipeline_complete_connect_upstream_ignore_source
|
|||
/*Connecting first comp to second while second is from other pipeline
|
||||
*and first has no downstream components
|
||||
*/
|
||||
test_data->first->is_endpoint = 0;
|
||||
test_data->second->is_endpoint = 0;
|
||||
list_item_append(&result.sched_comp->bsource_list,
|
||||
&test_data->b1->sink_list);
|
||||
test_data->b1->sink = result.sched_comp;
|
||||
|
@ -166,10 +162,10 @@ static void test_audio_pipeline_complete_connect_upstream_ignore_source
|
|||
test_data->b2->sink = test_data->second;
|
||||
|
||||
/*Testing component*/
|
||||
pipeline_complete(&result);
|
||||
pipeline_complete(&result, test_data->first);
|
||||
|
||||
assert_int_equal(test_data->first->is_endpoint, 1);
|
||||
assert_int_equal(test_data->second->is_endpoint, 0);
|
||||
assert_true(list_is_empty(&test_data->first->bsink_list));
|
||||
assert_false(list_is_empty(&test_data->second->bsink_list));
|
||||
}
|
||||
|
||||
/*Test going downstream all the way*/
|
||||
|
@ -181,8 +177,6 @@ static void test_audio_pipeline_complete_connect_downstream_full(void **state)
|
|||
cleanup_test_data(test_data);
|
||||
|
||||
/*Connecting first comp to second*/
|
||||
test_data->first->is_endpoint = 0;
|
||||
test_data->second->is_endpoint = 0;
|
||||
test_data->second->comp.pipeline_id = PIPELINE_ID_SAME;
|
||||
list_item_append(&result.sched_comp->bsink_list,
|
||||
&test_data->b1->source_list);
|
||||
|
@ -197,7 +191,7 @@ static void test_audio_pipeline_complete_connect_downstream_full(void **state)
|
|||
test_data->second->frames = 0;
|
||||
|
||||
/*Testing component*/
|
||||
pipeline_complete(&result);
|
||||
pipeline_complete(&result, test_data->first);
|
||||
|
||||
assert_int_equal(test_data->first->frames,
|
||||
result.ipc_pipe.frames_per_sched);
|
||||
|
@ -214,8 +208,6 @@ static void test_audio_pipeline_complete_connect_upstream_full(void **state)
|
|||
cleanup_test_data(test_data);
|
||||
|
||||
/*Connecting first comp to second*/
|
||||
test_data->first->is_endpoint = 0;
|
||||
test_data->second->is_endpoint = 0;
|
||||
test_data->second->comp.pipeline_id = PIPELINE_ID_SAME;
|
||||
list_item_append(&result.sched_comp->bsource_list,
|
||||
&test_data->b1->sink_list);
|
||||
|
@ -223,7 +215,7 @@ static void test_audio_pipeline_complete_connect_upstream_full(void **state)
|
|||
test_data->b1->source = test_data->second;
|
||||
|
||||
/*Testing component*/
|
||||
pipeline_complete(&result);
|
||||
pipeline_complete(&result, test_data->first);
|
||||
|
||||
assert_int_equal(test_data->first->frames,
|
||||
result.ipc_pipe.frames_per_sched);
|
||||
|
@ -241,8 +233,6 @@ static void test_audio_pipeline_complete_connect_upstream_other_pipeline
|
|||
cleanup_test_data(test_data);
|
||||
|
||||
/*Connecting first comp to second*/
|
||||
test_data->first->is_endpoint = 0;
|
||||
test_data->second->is_endpoint = 0;
|
||||
test_data->second->comp.pipeline_id = PIPELINE_ID_DIFFERENT;
|
||||
list_item_append(&result.sched_comp->bsource_list,
|
||||
&test_data->b1->sink_list);
|
||||
|
@ -252,7 +242,7 @@ static void test_audio_pipeline_complete_connect_upstream_other_pipeline
|
|||
&test_data->b1->source_list);
|
||||
|
||||
/*Testing component*/
|
||||
pipeline_complete(&result);
|
||||
pipeline_complete(&result, test_data->first);
|
||||
|
||||
assert_ptr_equal(test_data->first, result.source_comp);
|
||||
}
|
||||
|
|
|
@ -58,19 +58,15 @@ struct pipeline_connect_data *get_standard_connect_objects(void)
|
|||
|
||||
struct comp_dev *first = calloc(sizeof(struct comp_dev), 1);
|
||||
|
||||
first->is_endpoint = 0;
|
||||
first->comp.id = 3;
|
||||
first->comp.pipeline_id = PIPELINE_ID_SAME;
|
||||
list_init(&first->bsink_list);
|
||||
list_init(&first->bsource_list);
|
||||
list_init(&pipe->comp_list);
|
||||
list_init(&pipe->buffer_list);
|
||||
pipeline_connect_data->first = first;
|
||||
pipe->sched_comp = first;
|
||||
|
||||
struct comp_dev *second = calloc(sizeof(struct comp_dev), 1);
|
||||
|
||||
second->is_endpoint = 0;
|
||||
second->comp.id = 4;
|
||||
second->comp.pipeline_id = PIPELINE_ID_DIFFERENT;
|
||||
list_init(&second->bsink_list);
|
||||
|
|
|
@ -58,7 +58,9 @@ static void test_audio_pipeline_free_comp_busy(void **state)
|
|||
|
||||
cleanup_test_data(test_data);
|
||||
|
||||
result.source_comp = test_data->first;
|
||||
result.sched_comp->state = 3;
|
||||
|
||||
/*Testing component*/
|
||||
int err = pipeline_free(&result);
|
||||
|
||||
|
@ -72,7 +74,9 @@ static void test_audio_pipeline_free_return_value(void **state)
|
|||
|
||||
cleanup_test_data(test_data);
|
||||
|
||||
result.source_comp = test_data->first;
|
||||
result.sched_comp->state = COMP_STATE_READY;
|
||||
|
||||
/*Testing component*/
|
||||
int err = pipeline_free(&result);
|
||||
|
||||
|
@ -86,6 +90,8 @@ static void test_audio_pipeline_free_sheduler_task_free(void **state)
|
|||
|
||||
cleanup_test_data(test_data);
|
||||
|
||||
result.source_comp = test_data->first;
|
||||
|
||||
/*Testing component*/
|
||||
pipeline_free(&result);
|
||||
|
||||
|
@ -94,51 +100,7 @@ static void test_audio_pipeline_free_sheduler_task_free(void **state)
|
|||
assert_ptr_equal(NULL, result.pipe_task.func);
|
||||
}
|
||||
|
||||
static void test_audio_pipeline_free_disconnect_upstream_full(void **state)
|
||||
{
|
||||
struct pipeline_connect_data *test_data = *state;
|
||||
struct pipeline result = test_data->p;
|
||||
|
||||
cleanup_test_data(test_data);
|
||||
|
||||
/*Set pipeline to check that is null later*/
|
||||
test_data->first->pipeline = &result;
|
||||
test_data->second->pipeline = &result;
|
||||
test_data->second->comp.pipeline_id = PIPELINE_ID_SAME;
|
||||
test_data->first->comp.pipeline_id = PIPELINE_ID_SAME;
|
||||
list_item_append(&result.sched_comp->bsource_list,
|
||||
&test_data->b1->sink_list);
|
||||
test_data->b1->sink = result.sched_comp;
|
||||
test_data->b1->source = test_data->second;
|
||||
|
||||
/*Testing component*/
|
||||
pipeline_free(&result);
|
||||
|
||||
assert_ptr_equal(NULL, test_data->second->pipeline);
|
||||
assert_ptr_equal(NULL, test_data->first->pipeline);
|
||||
}
|
||||
|
||||
static void test_audio_pipeline_free_disconnect_upstream_list_delete
|
||||
(void **state)
|
||||
{
|
||||
struct pipeline_connect_data *test_data = *state;
|
||||
struct pipeline result = test_data->p;
|
||||
|
||||
cleanup_test_data(test_data);
|
||||
|
||||
list_item_append(&result.sched_comp->bsource_list,
|
||||
&test_data->b1->sink_list);
|
||||
test_data->b1->sink = result.sched_comp;
|
||||
test_data->b1->source = test_data->second;
|
||||
|
||||
/*Testing component*/
|
||||
pipeline_free(&result);
|
||||
|
||||
assert_true(list_is_empty(&test_data->second->bsource_list));
|
||||
assert_true(list_is_empty(&test_data->first->bsource_list));
|
||||
}
|
||||
|
||||
static void test_audio_pipeline_free_disconnect_downstream_full(void **state)
|
||||
static void test_audio_pipeline_free_disconnect_full(void **state)
|
||||
{
|
||||
struct pipeline_connect_data *test_data = *state;
|
||||
struct pipeline result = test_data->p;
|
||||
|
@ -146,6 +108,7 @@ static void test_audio_pipeline_free_disconnect_downstream_full(void **state)
|
|||
cleanup_test_data(test_data);
|
||||
|
||||
/*Set pipeline to check that is null later*/
|
||||
result.source_comp = test_data->first;
|
||||
test_data->first->pipeline = &result;
|
||||
test_data->second->pipeline = &result;
|
||||
test_data->second->comp.pipeline_id = PIPELINE_ID_SAME;
|
||||
|
@ -162,7 +125,7 @@ static void test_audio_pipeline_free_disconnect_downstream_full(void **state)
|
|||
assert_ptr_equal(NULL, test_data->first->pipeline);
|
||||
}
|
||||
|
||||
static void test_audio_pipeline_free_disconnect_downstream_list_del
|
||||
static void test_audio_pipeline_free_disconnect_list_del
|
||||
(void **state)
|
||||
{
|
||||
struct pipeline_connect_data *test_data = *state;
|
||||
|
@ -170,6 +133,7 @@ static void test_audio_pipeline_free_disconnect_downstream_list_del
|
|||
|
||||
cleanup_test_data(test_data);
|
||||
|
||||
result.source_comp = test_data->first;
|
||||
test_data->b1->source = test_data->first;
|
||||
list_item_append(&result.sched_comp->bsink_list,
|
||||
&test_data->b1->source_list);
|
||||
|
@ -195,16 +159,10 @@ int main(void)
|
|||
test_audio_pipeline_free_sheduler_task_free
|
||||
),
|
||||
cmocka_unit_test(
|
||||
test_audio_pipeline_free_disconnect_upstream_full
|
||||
test_audio_pipeline_free_disconnect_full
|
||||
),
|
||||
cmocka_unit_test(
|
||||
test_audio_pipeline_free_disconnect_upstream_list_delete
|
||||
),
|
||||
cmocka_unit_test(
|
||||
test_audio_pipeline_free_disconnect_downstream_full
|
||||
),
|
||||
cmocka_unit_test(
|
||||
test_audio_pipeline_free_disconnect_downstream_list_del
|
||||
test_audio_pipeline_free_disconnect_list_del
|
||||
),
|
||||
};
|
||||
|
||||
|
|
|
@ -72,19 +72,6 @@ static void test_audio_pipeline_pipeline_new_creation(void **state)
|
|||
assert_non_null(result);
|
||||
}
|
||||
|
||||
static void test_audio_pipeline_new_list_initialization(void **state)
|
||||
{
|
||||
struct pipeline_new_setup_data *test_data = *state;
|
||||
|
||||
/*Testing component*/
|
||||
struct pipeline *result = pipeline_new(&test_data->ipc_data,
|
||||
test_data->comp_data);
|
||||
|
||||
/*Check list initialization*/
|
||||
assert_ptr_equal(&result->comp_list, result->comp_list.next);
|
||||
assert_ptr_equal(&result->buffer_list, result->buffer_list.next);
|
||||
}
|
||||
|
||||
static void test_audio_pipeline_new_sheduler_init(void **state)
|
||||
{
|
||||
struct pipeline_new_setup_data *test_data = *state;
|
||||
|
@ -131,7 +118,6 @@ int main(void)
|
|||
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test(test_audio_pipeline_pipeline_new_creation),
|
||||
cmocka_unit_test(test_audio_pipeline_new_list_initialization),
|
||||
cmocka_unit_test(test_audio_pipeline_new_sheduler_init),
|
||||
cmocka_unit_test(test_audio_pipeline_new_sheduler_config),
|
||||
cmocka_unit_test(test_audio_pipeline_new_ipc_data_coppy),
|
||||
|
|
Loading…
Reference in New Issue