This commit is contained in:
Wim Taymans 2017-05-26 08:05:01 +02:00
parent d1a06ae247
commit 5b037661d9
154 changed files with 21017 additions and 23044 deletions

View file

@ -12,111 +12,103 @@
struct spa_ringbuffer rb;
uint8_t *data;
static int
fill_int_array (int *array, int start, int count)
static int fill_int_array(int *array, int start, int count)
{
int i, j = start;
for (i = 0; i < count; i++)
{
array[i] = j;
j = (j + 1) % MAX_VALUE;
}
return j;
int i, j = start;
for (i = 0; i < count; i++) {
array[i] = j;
j = (j + 1) % MAX_VALUE;
}
return j;
}
static int
cmp_array (int *array1, int *array2, int count)
static int cmp_array(int *array1, int *array2, int count)
{
int i;
for (i = 0; i < count; i++)
if (array1[i] != array2[i])
{
printf("%d != %d at offset %d\n", array1[i], array2[i], i);
return 0;
}
int i;
for (i = 0; i < count; i++)
if (array1[i] != array2[i]) {
printf("%d != %d at offset %d\n", array1[i], array2[i], i);
return 0;
}
return 1;
return 1;
}
static void *
reader_start (void * arg)
static void *reader_start(void *arg)
{
int i = 0, a[ARRAY_SIZE], b[ARRAY_SIZE];
unsigned long j = 0, nfailures = 0;
int i = 0, a[ARRAY_SIZE], b[ARRAY_SIZE];
unsigned long j = 0, nfailures = 0;
printf("reader started on cpu: %d\n", sched_getcpu());
printf("reader started on cpu: %d\n", sched_getcpu());
i = fill_int_array (a, i, ARRAY_SIZE);
i = fill_int_array(a, i, ARRAY_SIZE);
while (1)
{
uint32_t index;
while (1) {
uint32_t index;
if (spa_ringbuffer_get_read_index (&rb, &index) >= ARRAY_SIZE * sizeof (int))
{
spa_ringbuffer_read_data (&rb, data, index & rb.mask, b, ARRAY_SIZE * sizeof (int));
if (spa_ringbuffer_get_read_index(&rb, &index) >= ARRAY_SIZE * sizeof(int)) {
spa_ringbuffer_read_data(&rb, data, index & rb.mask, b,
ARRAY_SIZE * sizeof(int));
if (!cmp_array (a, b, ARRAY_SIZE))
{
nfailures++;
printf("failure in chunk %lu - probability: %lu/%lu = %.3f per million\n",
j, nfailures, j, (float) nfailures / (j + 1) * 1000000);
i = (b[0] + ARRAY_SIZE) % MAX_VALUE;
}
i = fill_int_array (a, i, ARRAY_SIZE);
j++;
if (!cmp_array(a, b, ARRAY_SIZE)) {
nfailures++;
printf
("failure in chunk %lu - probability: %lu/%lu = %.3f per million\n",
j, nfailures, j, (float) nfailures / (j + 1) * 1000000);
i = (b[0] + ARRAY_SIZE) % MAX_VALUE;
}
i = fill_int_array(a, i, ARRAY_SIZE);
j++;
spa_ringbuffer_read_update (&rb, index + ARRAY_SIZE * sizeof (int));
}
}
spa_ringbuffer_read_update(&rb, index + ARRAY_SIZE * sizeof(int));
}
}
return NULL;
return NULL;
}
static void *
writer_start (void * arg)
static void *writer_start(void *arg)
{
int i = 0, a[ARRAY_SIZE];
printf("writer started on cpu: %d\n", sched_getcpu());
int i = 0, a[ARRAY_SIZE];
printf("writer started on cpu: %d\n", sched_getcpu());
i = fill_int_array (a, i, ARRAY_SIZE);
i = fill_int_array(a, i, ARRAY_SIZE);
while (1)
{
uint32_t index;
while (1) {
uint32_t index;
if (spa_ringbuffer_get_write_index (&rb, &index) >= ARRAY_SIZE * sizeof (int))
{
spa_ringbuffer_write_data (&rb, data, index & rb.mask, a, ARRAY_SIZE * sizeof (int));
spa_ringbuffer_write_update (&rb, index + ARRAY_SIZE * sizeof (int));
if (spa_ringbuffer_get_write_index(&rb, &index) >= ARRAY_SIZE * sizeof(int)) {
spa_ringbuffer_write_data(&rb, data, index & rb.mask, a,
ARRAY_SIZE * sizeof(int));
spa_ringbuffer_write_update(&rb, index + ARRAY_SIZE * sizeof(int));
i = fill_int_array (a, i, ARRAY_SIZE);
}
}
i = fill_int_array(a, i, ARRAY_SIZE);
}
}
return NULL;
return NULL;
}
int main(int argc, char *argv[])
{
int size;
int size;
printf("starting ringbuffer stress test\n");
printf("starting ringbuffer stress test\n");
sscanf(argv[1], "%d", &size);
sscanf(argv[1], "%d", &size);
printf("buffer size (bytes): %d\n", size);
printf("array size (bytes): %ld\n", sizeof(int) * ARRAY_SIZE);
printf("buffer size (bytes): %d\n", size);
printf("array size (bytes): %ld\n", sizeof(int) * ARRAY_SIZE);
spa_ringbuffer_init (&rb, size);
data = malloc (size);
spa_ringbuffer_init(&rb, size);
data = malloc(size);
pthread_t reader_thread, writer_thread;
pthread_create (&reader_thread, NULL, reader_start, NULL);
pthread_create (&writer_thread, NULL, writer_start, NULL);
pthread_t reader_thread, writer_thread;
pthread_create(&reader_thread, NULL, reader_start, NULL);
pthread_create(&writer_thread, NULL, writer_start, NULL);
while (1)
sleep(1);
while (1)
sleep(1);
return 0;
return 0;
}

View file

@ -40,92 +40,91 @@
#include <lib/props.h>
struct type {
uint32_t node;
uint32_t props;
uint32_t format;
uint32_t props_device;
uint32_t props_freq;
uint32_t props_volume;
uint32_t props_min_latency;
uint32_t props_live;
struct spa_type_meta meta;
struct spa_type_data data;
struct spa_type_media_type media_type;
struct spa_type_media_subtype media_subtype;
struct spa_type_format_audio format_audio;
struct spa_type_audio_format audio_format;
struct spa_type_event_node event_node;
struct spa_type_command_node command_node;
uint32_t node;
uint32_t props;
uint32_t format;
uint32_t props_device;
uint32_t props_freq;
uint32_t props_volume;
uint32_t props_min_latency;
uint32_t props_live;
struct spa_type_meta meta;
struct spa_type_data data;
struct spa_type_media_type media_type;
struct spa_type_media_subtype media_subtype;
struct spa_type_format_audio format_audio;
struct spa_type_audio_format audio_format;
struct spa_type_event_node event_node;
struct spa_type_command_node command_node;
};
static inline void
init_type (struct type *type, struct spa_type_map *map)
static inline void init_type(struct type *type, struct spa_type_map *map)
{
type->node = spa_type_map_get_id (map, SPA_TYPE__Node);
type->props = spa_type_map_get_id (map, SPA_TYPE__Props);
type->format = spa_type_map_get_id (map, SPA_TYPE__Format);
type->props_device = spa_type_map_get_id (map, SPA_TYPE_PROPS__device);
type->props_freq = spa_type_map_get_id (map, SPA_TYPE_PROPS__frequency);
type->props_volume = spa_type_map_get_id (map, SPA_TYPE_PROPS__volume);
type->props_min_latency = spa_type_map_get_id (map, SPA_TYPE_PROPS__minLatency);
type->props_live = spa_type_map_get_id (map, SPA_TYPE_PROPS__live);
spa_type_meta_map (map, &type->meta);
spa_type_data_map (map, &type->data);
spa_type_media_type_map (map, &type->media_type);
spa_type_media_subtype_map (map, &type->media_subtype);
spa_type_format_audio_map (map, &type->format_audio);
spa_type_audio_format_map (map, &type->audio_format);
spa_type_event_node_map (map, &type->event_node);
spa_type_command_node_map (map, &type->command_node);
type->node = spa_type_map_get_id(map, SPA_TYPE__Node);
type->props = spa_type_map_get_id(map, SPA_TYPE__Props);
type->format = spa_type_map_get_id(map, SPA_TYPE__Format);
type->props_device = spa_type_map_get_id(map, SPA_TYPE_PROPS__device);
type->props_freq = spa_type_map_get_id(map, SPA_TYPE_PROPS__frequency);
type->props_volume = spa_type_map_get_id(map, SPA_TYPE_PROPS__volume);
type->props_min_latency = spa_type_map_get_id(map, SPA_TYPE_PROPS__minLatency);
type->props_live = spa_type_map_get_id(map, SPA_TYPE_PROPS__live);
spa_type_meta_map(map, &type->meta);
spa_type_data_map(map, &type->data);
spa_type_media_type_map(map, &type->media_type);
spa_type_media_subtype_map(map, &type->media_subtype);
spa_type_format_audio_map(map, &type->format_audio);
spa_type_audio_format_map(map, &type->audio_format);
spa_type_event_node_map(map, &type->event_node);
spa_type_command_node_map(map, &type->command_node);
}
struct buffer {
struct spa_buffer buffer;
struct spa_meta metas[1];
struct spa_meta_header header;
struct spa_data datas[1];
struct spa_chunk chunks[1];
struct spa_buffer buffer;
struct spa_meta metas[1];
struct spa_meta_header header;
struct spa_data datas[1];
struct spa_chunk chunks[1];
};
struct data {
struct spa_type_map *map;
struct spa_log *log;
struct spa_loop data_loop;
struct type type;
struct spa_type_map *map;
struct spa_log *log;
struct spa_loop data_loop;
struct type type;
struct spa_support support[4];
uint32_t n_support;
struct spa_support support[4];
uint32_t n_support;
struct spa_graph graph;
struct spa_graph_node source_node;
struct spa_graph_port source_out;
struct spa_graph_port volume_in;
struct spa_graph_node volume_node;
struct spa_graph_port volume_out;
struct spa_graph_port sink_in;
struct spa_graph_node sink_node;
struct spa_graph graph;
struct spa_graph_node source_node;
struct spa_graph_port source_out;
struct spa_graph_port volume_in;
struct spa_graph_node volume_node;
struct spa_graph_port volume_out;
struct spa_graph_port sink_in;
struct spa_graph_node sink_node;
struct spa_node *sink;
struct spa_port_io volume_sink_io[1];
struct spa_node *sink;
struct spa_port_io volume_sink_io[1];
struct spa_node *volume;
struct spa_buffer *volume_buffers[1];
struct buffer volume_buffer[1];
struct spa_node *volume;
struct spa_buffer *volume_buffers[1];
struct buffer volume_buffer[1];
struct spa_node *source;
struct spa_port_io source_volume_io[1];
struct spa_buffer *source_buffers[1];
struct buffer source_buffer[1];
struct spa_node *source;
struct spa_port_io source_volume_io[1];
struct spa_buffer *source_buffers[1];
struct buffer source_buffer[1];
bool running;
pthread_t thread;
bool running;
pthread_t thread;
struct spa_source sources[16];
unsigned int n_sources;
struct spa_source sources[16];
unsigned int n_sources;
bool rebuild_fds;
struct pollfd fds[16];
unsigned int n_fds;
bool rebuild_fds;
struct pollfd fds[16];
unsigned int n_fds;
};
#define MIN_LATENCY 64
@ -133,433 +132,428 @@ struct data {
#define BUFFER_SIZE MIN_LATENCY
static void
init_buffer (struct data *data, struct spa_buffer **bufs, struct buffer *ba, int n_buffers, size_t size)
init_buffer(struct data *data, struct spa_buffer **bufs, struct buffer *ba, int n_buffers,
size_t size)
{
int i;
int i;
for (i = 0; i < n_buffers; i++) {
struct buffer *b = &ba[i];
bufs[i] = &b->buffer;
for (i = 0; i < n_buffers; i++) {
struct buffer *b = &ba[i];
bufs[i] = &b->buffer;
b->buffer.id = i;
b->buffer.n_metas = 1;
b->buffer.metas = b->metas;
b->buffer.n_datas = 1;
b->buffer.datas = b->datas;
b->buffer.id = i;
b->buffer.n_metas = 1;
b->buffer.metas = b->metas;
b->buffer.n_datas = 1;
b->buffer.datas = b->datas;
b->header.flags = 0;
b->header.seq = 0;
b->header.pts = 0;
b->header.dts_offset = 0;
b->metas[0].type = data->type.meta.Header;
b->metas[0].data = &b->header;
b->metas[0].size = sizeof (b->header);
b->header.flags = 0;
b->header.seq = 0;
b->header.pts = 0;
b->header.dts_offset = 0;
b->metas[0].type = data->type.meta.Header;
b->metas[0].data = &b->header;
b->metas[0].size = sizeof(b->header);
b->datas[0].type = data->type.data.MemPtr;
b->datas[0].flags = 0;
b->datas[0].fd = -1;
b->datas[0].mapoffset = 0;
b->datas[0].maxsize = size;
b->datas[0].data = malloc (size);
b->datas[0].chunk = &b->chunks[0];
b->datas[0].chunk->offset = 0;
b->datas[0].chunk->size = size;
b->datas[0].chunk->stride = 0;
}
b->datas[0].type = data->type.data.MemPtr;
b->datas[0].flags = 0;
b->datas[0].fd = -1;
b->datas[0].mapoffset = 0;
b->datas[0].maxsize = size;
b->datas[0].data = malloc(size);
b->datas[0].chunk = &b->chunks[0];
b->datas[0].chunk->offset = 0;
b->datas[0].chunk->size = size;
b->datas[0].chunk->stride = 0;
}
}
static int
make_node (struct data *data, struct spa_node **node, const char *lib, const char *name)
static int make_node(struct data *data, struct spa_node **node, const char *lib, const char *name)
{
struct spa_handle *handle;
int res;
void *hnd;
spa_handle_factory_enum_func_t enum_func;
unsigned int i;
uint32_t state = 0;
struct spa_handle *handle;
int res;
void *hnd;
spa_handle_factory_enum_func_t enum_func;
unsigned int i;
uint32_t state = 0;
if ((hnd = dlopen (lib, RTLD_NOW)) == NULL) {
printf ("can't load %s: %s\n", lib, dlerror());
return SPA_RESULT_ERROR;
}
if ((enum_func = dlsym (hnd, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)) == NULL) {
printf ("can't find enum function\n");
return SPA_RESULT_ERROR;
}
if ((hnd = dlopen(lib, RTLD_NOW)) == NULL) {
printf("can't load %s: %s\n", lib, dlerror());
return SPA_RESULT_ERROR;
}
if ((enum_func = dlsym(hnd, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)) == NULL) {
printf("can't find enum function\n");
return SPA_RESULT_ERROR;
}
for (i = 0; ;i++) {
const struct spa_handle_factory *factory;
void *iface;
for (i = 0;; i++) {
const struct spa_handle_factory *factory;
void *iface;
if ((res = enum_func (&factory, state++)) < 0) {
if (res != SPA_RESULT_ENUM_END)
printf ("can't enumerate factories: %d\n", res);
break;
}
if (strcmp (factory->name, name))
continue;
if ((res = enum_func(&factory, state++)) < 0) {
if (res != SPA_RESULT_ENUM_END)
printf("can't enumerate factories: %d\n", res);
break;
}
if (strcmp(factory->name, name))
continue;
handle = calloc (1, factory->size);
if ((res = spa_handle_factory_init (factory, handle, NULL, data->support, data->n_support)) < 0) {
printf ("can't make factory instance: %d\n", res);
return res;
}
if ((res = spa_handle_get_interface (handle, data->type.node, &iface)) < 0) {
printf ("can't get interface %d\n", res);
return res;
}
*node = iface;
return SPA_RESULT_OK;
}
return SPA_RESULT_ERROR;
handle = calloc(1, factory->size);
if ((res =
spa_handle_factory_init(factory, handle, NULL, data->support,
data->n_support)) < 0) {
printf("can't make factory instance: %d\n", res);
return res;
}
if ((res = spa_handle_get_interface(handle, data->type.node, &iface)) < 0) {
printf("can't get interface %d\n", res);
return res;
}
*node = iface;
return SPA_RESULT_OK;
}
return SPA_RESULT_ERROR;
}
static void on_sink_event(struct spa_node *node, struct spa_event *event, void *user_data)
{
printf("got event %d\n", SPA_EVENT_TYPE(event));
}
static void on_sink_need_input(struct spa_node *node, void *user_data)
{
struct data *data = user_data;
data->sink_node.action = SPA_GRAPH_ACTION_CHECK;
data->sink_node.state = SPA_RESULT_NEED_BUFFER;
spa_graph_node_schedule(&data->graph, &data->sink_node);
}
static void
on_sink_event (struct spa_node *node, struct spa_event *event, void *user_data)
on_sink_reuse_buffer(struct spa_node *node, uint32_t port_id, uint32_t buffer_id, void *user_data)
{
printf ("got event %d\n", SPA_EVENT_TYPE (event));
struct data *data = user_data;
data->volume_sink_io[0].buffer_id = buffer_id;
}
static void
on_sink_need_input (struct spa_node *node, void *user_data)
{
struct data *data = user_data;
data->sink_node.action = SPA_GRAPH_ACTION_CHECK;
data->sink_node.state = SPA_RESULT_NEED_BUFFER;
spa_graph_node_schedule (&data->graph, &data->sink_node);
}
static void
on_sink_reuse_buffer (struct spa_node *node, uint32_t port_id, uint32_t buffer_id, void *user_data)
{
struct data *data = user_data;
data->volume_sink_io[0].buffer_id = buffer_id;
}
static const struct spa_node_callbacks sink_callbacks =
{
&on_sink_event,
&on_sink_need_input,
NULL,
&on_sink_reuse_buffer
static const struct spa_node_callbacks sink_callbacks = {
&on_sink_event,
&on_sink_need_input,
NULL,
&on_sink_reuse_buffer
};
static int
do_add_source (struct spa_loop *loop,
struct spa_source *source)
static int do_add_source(struct spa_loop *loop, struct spa_source *source)
{
struct data *data = SPA_CONTAINER_OF (loop, struct data, data_loop);
struct data *data = SPA_CONTAINER_OF(loop, struct data, data_loop);
data->sources[data->n_sources] = *source;
data->n_sources++;
data->rebuild_fds = true;
data->sources[data->n_sources] = *source;
data->n_sources++;
data->rebuild_fds = true;
return SPA_RESULT_OK;
return SPA_RESULT_OK;
}
static int
do_update_source (struct spa_source *source)
static int do_update_source(struct spa_source *source)
{
return SPA_RESULT_OK;
return SPA_RESULT_OK;
}
static void
do_remove_source (struct spa_source *source)
static void do_remove_source(struct spa_source *source)
{
}
static int
do_invoke (struct spa_loop *loop,
spa_invoke_func_t func,
uint32_t seq,
size_t size,
void *data,
void *user_data)
do_invoke(struct spa_loop *loop,
spa_invoke_func_t func, uint32_t seq, size_t size, void *data, void *user_data)
{
return func (loop, false, seq, size, data, user_data);
return func(loop, false, seq, size, data, user_data);
}
static int
make_nodes (struct data *data, const char *device)
static int make_nodes(struct data *data, const char *device)
{
int res;
struct spa_props *props;
struct spa_pod_builder b = { 0 };
struct spa_pod_frame f[2];
uint8_t buffer[128];
int res;
struct spa_props *props;
struct spa_pod_builder b = { 0 };
struct spa_pod_frame f[2];
uint8_t buffer[128];
if ((res = make_node (data, &data->sink,
"build/spa/plugins/alsa/libspa-alsa.so",
"alsa-sink")) < 0) {
printf ("can't create alsa-sink: %d\n", res);
return res;
}
spa_node_set_callbacks (data->sink, &sink_callbacks, sizeof (sink_callbacks), data);
if ((res = make_node(data, &data->sink,
"build/spa/plugins/alsa/libspa-alsa.so", "alsa-sink")) < 0) {
printf("can't create alsa-sink: %d\n", res);
return res;
}
spa_node_set_callbacks(data->sink, &sink_callbacks, sizeof(sink_callbacks), data);
spa_pod_builder_init (&b, buffer, sizeof (buffer));
spa_pod_builder_props (&b, &f[0], data->type.props,
SPA_POD_PROP (&f[1], data->type.props_device, 0, SPA_POD_TYPE_STRING, 1, device ? device : "hw:0"),
SPA_POD_PROP (&f[1], data->type.props_min_latency, 0, SPA_POD_TYPE_INT, 1, MIN_LATENCY));
props = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_props);
spa_pod_builder_init(&b, buffer, sizeof(buffer));
spa_pod_builder_props(&b, &f[0], data->type.props,
SPA_POD_PROP(&f[1], data->type.props_device, 0, SPA_POD_TYPE_STRING, 1,
device ? device : "hw:0"),
SPA_POD_PROP(&f[1], data->type.props_min_latency, 0, SPA_POD_TYPE_INT, 1,
MIN_LATENCY));
props = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_props);
if ((res = spa_node_set_props (data->sink, props)) < 0)
printf ("got set_props error %d\n", res);
if ((res = spa_node_set_props(data->sink, props)) < 0)
printf("got set_props error %d\n", res);
if ((res = make_node (data, &data->volume,
"build/spa/plugins/volume/libspa-volume.so",
"volume")) < 0) {
printf ("can't create volume: %d\n", res);
return res;
}
if ((res = make_node(data, &data->volume,
"build/spa/plugins/volume/libspa-volume.so", "volume")) < 0) {
printf("can't create volume: %d\n", res);
return res;
}
if ((res = make_node (data, &data->source,
"build/spa/plugins/audiotestsrc/libspa-audiotestsrc.so",
"audiotestsrc")) < 0) {
printf ("can't create audiotestsrc: %d\n", res);
return res;
}
if ((res = make_node(data, &data->source,
"build/spa/plugins/audiotestsrc/libspa-audiotestsrc.so",
"audiotestsrc")) < 0) {
printf("can't create audiotestsrc: %d\n", res);
return res;
}
spa_pod_builder_init (&b, buffer, sizeof (buffer));
spa_pod_builder_props (&b, &f[0], data->type.props,
SPA_POD_PROP (&f[1], data->type.props_freq, 0, SPA_POD_TYPE_DOUBLE, 1, 600.0),
SPA_POD_PROP (&f[1], data->type.props_volume, 0, SPA_POD_TYPE_DOUBLE, 1, 0.5),
SPA_POD_PROP (&f[1], data->type.props_live, 0, SPA_POD_TYPE_BOOL, 1, false));
props = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_props);
spa_pod_builder_init(&b, buffer, sizeof(buffer));
spa_pod_builder_props(&b, &f[0], data->type.props,
SPA_POD_PROP(&f[1], data->type.props_freq, 0, SPA_POD_TYPE_DOUBLE, 1,
600.0),
SPA_POD_PROP(&f[1], data->type.props_volume, 0, SPA_POD_TYPE_DOUBLE, 1,
0.5),
SPA_POD_PROP(&f[1], data->type.props_live, 0, SPA_POD_TYPE_BOOL, 1,
false));
props = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_props);
if ((res = spa_node_set_props (data->source, props)) < 0)
printf ("got set_props error %d\n", res);
if ((res = spa_node_set_props(data->source, props)) < 0)
printf("got set_props error %d\n", res);
data->source_volume_io[0] = SPA_PORT_IO_INIT;
data->volume_sink_io[0] = SPA_PORT_IO_INIT;
data->source_volume_io[0] = SPA_PORT_IO_INIT;
data->volume_sink_io[0] = SPA_PORT_IO_INIT;
spa_node_port_set_io (data->source, SPA_DIRECTION_OUTPUT, 0, &data->source_volume_io[0]);
spa_node_port_set_io (data->volume, SPA_DIRECTION_INPUT, 0, &data->source_volume_io[0]);
spa_node_port_set_io (data->volume, SPA_DIRECTION_OUTPUT, 0, &data->volume_sink_io[0]);
spa_node_port_set_io (data->sink, SPA_DIRECTION_INPUT, 0, &data->volume_sink_io[0]);
spa_node_port_set_io(data->source, SPA_DIRECTION_OUTPUT, 0, &data->source_volume_io[0]);
spa_node_port_set_io(data->volume, SPA_DIRECTION_INPUT, 0, &data->source_volume_io[0]);
spa_node_port_set_io(data->volume, SPA_DIRECTION_OUTPUT, 0, &data->volume_sink_io[0]);
spa_node_port_set_io(data->sink, SPA_DIRECTION_INPUT, 0, &data->volume_sink_io[0]);
spa_graph_node_add (&data->graph, &data->source_node, spa_graph_node_schedule_default, data->source);
spa_graph_port_add (&data->graph, &data->source_node,
&data->source_out, SPA_DIRECTION_OUTPUT, 0,
0, &data->source_volume_io[0]);
spa_graph_node_add(&data->graph, &data->source_node, spa_graph_node_schedule_default,
data->source);
spa_graph_port_add(&data->graph, &data->source_node, &data->source_out,
SPA_DIRECTION_OUTPUT, 0, 0, &data->source_volume_io[0]);
spa_graph_node_add (&data->graph, &data->volume_node, spa_graph_node_schedule_default, data->volume);
spa_graph_port_add (&data->graph, &data->volume_node,
&data->volume_in, SPA_DIRECTION_INPUT, 0,
0, &data->source_volume_io[0]);
spa_graph_node_add(&data->graph, &data->volume_node, spa_graph_node_schedule_default,
data->volume);
spa_graph_port_add(&data->graph, &data->volume_node, &data->volume_in, SPA_DIRECTION_INPUT,
0, 0, &data->source_volume_io[0]);
spa_graph_port_link (&data->graph, &data->source_out, &data->volume_in);
spa_graph_port_link(&data->graph, &data->source_out, &data->volume_in);
spa_graph_port_add (&data->graph, &data->volume_node,
&data->volume_out, SPA_DIRECTION_OUTPUT, 0,
0, &data->volume_sink_io[0]);
spa_graph_port_add(&data->graph, &data->volume_node,
&data->volume_out, SPA_DIRECTION_OUTPUT, 0, 0, &data->volume_sink_io[0]);
spa_graph_node_add (&data->graph, &data->sink_node, spa_graph_node_schedule_default, data->sink);
spa_graph_port_add (&data->graph, &data->sink_node,
&data->sink_in, SPA_DIRECTION_INPUT, 0,
0, &data->volume_sink_io[0]);
spa_graph_node_add(&data->graph, &data->sink_node, spa_graph_node_schedule_default,
data->sink);
spa_graph_port_add(&data->graph, &data->sink_node, &data->sink_in, SPA_DIRECTION_INPUT, 0,
0, &data->volume_sink_io[0]);
spa_graph_port_link (&data->graph, &data->volume_out, &data->sink_in);
spa_graph_port_link(&data->graph, &data->volume_out, &data->sink_in);
return res;
return res;
}
static int
negotiate_formats (struct data *data)
static int negotiate_formats(struct data *data)
{
int res;
struct spa_format *format, *filter;
uint32_t state = 0;
struct spa_pod_builder b = { 0 };
struct spa_pod_frame f[2];
uint8_t buffer[256];
int res;
struct spa_format *format, *filter;
uint32_t state = 0;
struct spa_pod_builder b = { 0 };
struct spa_pod_frame f[2];
uint8_t buffer[256];
spa_pod_builder_init (&b, buffer, sizeof (buffer));
spa_pod_builder_format (&b, &f[0], data->type.format,
data->type.media_type.audio, data->type.media_subtype.raw,
SPA_POD_PROP (&f[1], data->type.format_audio.format, 0,
SPA_POD_TYPE_ID, 1,
data->type.audio_format.S16),
SPA_POD_PROP (&f[1], data->type.format_audio.layout, 0,
SPA_POD_TYPE_INT, 1,
SPA_AUDIO_LAYOUT_INTERLEAVED),
SPA_POD_PROP (&f[1], data->type.format_audio.rate, 0,
SPA_POD_TYPE_INT, 1,
44100),
SPA_POD_PROP (&f[1], data->type.format_audio.channels, 0,
SPA_POD_TYPE_INT, 1,
2));
filter = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_format);
spa_pod_builder_init(&b, buffer, sizeof(buffer));
spa_pod_builder_format(&b, &f[0], data->type.format,
data->type.media_type.audio,
data->type.media_subtype.raw,
SPA_POD_PROP(&f[1], data->type.format_audio.format, 0, SPA_POD_TYPE_ID, 1,
data->type.audio_format.S16),
SPA_POD_PROP(&f[1], data->type.format_audio.layout, 0, SPA_POD_TYPE_INT, 1,
SPA_AUDIO_LAYOUT_INTERLEAVED),
SPA_POD_PROP(&f[1], data->type.format_audio.rate, 0, SPA_POD_TYPE_INT, 1,
44100),
SPA_POD_PROP(&f[1], data->type.format_audio.channels, 0, SPA_POD_TYPE_INT, 1,
2));
filter = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_format);
if ((res = spa_node_port_enum_formats (data->sink, SPA_DIRECTION_INPUT, 0, &format, filter, state)) < 0)
return res;
if ((res =
spa_node_port_enum_formats(data->sink, SPA_DIRECTION_INPUT, 0, &format, filter,
state)) < 0)
return res;
if ((res = spa_node_port_set_format (data->sink, SPA_DIRECTION_INPUT, 0, 0, format)) < 0)
return res;
if ((res = spa_node_port_set_format(data->sink, SPA_DIRECTION_INPUT, 0, 0, format)) < 0)
return res;
if ((res = spa_node_port_set_format (data->volume, SPA_DIRECTION_OUTPUT, 0, 0, format)) < 0)
return res;
if ((res = spa_node_port_set_format(data->volume, SPA_DIRECTION_OUTPUT, 0, 0, format)) < 0)
return res;
init_buffer (data, data->volume_buffers, data->volume_buffer, 1, BUFFER_SIZE);
if ((res = spa_node_port_use_buffers (data->sink, SPA_DIRECTION_INPUT, 0, data->volume_buffers, 1)) < 0)
return res;
if ((res = spa_node_port_use_buffers (data->volume, SPA_DIRECTION_OUTPUT, 0, data->volume_buffers, 1)) < 0)
return res;
init_buffer(data, data->volume_buffers, data->volume_buffer, 1, BUFFER_SIZE);
if ((res =
spa_node_port_use_buffers(data->sink, SPA_DIRECTION_INPUT, 0, data->volume_buffers,
1)) < 0)
return res;
if ((res =
spa_node_port_use_buffers(data->volume, SPA_DIRECTION_OUTPUT, 0, data->volume_buffers,
1)) < 0)
return res;
if ((res = spa_node_port_set_format (data->volume, SPA_DIRECTION_INPUT, 0, 0, format)) < 0)
return res;
if ((res = spa_node_port_set_format (data->source, SPA_DIRECTION_OUTPUT, 0, 0, format)) < 0)
return res;
if ((res = spa_node_port_set_format(data->volume, SPA_DIRECTION_INPUT, 0, 0, format)) < 0)
return res;
if ((res = spa_node_port_set_format(data->source, SPA_DIRECTION_OUTPUT, 0, 0, format)) < 0)
return res;
init_buffer (data, data->source_buffers, data->source_buffer, 1, BUFFER_SIZE);
if ((res = spa_node_port_use_buffers (data->volume, SPA_DIRECTION_INPUT, 0, data->source_buffers, 1)) < 0)
return res;
if ((res = spa_node_port_use_buffers (data->source, SPA_DIRECTION_OUTPUT, 0, data->source_buffers, 1)) < 0)
return res;
init_buffer(data, data->source_buffers, data->source_buffer, 1, BUFFER_SIZE);
if ((res =
spa_node_port_use_buffers(data->volume, SPA_DIRECTION_INPUT, 0, data->source_buffers,
1)) < 0)
return res;
if ((res =
spa_node_port_use_buffers(data->source, SPA_DIRECTION_OUTPUT, 0, data->source_buffers,
1)) < 0)
return res;
return SPA_RESULT_OK;
return SPA_RESULT_OK;
}
static void *
loop (void *user_data)
static void *loop(void *user_data)
{
struct data *data = user_data;
struct data *data = user_data;
printf ("enter thread %d\n", data->n_sources);
while (data->running) {
int i, r;
printf("enter thread %d\n", data->n_sources);
while (data->running) {
int i, r;
/* rebuild */
if (data->rebuild_fds) {
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
data->fds[i].fd = p->fd;
data->fds[i].events = p->mask;
}
data->n_fds = data->n_sources;
data->rebuild_fds = false;
}
/* rebuild */
if (data->rebuild_fds) {
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
data->fds[i].fd = p->fd;
data->fds[i].events = p->mask;
}
data->n_fds = data->n_sources;
data->rebuild_fds = false;
}
r = poll (data->fds, data->n_fds, -1);
if (r < 0) {
if (errno == EINTR)
continue;
break;
}
if (r == 0) {
fprintf (stderr, "select timeout");
break;
}
r = poll(data->fds, data->n_fds, -1);
if (r < 0) {
if (errno == EINTR)
continue;
break;
}
if (r == 0) {
fprintf(stderr, "select timeout");
break;
}
/* after */
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
p->rmask = 0;
if (data->fds[i].revents & POLLIN)
p->rmask |= SPA_IO_IN;
if (data->fds[i].revents & POLLOUT)
p->rmask |= SPA_IO_OUT;
if (data->fds[i].revents & POLLHUP)
p->rmask |= SPA_IO_HUP;
if (data->fds[i].revents & POLLERR)
p->rmask |= SPA_IO_ERR;
}
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
if (p->rmask)
p->func (p);
}
}
printf ("leave thread\n");
/* after */
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
p->rmask = 0;
if (data->fds[i].revents & POLLIN)
p->rmask |= SPA_IO_IN;
if (data->fds[i].revents & POLLOUT)
p->rmask |= SPA_IO_OUT;
if (data->fds[i].revents & POLLHUP)
p->rmask |= SPA_IO_HUP;
if (data->fds[i].revents & POLLERR)
p->rmask |= SPA_IO_ERR;
}
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
if (p->rmask)
p->func(p);
}
}
printf("leave thread\n");
return NULL;
return NULL;
}
static void
run_async_sink (struct data *data)
static void run_async_sink(struct data *data)
{
int res;
int err;
int res;
int err;
{
struct spa_command cmd = SPA_COMMAND_INIT (data->type.command_node.Start);
if ((res = spa_node_send_command (data->source, &cmd)) < 0)
printf ("got source error %d\n", res);
if ((res = spa_node_send_command (data->volume, &cmd)) < 0)
printf ("got volume error %d\n", res);
if ((res = spa_node_send_command (data->sink, &cmd)) < 0)
printf ("got sink error %d\n", res);
}
{
struct spa_command cmd = SPA_COMMAND_INIT(data->type.command_node.Start);
if ((res = spa_node_send_command(data->source, &cmd)) < 0)
printf("got source error %d\n", res);
if ((res = spa_node_send_command(data->volume, &cmd)) < 0)
printf("got volume error %d\n", res);
if ((res = spa_node_send_command(data->sink, &cmd)) < 0)
printf("got sink error %d\n", res);
}
data->running = true;
if ((err = pthread_create (&data->thread, NULL, loop, data)) != 0) {
printf ("can't create thread: %d %s", err, strerror (err));
data->running = false;
}
data->running = true;
if ((err = pthread_create(&data->thread, NULL, loop, data)) != 0) {
printf("can't create thread: %d %s", err, strerror(err));
data->running = false;
}
printf ("sleeping for 1000 seconds\n");
sleep (1000);
printf("sleeping for 1000 seconds\n");
sleep(1000);
if (data->running) {
data->running = false;
pthread_join (data->thread, NULL);
}
if (data->running) {
data->running = false;
pthread_join(data->thread, NULL);
}
{
struct spa_command cmd = SPA_COMMAND_INIT (data->type.command_node.Pause);
if ((res = spa_node_send_command (data->sink, &cmd)) < 0)
printf ("got error %d\n", res);
if ((res = spa_node_send_command (data->volume, &cmd)) < 0)
printf ("got volume error %d\n", res);
if ((res = spa_node_send_command (data->source, &cmd)) < 0)
printf ("got source error %d\n", res);
}
{
struct spa_command cmd = SPA_COMMAND_INIT(data->type.command_node.Pause);
if ((res = spa_node_send_command(data->sink, &cmd)) < 0)
printf("got error %d\n", res);
if ((res = spa_node_send_command(data->volume, &cmd)) < 0)
printf("got volume error %d\n", res);
if ((res = spa_node_send_command(data->source, &cmd)) < 0)
printf("got source error %d\n", res);
}
}
int
main (int argc, char *argv[])
int main(int argc, char *argv[])
{
struct data data = { NULL };
int res;
const char *str;
struct data data = { NULL };
int res;
const char *str;
spa_graph_init (&data.graph);
spa_graph_init(&data.graph);
data.map = spa_type_map_get_default();
data.log = spa_log_get_default();
data.data_loop.size = sizeof (struct spa_loop);
data.data_loop.add_source = do_add_source;
data.data_loop.update_source = do_update_source;
data.data_loop.remove_source = do_remove_source;
data.data_loop.invoke = do_invoke;
data.map = spa_type_map_get_default();
data.log = spa_log_get_default();
data.data_loop.size = sizeof(struct spa_loop);
data.data_loop.add_source = do_add_source;
data.data_loop.update_source = do_update_source;
data.data_loop.remove_source = do_remove_source;
data.data_loop.invoke = do_invoke;
if ((str = getenv ("SPA_DEBUG")))
data.log->level = atoi (str);
if ((str = getenv("SPA_DEBUG")))
data.log->level = atoi(str);
data.support[0].type = SPA_TYPE__TypeMap;
data.support[0].data = data.map;
data.support[1].type = SPA_TYPE__Log;
data.support[1].data = data.log;
data.support[2].type = SPA_TYPE_LOOP__DataLoop;
data.support[2].data = &data.data_loop;
data.support[3].type = SPA_TYPE_LOOP__MainLoop;
data.support[3].data = &data.data_loop;
data.n_support = 4;
data.support[0].type = SPA_TYPE__TypeMap;
data.support[0].data = data.map;
data.support[1].type = SPA_TYPE__Log;
data.support[1].data = data.log;
data.support[2].type = SPA_TYPE_LOOP__DataLoop;
data.support[2].data = &data.data_loop;
data.support[3].type = SPA_TYPE_LOOP__MainLoop;
data.support[3].data = &data.data_loop;
data.n_support = 4;
init_type (&data.type, data.map);
init_type(&data.type, data.map);
if ((res = make_nodes (&data, argc > 1 ? argv[1] : NULL)) < 0) {
printf ("can't make nodes: %d\n", res);
return -1;
}
if ((res = negotiate_formats (&data)) < 0) {
printf ("can't negotiate nodes: %d\n", res);
return -1;
}
if ((res = make_nodes(&data, argc > 1 ? argv[1] : NULL)) < 0) {
printf("can't make nodes: %d\n", res);
return -1;
}
if ((res = negotiate_formats(&data)) < 0) {
printf("can't negotiate nodes: %d\n", res);
return -1;
}
run_async_sink (&data);
run_async_sink(&data);
}

File diff suppressed because it is too large Load diff

View file

@ -47,86 +47,85 @@
#define MODE_DIRECT (1<<4)
struct type {
uint32_t node;
uint32_t props;
uint32_t format;
uint32_t props_device;
uint32_t props_freq;
uint32_t props_volume;
uint32_t props_min_latency;
uint32_t props_live;
struct spa_type_meta meta;
struct spa_type_data data;
struct spa_type_media_type media_type;
struct spa_type_media_subtype media_subtype;
struct spa_type_event_node event_node;
struct spa_type_command_node command_node;
uint32_t node;
uint32_t props;
uint32_t format;
uint32_t props_device;
uint32_t props_freq;
uint32_t props_volume;
uint32_t props_min_latency;
uint32_t props_live;
struct spa_type_meta meta;
struct spa_type_data data;
struct spa_type_media_type media_type;
struct spa_type_media_subtype media_subtype;
struct spa_type_event_node event_node;
struct spa_type_command_node command_node;
};
static inline void
init_type (struct type *type, struct spa_type_map *map)
static inline void init_type(struct type *type, struct spa_type_map *map)
{
type->node = spa_type_map_get_id (map, SPA_TYPE__Node);
type->props = spa_type_map_get_id (map, SPA_TYPE__Props);
type->format = spa_type_map_get_id (map, SPA_TYPE__Format);
type->props_device = spa_type_map_get_id (map, SPA_TYPE_PROPS__device);
type->props_freq = spa_type_map_get_id (map, SPA_TYPE_PROPS__frequency);
type->props_volume = spa_type_map_get_id (map, SPA_TYPE_PROPS__volume);
type->props_min_latency = spa_type_map_get_id (map, SPA_TYPE_PROPS__minLatency);
type->props_live = spa_type_map_get_id (map, SPA_TYPE_PROPS__live);
spa_type_meta_map (map, &type->meta);
spa_type_data_map (map, &type->data);
spa_type_media_type_map (map, &type->media_type);
spa_type_media_subtype_map (map, &type->media_subtype);
spa_type_event_node_map (map, &type->event_node);
spa_type_command_node_map (map, &type->command_node);
type->node = spa_type_map_get_id(map, SPA_TYPE__Node);
type->props = spa_type_map_get_id(map, SPA_TYPE__Props);
type->format = spa_type_map_get_id(map, SPA_TYPE__Format);
type->props_device = spa_type_map_get_id(map, SPA_TYPE_PROPS__device);
type->props_freq = spa_type_map_get_id(map, SPA_TYPE_PROPS__frequency);
type->props_volume = spa_type_map_get_id(map, SPA_TYPE_PROPS__volume);
type->props_min_latency = spa_type_map_get_id(map, SPA_TYPE_PROPS__minLatency);
type->props_live = spa_type_map_get_id(map, SPA_TYPE_PROPS__live);
spa_type_meta_map(map, &type->meta);
spa_type_data_map(map, &type->data);
spa_type_media_type_map(map, &type->media_type);
spa_type_media_subtype_map(map, &type->media_subtype);
spa_type_event_node_map(map, &type->event_node);
spa_type_command_node_map(map, &type->command_node);
}
struct buffer {
struct spa_buffer buffer;
struct spa_meta metas[1];
struct spa_meta_header header;
struct spa_data datas[1];
struct spa_chunk chunks[1];
struct spa_buffer buffer;
struct spa_meta metas[1];
struct spa_meta_header header;
struct spa_data datas[1];
struct spa_chunk chunks[1];
};
struct data {
struct spa_type_map *map;
struct spa_log *log;
struct spa_loop data_loop;
struct type type;
struct spa_type_map *map;
struct spa_log *log;
struct spa_loop data_loop;
struct type type;
int mode;
int mode;
struct spa_support support[4];
uint32_t n_support;
struct spa_support support[4];
uint32_t n_support;
int iterations;
int iterations;
struct spa_graph graph;
struct spa_graph_node source_node;
struct spa_graph_port source_out;
struct spa_graph_port sink_in;
struct spa_graph_node sink_node;
struct spa_graph graph;
struct spa_graph_node source_node;
struct spa_graph_port source_out;
struct spa_graph_port sink_in;
struct spa_graph_node sink_node;
struct spa_node *sink;
struct spa_port_io source_sink_io[1];
struct spa_node *sink;
struct spa_port_io source_sink_io[1];
struct spa_node *source;
struct spa_buffer *source_buffers[1];
struct buffer source_buffer[1];
struct spa_node *source;
struct spa_buffer *source_buffers[1];
struct buffer source_buffer[1];
bool running;
pthread_t thread;
bool running;
pthread_t thread;
struct spa_source sources[16];
unsigned int n_sources;
struct spa_source sources[16];
unsigned int n_sources;
bool rebuild_fds;
struct pollfd fds[16];
unsigned int n_fds;
bool rebuild_fds;
struct pollfd fds[16];
unsigned int n_fds;
void *hnd;
void *hnd;
};
#define MIN_LATENCY 64
@ -134,444 +133,423 @@ struct data {
#define BUFFER_SIZE MIN_LATENCY
static void
init_buffer (struct data *data, struct spa_buffer **bufs, struct buffer *ba, int n_buffers, size_t size)
init_buffer(struct data *data, struct spa_buffer **bufs, struct buffer *ba, int n_buffers,
size_t size)
{
int i;
int i;
for (i = 0; i < n_buffers; i++) {
struct buffer *b = &ba[i];
bufs[i] = &b->buffer;
for (i = 0; i < n_buffers; i++) {
struct buffer *b = &ba[i];
bufs[i] = &b->buffer;
b->buffer.id = i;
b->buffer.n_metas = 1;
b->buffer.metas = b->metas;
b->buffer.n_datas = 1;
b->buffer.datas = b->datas;
b->buffer.id = i;
b->buffer.n_metas = 1;
b->buffer.metas = b->metas;
b->buffer.n_datas = 1;
b->buffer.datas = b->datas;
b->header.flags = 0;
b->header.seq = 0;
b->header.pts = 0;
b->header.dts_offset = 0;
b->metas[0].type = data->type.meta.Header;
b->metas[0].data = &b->header;
b->metas[0].size = sizeof (b->header);
b->header.flags = 0;
b->header.seq = 0;
b->header.pts = 0;
b->header.dts_offset = 0;
b->metas[0].type = data->type.meta.Header;
b->metas[0].data = &b->header;
b->metas[0].size = sizeof(b->header);
b->datas[0].type = data->type.data.MemPtr;
b->datas[0].flags = 0;
b->datas[0].fd = -1;
b->datas[0].mapoffset = 0;
b->datas[0].maxsize = size;
b->datas[0].data = malloc (size);
b->datas[0].chunk = &b->chunks[0];
b->datas[0].chunk->offset = 0;
b->datas[0].chunk->size = size;
b->datas[0].chunk->stride = 0;
}
b->datas[0].type = data->type.data.MemPtr;
b->datas[0].flags = 0;
b->datas[0].fd = -1;
b->datas[0].mapoffset = 0;
b->datas[0].maxsize = size;
b->datas[0].data = malloc(size);
b->datas[0].chunk = &b->chunks[0];
b->datas[0].chunk->offset = 0;
b->datas[0].chunk->size = size;
b->datas[0].chunk->stride = 0;
}
}
static int
make_node (struct data *data, struct spa_node **node, const char *lib, const char *name)
static int make_node(struct data *data, struct spa_node **node, const char *lib, const char *name)
{
struct spa_handle *handle;
int res;
spa_handle_factory_enum_func_t enum_func;
unsigned int i;
uint32_t state = 0;
struct spa_handle *handle;
int res;
spa_handle_factory_enum_func_t enum_func;
unsigned int i;
uint32_t state = 0;
if (data->hnd == NULL) {
if ((data->hnd = dlopen (lib, RTLD_NOW)) == NULL) {
printf ("can't load %s: %s\n", lib, dlerror());
return SPA_RESULT_ERROR;
}
}
if ((enum_func = dlsym (data->hnd, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)) == NULL) {
printf ("can't find enum function\n");
return SPA_RESULT_ERROR;
}
if (data->hnd == NULL) {
if ((data->hnd = dlopen(lib, RTLD_NOW)) == NULL) {
printf("can't load %s: %s\n", lib, dlerror());
return SPA_RESULT_ERROR;
}
}
if ((enum_func = dlsym(data->hnd, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)) == NULL) {
printf("can't find enum function\n");
return SPA_RESULT_ERROR;
}
for (i = 0; ;i++) {
const struct spa_handle_factory *factory;
void *iface;
for (i = 0;; i++) {
const struct spa_handle_factory *factory;
void *iface;
if ((res = enum_func (&factory, state++)) < 0) {
if (res != SPA_RESULT_ENUM_END)
printf ("can't enumerate factories: %d\n", res);
break;
}
if (strcmp (factory->name, name))
continue;
if ((res = enum_func(&factory, state++)) < 0) {
if (res != SPA_RESULT_ENUM_END)
printf("can't enumerate factories: %d\n", res);
break;
}
if (strcmp(factory->name, name))
continue;
handle = calloc (1, factory->size);
if ((res = spa_handle_factory_init (factory, handle, NULL, data->support, data->n_support)) < 0) {
printf ("can't make factory instance: %d\n", res);
return res;
}
if ((res = spa_handle_get_interface (handle, data->type.node, &iface)) < 0) {
printf ("can't get interface %d\n", res);
return res;
}
*node = iface;
return SPA_RESULT_OK;
}
return SPA_RESULT_ERROR;
handle = calloc(1, factory->size);
if ((res =
spa_handle_factory_init(factory, handle, NULL, data->support,
data->n_support)) < 0) {
printf("can't make factory instance: %d\n", res);
return res;
}
if ((res = spa_handle_get_interface(handle, data->type.node, &iface)) < 0) {
printf("can't get interface %d\n", res);
return res;
}
*node = iface;
return SPA_RESULT_OK;
}
return SPA_RESULT_ERROR;
}
static void on_sink_pull(struct data *data)
{
spa_log_trace(data->log, "do sink pull");
data->sink_node.state = SPA_RESULT_NEED_BUFFER;
if (data->mode & MODE_DIRECT) {
spa_node_process_output(data->source);
spa_node_process_input(data->sink);
} else {
data->sink_node.action = SPA_GRAPH_ACTION_CHECK;
spa_graph_node_schedule(&data->graph, &data->sink_node);
}
}
static void on_source_push(struct data *data)
{
spa_log_trace(data->log, "do source push");
if (data->mode & MODE_DIRECT) {
spa_node_process_output(data->source);
spa_node_process_input(data->sink);
} else {
data->source_node.action = SPA_GRAPH_ACTION_OUT;
spa_graph_node_schedule(&data->graph, &data->source_node);
}
}
static void on_sink_event(struct spa_node *node, struct spa_event *event, void *user_data)
{
struct data *data = user_data;
spa_log_trace(data->log, "got sink event %d", SPA_EVENT_TYPE(event));
}
static void on_sink_need_input(struct spa_node *node, void *user_data)
{
struct data *data = user_data;
spa_log_trace(data->log, "need input");
on_sink_pull(data);
if (--data->iterations == 0)
data->running = false;
}
static void
on_sink_pull (struct data *data)
on_sink_reuse_buffer(struct spa_node *node, uint32_t port_id, uint32_t buffer_id, void *user_data)
{
spa_log_trace (data->log, "do sink pull");
data->sink_node.state = SPA_RESULT_NEED_BUFFER;
if (data->mode & MODE_DIRECT) {
spa_node_process_output (data->source);
spa_node_process_input (data->sink);
}
else {
data->sink_node.action = SPA_GRAPH_ACTION_CHECK;
spa_graph_node_schedule (&data->graph, &data->sink_node);
}
struct data *data = user_data;
data->source_sink_io[0].buffer_id = buffer_id;
}
static void
on_source_push (struct data *data)
{
spa_log_trace (data->log, "do source push");
if (data->mode & MODE_DIRECT) {
spa_node_process_output (data->source);
spa_node_process_input (data->sink);
}
else {
data->source_node.action = SPA_GRAPH_ACTION_OUT;
spa_graph_node_schedule (&data->graph, &data->source_node);
}
}
static void
on_sink_event (struct spa_node *node, struct spa_event *event, void *user_data)
{
struct data *data = user_data;
spa_log_trace (data->log, "got sink event %d", SPA_EVENT_TYPE (event));
}
static void
on_sink_need_input (struct spa_node *node, void *user_data)
{
struct data *data = user_data;
spa_log_trace (data->log, "need input");
on_sink_pull (data);
if (--data->iterations == 0)
data->running = false;
}
static void
on_sink_reuse_buffer (struct spa_node *node, uint32_t port_id, uint32_t buffer_id, void *user_data)
{
struct data *data = user_data;
data->source_sink_io[0].buffer_id = buffer_id;
}
static const struct spa_node_callbacks sink_callbacks =
{
&on_sink_event,
&on_sink_need_input,
NULL,
&on_sink_reuse_buffer
static const struct spa_node_callbacks sink_callbacks = {
&on_sink_event,
&on_sink_need_input,
NULL,
&on_sink_reuse_buffer
};
static void
on_source_event (struct spa_node *node, struct spa_event *event, void *user_data)
static void on_source_event(struct spa_node *node, struct spa_event *event, void *user_data)
{
struct data *data = user_data;
spa_log_trace (data->log, "got source event %d", SPA_EVENT_TYPE (event));
struct data *data = user_data;
spa_log_trace(data->log, "got source event %d", SPA_EVENT_TYPE(event));
}
static void
on_source_have_output (struct spa_node *node, void *user_data)
static void on_source_have_output(struct spa_node *node, void *user_data)
{
struct data *data = user_data;
spa_log_trace (data->log, "have_output");
on_source_push (data);
if (--data->iterations == 0)
data->running = false;
struct data *data = user_data;
spa_log_trace(data->log, "have_output");
on_source_push(data);
if (--data->iterations == 0)
data->running = false;
}
static const struct spa_node_callbacks source_callbacks =
{
&on_source_event,
NULL,
&on_source_have_output,
NULL
static const struct spa_node_callbacks source_callbacks = {
&on_source_event,
NULL,
&on_source_have_output,
NULL
};
static int
do_add_source (struct spa_loop *loop,
struct spa_source *source)
static int do_add_source(struct spa_loop *loop, struct spa_source *source)
{
struct data *data = SPA_CONTAINER_OF (loop, struct data, data_loop);
struct data *data = SPA_CONTAINER_OF(loop, struct data, data_loop);
data->sources[data->n_sources] = *source;
data->n_sources++;
data->rebuild_fds = true;
data->sources[data->n_sources] = *source;
data->n_sources++;
data->rebuild_fds = true;
return SPA_RESULT_OK;
return SPA_RESULT_OK;
}
static int
do_update_source (struct spa_source *source)
static int do_update_source(struct spa_source *source)
{
return SPA_RESULT_OK;
return SPA_RESULT_OK;
}
static void
do_remove_source (struct spa_source *source)
static void do_remove_source(struct spa_source *source)
{
}
static int
do_invoke (struct spa_loop *loop,
spa_invoke_func_t func,
uint32_t seq,
size_t size,
void *data,
void *user_data)
do_invoke(struct spa_loop *loop,
spa_invoke_func_t func, uint32_t seq, size_t size, void *data, void *user_data)
{
return func (loop, false, seq, size, data, user_data);
return func(loop, false, seq, size, data, user_data);
}
static int
make_nodes (struct data *data)
static int make_nodes(struct data *data)
{
int res;
int res;
if ((res = make_node (data, &data->sink,
"build/spa/plugins/test/libspa-test.so",
"fakesink")) < 0) {
printf ("can't create fakesink: %d\n", res);
return res;
}
if ((res = make_node(data, &data->sink,
"build/spa/plugins/test/libspa-test.so", "fakesink")) < 0) {
printf("can't create fakesink: %d\n", res);
return res;
}
if (data->mode & MODE_ASYNC_PULL)
spa_node_set_callbacks (data->sink, &sink_callbacks, sizeof (sink_callbacks), data);
if (data->mode & MODE_ASYNC_PULL)
spa_node_set_callbacks(data->sink, &sink_callbacks, sizeof(sink_callbacks), data);
if ((res = make_node (data, &data->source,
"build/spa/plugins/test/libspa-test.so",
"fakesrc")) < 0) {
printf ("can't create fakesrc: %d\n", res);
return res;
}
if ((res = make_node(data, &data->source,
"build/spa/plugins/test/libspa-test.so", "fakesrc")) < 0) {
printf("can't create fakesrc: %d\n", res);
return res;
}
if (data->mode & MODE_ASYNC_PUSH)
spa_node_set_callbacks (data->source, &source_callbacks, sizeof (source_callbacks), data);
if (data->mode & MODE_ASYNC_PUSH)
spa_node_set_callbacks(data->source, &source_callbacks, sizeof(source_callbacks),
data);
data->source_sink_io[0] = SPA_PORT_IO_INIT;
data->source_sink_io[0].status = SPA_RESULT_NEED_BUFFER;
data->source_sink_io[0] = SPA_PORT_IO_INIT;
data->source_sink_io[0].status = SPA_RESULT_NEED_BUFFER;
spa_node_port_set_io (data->source, SPA_DIRECTION_OUTPUT, 0, &data->source_sink_io[0]);
spa_node_port_set_io (data->sink, SPA_DIRECTION_INPUT, 0, &data->source_sink_io[0]);
spa_node_port_set_io(data->source, SPA_DIRECTION_OUTPUT, 0, &data->source_sink_io[0]);
spa_node_port_set_io(data->sink, SPA_DIRECTION_INPUT, 0, &data->source_sink_io[0]);
spa_graph_node_add (&data->graph, &data->source_node,
spa_graph_node_schedule_default, data->source);
data->source_node.flags = (data->mode & MODE_ASYNC_PUSH) ? SPA_GRAPH_NODE_FLAG_ASYNC : 0;
spa_graph_port_add (&data->graph, &data->source_node,
&data->source_out, SPA_DIRECTION_OUTPUT, 0,
0, &data->source_sink_io[0]);
spa_graph_node_add(&data->graph, &data->source_node,
spa_graph_node_schedule_default, data->source);
data->source_node.flags = (data->mode & MODE_ASYNC_PUSH) ? SPA_GRAPH_NODE_FLAG_ASYNC : 0;
spa_graph_port_add(&data->graph, &data->source_node,
&data->source_out, SPA_DIRECTION_OUTPUT, 0, 0, &data->source_sink_io[0]);
spa_graph_node_add (&data->graph, &data->sink_node, spa_graph_node_schedule_default, data->sink);
data->sink_node.flags = (data->mode & MODE_ASYNC_PULL) ? SPA_GRAPH_NODE_FLAG_ASYNC : 0;
spa_graph_port_add (&data->graph, &data->sink_node,
&data->sink_in, SPA_DIRECTION_INPUT, 0,
0, &data->source_sink_io[0]);
spa_graph_node_add(&data->graph, &data->sink_node, spa_graph_node_schedule_default,
data->sink);
data->sink_node.flags = (data->mode & MODE_ASYNC_PULL) ? SPA_GRAPH_NODE_FLAG_ASYNC : 0;
spa_graph_port_add(&data->graph, &data->sink_node,
&data->sink_in, SPA_DIRECTION_INPUT, 0, 0, &data->source_sink_io[0]);
spa_graph_port_link (&data->graph, &data->source_out, &data->sink_in);
spa_graph_port_link(&data->graph, &data->source_out, &data->sink_in);
return res;
return res;
}
static int
negotiate_formats (struct data *data)
static int negotiate_formats(struct data *data)
{
int res;
struct spa_format *format;
struct spa_pod_builder b = { 0 };
struct spa_pod_frame f[2];
uint8_t buffer[256];
int res;
struct spa_format *format;
struct spa_pod_builder b = { 0 };
struct spa_pod_frame f[2];
uint8_t buffer[256];
spa_pod_builder_init (&b, buffer, sizeof (buffer));
spa_pod_builder_format (&b, &f[0], data->type.format,
data->type.media_type.binary, data->type.media_subtype.raw, 0);
format = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_format);
spa_pod_builder_init(&b, buffer, sizeof(buffer));
spa_pod_builder_format(&b, &f[0], data->type.format,
data->type.media_type.binary, data->type.media_subtype.raw, 0);
format = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_format);
if ((res = spa_node_port_set_format (data->sink, SPA_DIRECTION_INPUT, 0, 0, format)) < 0)
return res;
if ((res = spa_node_port_set_format(data->sink, SPA_DIRECTION_INPUT, 0, 0, format)) < 0)
return res;
if ((res = spa_node_port_set_format (data->source, SPA_DIRECTION_OUTPUT, 0, 0, format)) < 0)
return res;
if ((res = spa_node_port_set_format(data->source, SPA_DIRECTION_OUTPUT, 0, 0, format)) < 0)
return res;
init_buffer (data, data->source_buffers, data->source_buffer, 1, BUFFER_SIZE);
init_buffer(data, data->source_buffers, data->source_buffer, 1, BUFFER_SIZE);
if ((res = spa_node_port_use_buffers (data->sink, SPA_DIRECTION_INPUT, 0, data->source_buffers, 1)) < 0)
return res;
if ((res = spa_node_port_use_buffers (data->source, SPA_DIRECTION_OUTPUT, 0, data->source_buffers, 1)) < 0)
return res;
if ((res =
spa_node_port_use_buffers(data->sink, SPA_DIRECTION_INPUT, 0, data->source_buffers,
1)) < 0)
return res;
if ((res =
spa_node_port_use_buffers(data->source, SPA_DIRECTION_OUTPUT, 0, data->source_buffers,
1)) < 0)
return res;
return SPA_RESULT_OK;
return SPA_RESULT_OK;
}
static void *
loop (void *user_data)
static void *loop(void *user_data)
{
struct data *data = user_data;
struct data *data = user_data;
printf ("enter thread %d\n", data->n_sources);
while (data->running) {
int i, r;
printf("enter thread %d\n", data->n_sources);
while (data->running) {
int i, r;
/* rebuild */
if (data->rebuild_fds) {
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
data->fds[i].fd = p->fd;
data->fds[i].events = p->mask;
}
data->n_fds = data->n_sources;
data->rebuild_fds = false;
}
/* rebuild */
if (data->rebuild_fds) {
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
data->fds[i].fd = p->fd;
data->fds[i].events = p->mask;
}
data->n_fds = data->n_sources;
data->rebuild_fds = false;
}
r = poll (data->fds, data->n_fds, -1);
if (r < 0) {
if (errno == EINTR)
continue;
break;
}
if (r == 0) {
fprintf (stderr, "select timeout");
break;
}
r = poll(data->fds, data->n_fds, -1);
if (r < 0) {
if (errno == EINTR)
continue;
break;
}
if (r == 0) {
fprintf(stderr, "select timeout");
break;
}
/* after */
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
p->rmask = 0;
if (data->fds[i].revents & POLLIN)
p->rmask |= SPA_IO_IN;
if (data->fds[i].revents & POLLOUT)
p->rmask |= SPA_IO_OUT;
if (data->fds[i].revents & POLLHUP)
p->rmask |= SPA_IO_HUP;
if (data->fds[i].revents & POLLERR)
p->rmask |= SPA_IO_ERR;
}
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
if (p->rmask)
p->func (p);
}
}
printf ("leave thread\n");
/* after */
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
p->rmask = 0;
if (data->fds[i].revents & POLLIN)
p->rmask |= SPA_IO_IN;
if (data->fds[i].revents & POLLOUT)
p->rmask |= SPA_IO_OUT;
if (data->fds[i].revents & POLLHUP)
p->rmask |= SPA_IO_HUP;
if (data->fds[i].revents & POLLERR)
p->rmask |= SPA_IO_ERR;
}
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
if (p->rmask)
p->func(p);
}
}
printf("leave thread\n");
return NULL;
return NULL;
}
static void
run_graph (struct data *data)
static void run_graph(struct data *data)
{
int res;
int err, i;
struct timespec now;
int64_t start, stop;
int res;
int err, i;
struct timespec now;
int64_t start, stop;
{
struct spa_command cmd = SPA_COMMAND_INIT (data->type.command_node.Start);
if ((res = spa_node_send_command (data->source, &cmd)) < 0)
printf ("got source error %d\n", res);
if ((res = spa_node_send_command (data->sink, &cmd)) < 0)
printf ("got sink error %d\n", res);
}
{
struct spa_command cmd = SPA_COMMAND_INIT(data->type.command_node.Start);
if ((res = spa_node_send_command(data->source, &cmd)) < 0)
printf("got source error %d\n", res);
if ((res = spa_node_send_command(data->sink, &cmd)) < 0)
printf("got sink error %d\n", res);
}
clock_gettime (CLOCK_MONOTONIC, &now);
start = SPA_TIMESPEC_TO_TIME (&now);
clock_gettime(CLOCK_MONOTONIC, &now);
start = SPA_TIMESPEC_TO_TIME(&now);
printf ("running\n");
printf("running\n");
if (data->mode & MODE_SYNC_PUSH) {
for (i = 0; i < data->iterations; i++)
on_source_push (data);
}
else if (data->mode & MODE_SYNC_PULL) {
for (i = 0; i < data->iterations; i++)
on_sink_pull (data);
}
else {
data->running = true;
if ((err = pthread_create (&data->thread, NULL, loop, data)) != 0) {
printf ("can't create thread: %d %s", err, strerror (err));
data->running = false;
}
if (data->running) {
pthread_join (data->thread, NULL);
}
}
if (data->mode & MODE_SYNC_PUSH) {
for (i = 0; i < data->iterations; i++)
on_source_push(data);
} else if (data->mode & MODE_SYNC_PULL) {
for (i = 0; i < data->iterations; i++)
on_sink_pull(data);
} else {
data->running = true;
if ((err = pthread_create(&data->thread, NULL, loop, data)) != 0) {
printf("can't create thread: %d %s", err, strerror(err));
data->running = false;
}
if (data->running) {
pthread_join(data->thread, NULL);
}
}
clock_gettime (CLOCK_MONOTONIC, &now);
stop = SPA_TIMESPEC_TO_TIME (&now);
clock_gettime(CLOCK_MONOTONIC, &now);
stop = SPA_TIMESPEC_TO_TIME(&now);
printf ("stopping, elapsed %"PRIi64"\n", stop - start);
printf("stopping, elapsed %" PRIi64 "\n", stop - start);
{
struct spa_command cmd = SPA_COMMAND_INIT (data->type.command_node.Pause);
if ((res = spa_node_send_command (data->sink, &cmd)) < 0)
printf ("got error %d\n", res);
if ((res = spa_node_send_command (data->source, &cmd)) < 0)
printf ("got source error %d\n", res);
}
{
struct spa_command cmd = SPA_COMMAND_INIT(data->type.command_node.Pause);
if ((res = spa_node_send_command(data->sink, &cmd)) < 0)
printf("got error %d\n", res);
if ((res = spa_node_send_command(data->source, &cmd)) < 0)
printf("got source error %d\n", res);
}
}
int
main (int argc, char *argv[])
int main(int argc, char *argv[])
{
struct data data = { NULL };
int res;
const char *str;
struct data data = { NULL };
int res;
const char *str;
spa_graph_init (&data.graph);
spa_graph_init(&data.graph);
data.map = spa_type_map_get_default();
data.log = spa_log_get_default();
data.data_loop.size = sizeof (struct spa_loop);
data.data_loop.add_source = do_add_source;
data.data_loop.update_source = do_update_source;
data.data_loop.remove_source = do_remove_source;
data.data_loop.invoke = do_invoke;
data.map = spa_type_map_get_default();
data.log = spa_log_get_default();
data.data_loop.size = sizeof(struct spa_loop);
data.data_loop.add_source = do_add_source;
data.data_loop.update_source = do_update_source;
data.data_loop.remove_source = do_remove_source;
data.data_loop.invoke = do_invoke;
if ((str = getenv ("SPA_DEBUG")))
data.log->level = atoi (str);
if ((str = getenv("SPA_DEBUG")))
data.log->level = atoi(str);
data.mode = argc > 1 ? atoi (argv[1]) : MODE_SYNC_PUSH;
data.iterations = argc > 2 ? atoi (argv[2]) : 100000;
data.mode = argc > 1 ? atoi(argv[1]) : MODE_SYNC_PUSH;
data.iterations = argc > 2 ? atoi(argv[2]) : 100000;
printf ("mode %08x\n", data.mode);
printf("mode %08x\n", data.mode);
data.support[0].type = SPA_TYPE__TypeMap;
data.support[0].data = data.map;
data.support[1].type = SPA_TYPE__Log;
data.support[1].data = data.log;
data.support[2].type = SPA_TYPE_LOOP__DataLoop;
data.support[2].data = &data.data_loop;
data.support[3].type = SPA_TYPE_LOOP__MainLoop;
data.support[3].data = &data.data_loop;
data.n_support = 4;
data.support[0].type = SPA_TYPE__TypeMap;
data.support[0].data = data.map;
data.support[1].type = SPA_TYPE__Log;
data.support[1].data = data.log;
data.support[2].type = SPA_TYPE_LOOP__DataLoop;
data.support[2].data = &data.data_loop;
data.support[3].type = SPA_TYPE_LOOP__MainLoop;
data.support[3].data = &data.data_loop;
data.n_support = 4;
init_type (&data.type, data.map);
init_type(&data.type, data.map);
if ((res = make_nodes (&data)) < 0) {
printf ("can't make nodes: %d\n", res);
return -1;
}
if ((res = negotiate_formats (&data)) < 0) {
printf ("can't negotiate nodes: %d\n", res);
return -1;
}
if ((res = make_nodes(&data)) < 0) {
printf("can't make nodes: %d\n", res);
return -1;
}
if ((res = negotiate_formats(&data)) < 0) {
printf("can't negotiate nodes: %d\n", res);
return -1;
}
run_graph (&data);
run_graph(&data);
}

View file

@ -39,242 +39,241 @@
* framerate: (frac (25 1)) { (0 1) (MAX 1) },
*/
spa_build (SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_RAW,
type.format_video.format, SPA_PROP_TYPE_ID,
video_format.I420
SPA_POD_PROP_FLAG_UNSET |
SPA_PROP_RANGE_ENUM, 2,
video_format.I420,
video_format.YUY2,
type.format_video.size , SPA_PROP_TYPE_RECTANGLE,
320, 240,
SPA_POD_PROP_FLAG_UNSET |
SPA_PROP_RANGE_MIN_MAX,
1, 1,
INT32_MAX, INT32_MAX,
type.format_video.framerate, SPA_PROP_TYPE_FRACTION, 25, 1,
SPA_POD_PROP_FLAG_UNSET |
SPA_PROP_RANGE_MIN_MAX,
0, 1,
INT32_MAX, 1,
0);
spa_build(SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_RAW,
type.format_video.format, SPA_PROP_TYPE_ID,
video_format.I420
SPA_POD_PROP_FLAG_UNSET |
SPA_PROP_RANGE_ENUM, 2,
video_format.I420,
video_format.YUY2,
type.format_video.size, SPA_PROP_TYPE_RECTANGLE,
320, 240,
SPA_POD_PROP_FLAG_UNSET |
SPA_PROP_RANGE_MIN_MAX,
1, 1,
INT32_MAX, INT32_MAX,
type.format_video.framerate, SPA_PROP_TYPE_FRACTION, 25, 1,
SPA_POD_PROP_FLAG_UNSET | SPA_PROP_RANGE_MIN_MAX, 0, 1, INT32_MAX, 1, 0);
#endif
static struct {
uint32_t format;
struct spa_type_media_type media_type;
struct spa_type_media_subtype media_subtype;
struct spa_type_format_video format_video;
struct spa_type_video_format video_format;
} type = { 0, };
uint32_t format;
struct spa_type_media_type media_type;
struct spa_type_media_subtype media_subtype;
struct spa_type_format_video format_video;
struct spa_type_video_format video_format;
} type = { 0,};
static inline void
type_init (struct spa_type_map *map)
static inline void type_init(struct spa_type_map *map)
{
type.format = spa_type_map_get_id (map, SPA_TYPE__Format);
spa_type_media_type_map (map, &type.media_type);
spa_type_media_subtype_map (map, &type.media_subtype);
spa_type_format_video_map (map, &type.format_video);
spa_type_video_format_map (map, &type.video_format);
type.format = spa_type_map_get_id(map, SPA_TYPE__Format);
spa_type_media_type_map(map, &type.media_type);
spa_type_media_subtype_map(map, &type.media_subtype);
spa_type_format_video_map(map, &type.format_video);
spa_type_video_format_map(map, &type.video_format);
}
static void
do_static_struct (struct spa_type_map *map)
static void do_static_struct(struct spa_type_map *map)
{
struct _test_format {
struct spa_format fmt;
struct _test_format {
struct spa_format fmt;
struct {
struct spa_pod_prop prop_format;
struct {
uint32_t def_format;
uint32_t enum_format[2];
} format_vals;
uint32_t pad;
struct {
struct spa_pod_prop prop_format;
struct {
uint32_t def_format;
uint32_t enum_format[2];
} format_vals;
uint32_t pad;
struct spa_pod_prop prop_size;
struct {
struct spa_rectangle def_size;
struct spa_rectangle min_size;
struct spa_rectangle max_size;
} size_vals;
struct spa_pod_prop prop_size;
struct {
struct spa_rectangle def_size;
struct spa_rectangle min_size;
struct spa_rectangle max_size;
} size_vals;
struct spa_pod_prop prop_framerate;
struct {
struct spa_fraction def_framerate;
struct spa_fraction min_framerate;
struct spa_fraction max_framerate;
} framerate_vals;
} props;
} test_format = {
{ { sizeof (test_format.props) + sizeof (struct spa_format), SPA_POD_TYPE_OBJECT },
{ { 0, type.format },
{ { sizeof (uint32_t), SPA_POD_TYPE_ID }, type.media_type.video },
{ { sizeof (uint32_t), SPA_POD_TYPE_ID }, type.media_subtype.raw } },
}, {
{ { sizeof (test_format.props.format_vals) + sizeof (struct spa_pod_prop_body),
SPA_POD_TYPE_PROP } ,
{ type.format_video.format, SPA_POD_PROP_RANGE_ENUM | SPA_POD_PROP_FLAG_UNSET,
{ sizeof (uint32_t), SPA_POD_TYPE_ID } }, },
{ type.video_format.I420,
{ type.video_format.I420, type.video_format.YUY2 } }, 0,
struct spa_pod_prop prop_framerate;
struct {
struct spa_fraction def_framerate;
struct spa_fraction min_framerate;
struct spa_fraction max_framerate;
} framerate_vals;
} props;
} test_format = {
{ {
sizeof(test_format.props) + sizeof(struct spa_format), SPA_POD_TYPE_OBJECT},
{ {
0, type.format}, { {
sizeof(uint32_t), SPA_POD_TYPE_ID}
, type.media_type.video}
, { {
sizeof(uint32_t), SPA_POD_TYPE_ID}
, type.media_subtype.raw}
}
,}
, {
{ {
sizeof(test_format.props.format_vals) +
sizeof(struct spa_pod_prop_body), SPA_POD_TYPE_PROP}, {
type.format_video.format,
SPA_POD_PROP_RANGE_ENUM | SPA_POD_PROP_FLAG_UNSET, {
sizeof(uint32_t), SPA_POD_TYPE_ID}
}
,}
, {
type.video_format.I420, {
type.video_format.I420, type.video_format.YUY2}
}
, 0, { {
sizeof(test_format.props.size_vals) +
sizeof(struct spa_pod_prop_body), SPA_POD_TYPE_PROP}, {
type.format_video.size,
SPA_POD_PROP_RANGE_MIN_MAX | SPA_POD_PROP_FLAG_UNSET, {
sizeof(struct spa_rectangle), SPA_POD_TYPE_RECTANGLE}},}, { {
320, 243}, {
1, 1}, {
INT32_MAX, INT32_MAX}}, { {
sizeof(test_format.props.framerate_vals) +
sizeof(struct spa_pod_prop_body), SPA_POD_TYPE_PROP}, {
type.format_video.framerate,
SPA_POD_PROP_RANGE_MIN_MAX | SPA_POD_PROP_FLAG_UNSET, {
sizeof(struct spa_fraction), SPA_POD_TYPE_FRACTION}},}, { {
25, 1}, {
0, 1}, {
INT32_MAX, 1}},}
};
{ { sizeof (test_format.props.size_vals) + sizeof (struct spa_pod_prop_body),
SPA_POD_TYPE_PROP } ,
{ type.format_video.size, SPA_POD_PROP_RANGE_MIN_MAX | SPA_POD_PROP_FLAG_UNSET,
{ sizeof (struct spa_rectangle), SPA_POD_TYPE_RECTANGLE } }, },
{ { 320, 243 },
{ 1, 1 },
{ INT32_MAX, INT32_MAX } },
spa_debug_pod(&test_format.fmt.pod, map);
spa_debug_format(&test_format.fmt, map);
{ { sizeof (test_format.props.framerate_vals) + sizeof (struct spa_pod_prop_body),
SPA_POD_TYPE_PROP } ,
{ type.format_video.framerate, SPA_POD_PROP_RANGE_MIN_MAX | SPA_POD_PROP_FLAG_UNSET,
{ sizeof (struct spa_fraction), SPA_POD_TYPE_FRACTION } }, },
{ { 25, 1 },
{ 0, 1 },
{ INT32_MAX, 1 } },
}
};
{
uint32_t format = 0, match;
struct spa_fraction frac = { 0, 0 };
spa_debug_pod (&test_format.fmt.pod, map);
spa_debug_format (&test_format.fmt, map);
match = spa_pod_contents_query(&test_format.fmt.pod, sizeof(struct spa_format),
type.format_video.format, SPA_POD_TYPE_INT, &format,
type.format_video.framerate, SPA_POD_TYPE_FRACTION,
&frac, 0);
{
uint32_t format = 0, match;
struct spa_fraction frac = { 0, 0 };
match = spa_pod_contents_query (&test_format.fmt.pod, sizeof (struct spa_format),
type.format_video.format, SPA_POD_TYPE_INT, &format,
type.format_video.framerate, SPA_POD_TYPE_FRACTION, &frac,
0);
printf ("%d %d %d %d\n", match, format, frac.num, frac.denom);
}
printf("%d %d %d %d\n", match, format, frac.num, frac.denom);
}
}
int
main (int argc, char *argv[])
int main(int argc, char *argv[])
{
struct spa_pod_builder b = { NULL, };
struct spa_pod_frame frame[4];
uint8_t buffer[1024];
struct spa_format *fmt;
struct spa_type_map *map = spa_type_map_get_default();
struct spa_pod_builder b = { NULL, };
struct spa_pod_frame frame[4];
uint8_t buffer[1024];
struct spa_format *fmt;
struct spa_type_map *map = spa_type_map_get_default();
type_init (map);
type_init(map);
spa_pod_builder_init (&b, buffer, sizeof (buffer));
spa_pod_builder_init(&b, buffer, sizeof(buffer));
fmt = SPA_MEMBER (buffer, spa_pod_builder_push_format (&b, &frame[0], type.format,
type.media_type.video,
type.media_subtype.raw), struct spa_format);
spa_pod_builder_push_prop (&b, &frame[1],
type.format_video.format,
SPA_POD_PROP_RANGE_ENUM | SPA_POD_PROP_FLAG_UNSET);
spa_pod_builder_id (&b, type.video_format.I420);
spa_pod_builder_id (&b, type.video_format.I420);
spa_pod_builder_id (&b, type.video_format.YUY2);
spa_pod_builder_pop (&b, &frame[1]);
fmt = SPA_MEMBER(buffer, spa_pod_builder_push_format(&b, &frame[0], type.format,
type.media_type.video,
type.media_subtype.raw),
struct spa_format);
spa_pod_builder_push_prop(&b, &frame[1], type.format_video.format,
SPA_POD_PROP_RANGE_ENUM | SPA_POD_PROP_FLAG_UNSET);
spa_pod_builder_id(&b, type.video_format.I420);
spa_pod_builder_id(&b, type.video_format.I420);
spa_pod_builder_id(&b, type.video_format.YUY2);
spa_pod_builder_pop(&b, &frame[1]);
struct spa_rectangle size_min_max[] = { { 1, 1 }, { INT32_MAX, INT32_MAX } };
spa_pod_builder_push_prop (&b, &frame[1],
type.format_video.size,
SPA_POD_PROP_RANGE_MIN_MAX | SPA_POD_PROP_FLAG_UNSET);
spa_pod_builder_rectangle (&b, 320, 240);
spa_pod_builder_raw (&b, size_min_max, sizeof(size_min_max));
spa_pod_builder_pop (&b, &frame[1]);
struct spa_rectangle size_min_max[] = { {1, 1}, {INT32_MAX, INT32_MAX} };
spa_pod_builder_push_prop(&b, &frame[1],
type.format_video.size,
SPA_POD_PROP_RANGE_MIN_MAX | SPA_POD_PROP_FLAG_UNSET);
spa_pod_builder_rectangle(&b, 320, 240);
spa_pod_builder_raw(&b, size_min_max, sizeof(size_min_max));
spa_pod_builder_pop(&b, &frame[1]);
struct spa_fraction rate_min_max[] = { { 0, 1 }, { INT32_MAX, 1 } };
spa_pod_builder_push_prop (&b, &frame[1],
type.format_video.framerate,
SPA_POD_PROP_RANGE_MIN_MAX | SPA_POD_PROP_FLAG_UNSET);
spa_pod_builder_fraction (&b, 25, 1);
spa_pod_builder_raw (&b, rate_min_max, sizeof(rate_min_max));
spa_pod_builder_pop (&b, &frame[1]);
struct spa_fraction rate_min_max[] = { {0, 1}, {INT32_MAX, 1} };
spa_pod_builder_push_prop(&b, &frame[1],
type.format_video.framerate,
SPA_POD_PROP_RANGE_MIN_MAX | SPA_POD_PROP_FLAG_UNSET);
spa_pod_builder_fraction(&b, 25, 1);
spa_pod_builder_raw(&b, rate_min_max, sizeof(rate_min_max));
spa_pod_builder_pop(&b, &frame[1]);
spa_pod_builder_pop (&b, &frame[0]);
spa_pod_builder_pop(&b, &frame[0]);
spa_debug_pod (&fmt->pod, map);
spa_debug_pod(&fmt->pod, map);
spa_pod_builder_init (&b, buffer, sizeof (buffer));
spa_pod_builder_init(&b, buffer, sizeof(buffer));
spa_pod_builder_format (&b, &frame[0], type.format,
type.media_type.video, type.media_subtype.raw,
SPA_POD_TYPE_PROP, &frame[1],
type.format_video.format, SPA_POD_PROP_FLAG_UNSET |
SPA_POD_PROP_RANGE_ENUM,
SPA_POD_TYPE_ID, 3,
type.video_format.I420,
type.video_format.I420,
type.video_format.YUY2,
-SPA_POD_TYPE_PROP, &frame[1],
SPA_POD_TYPE_PROP, &frame[1],
type.format_video.size, SPA_POD_PROP_FLAG_UNSET |
SPA_POD_PROP_RANGE_MIN_MAX,
SPA_POD_TYPE_RECTANGLE, 3,
320, 241,
1, 1,
INT32_MAX, INT32_MAX,
-SPA_POD_TYPE_PROP, &frame[1],
SPA_POD_TYPE_PROP, &frame[1],
type.format_video.framerate, SPA_POD_PROP_FLAG_UNSET |
SPA_POD_PROP_RANGE_MIN_MAX,
SPA_POD_TYPE_FRACTION, 3,
25, 1,
0, 1,
INT32_MAX, 1,
-SPA_POD_TYPE_PROP, &frame[1]);
spa_pod_builder_format(&b, &frame[0], type.format,
type.media_type.video,
type.media_subtype.raw,
SPA_POD_TYPE_PROP, &frame[1], type.format_video.format,
SPA_POD_PROP_FLAG_UNSET | SPA_POD_PROP_RANGE_ENUM, SPA_POD_TYPE_ID, 3,
type.video_format.I420,
type.video_format.I420,
type.video_format.YUY2,
-SPA_POD_TYPE_PROP, &frame[1],
SPA_POD_TYPE_PROP, &frame[1], type.format_video.size,
SPA_POD_PROP_FLAG_UNSET | SPA_POD_PROP_RANGE_MIN_MAX, SPA_POD_TYPE_RECTANGLE, 3,
320, 241,
1, 1,
INT32_MAX, INT32_MAX,
-SPA_POD_TYPE_PROP, &frame[1],
SPA_POD_TYPE_PROP, &frame[1], type.format_video.framerate,
SPA_POD_PROP_FLAG_UNSET | SPA_POD_PROP_RANGE_MIN_MAX, SPA_POD_TYPE_FRACTION, 3,
25, 1,
0, 1,
INT32_MAX, 1,
-SPA_POD_TYPE_PROP, &frame[1]);
fmt = SPA_MEMBER (buffer, frame[0].ref, struct spa_format);
spa_debug_pod (&fmt->pod, map);
spa_debug_format (fmt, map);
fmt = SPA_MEMBER(buffer, frame[0].ref, struct spa_format);
spa_debug_pod(&fmt->pod, map);
spa_debug_format(fmt, map);
spa_pod_builder_init (&b, buffer, sizeof (buffer));
spa_pod_builder_init(&b, buffer, sizeof(buffer));
spa_pod_builder_add (&b,
SPA_POD_TYPE_OBJECT, &frame[0], 0, type.format,
SPA_POD_TYPE_ID, type.media_type.video,
SPA_POD_TYPE_ID, type.media_subtype.raw,
SPA_POD_TYPE_PROP, &frame[1],
type.format_video.format, SPA_POD_PROP_FLAG_UNSET |
SPA_POD_PROP_RANGE_ENUM,
SPA_POD_TYPE_ID, 3,
type.video_format.I420,
type.video_format.I420,
type.video_format.YUY2,
-SPA_POD_TYPE_PROP, &frame[1],
SPA_POD_TYPE_PROP, &frame[1],
type.format_video.size, SPA_POD_PROP_FLAG_UNSET |
SPA_POD_PROP_RANGE_MIN_MAX,
SPA_POD_TYPE_RECTANGLE, 3,
320, 242,
1, 1,
INT32_MAX, INT32_MAX,
-SPA_POD_TYPE_PROP, &frame[1],
SPA_POD_TYPE_PROP, &frame[1],
type.format_video.framerate, SPA_POD_PROP_FLAG_UNSET |
SPA_POD_PROP_RANGE_MIN_MAX,
SPA_POD_TYPE_FRACTION, 3,
25, 1,
0, 1,
INT32_MAX, 1,
-SPA_POD_TYPE_PROP, &frame[1],
-SPA_POD_TYPE_OBJECT, &frame[0],
0);
spa_pod_builder_add(&b,
SPA_POD_TYPE_OBJECT, &frame[0], 0, type.format,
SPA_POD_TYPE_ID, type.media_type.video,
SPA_POD_TYPE_ID, type.media_subtype.raw,
SPA_POD_TYPE_PROP, &frame[1],
type.format_video.format,
SPA_POD_PROP_FLAG_UNSET | SPA_POD_PROP_RANGE_ENUM, SPA_POD_TYPE_ID, 3,
type.video_format.I420,
type.video_format.I420,
type.video_format.YUY2,
-SPA_POD_TYPE_PROP, &frame[1],
SPA_POD_TYPE_PROP, &frame[1],
type.format_video.size,
SPA_POD_PROP_FLAG_UNSET | SPA_POD_PROP_RANGE_MIN_MAX, SPA_POD_TYPE_RECTANGLE, 3,
320, 242,
1, 1,
INT32_MAX, INT32_MAX,
-SPA_POD_TYPE_PROP, &frame[1],
SPA_POD_TYPE_PROP, &frame[1],
type.format_video.framerate,
SPA_POD_PROP_FLAG_UNSET | SPA_POD_PROP_RANGE_MIN_MAX, SPA_POD_TYPE_FRACTION, 3,
25, 1,
0, 1,
INT32_MAX, 1,
-SPA_POD_TYPE_PROP, &frame[1],
-SPA_POD_TYPE_OBJECT, &frame[0],
0);
fmt = SPA_MEMBER (buffer, frame[0].ref, struct spa_format);
spa_debug_pod (&fmt->pod, map);
spa_debug_format (fmt, map);
fmt = SPA_MEMBER(buffer, frame[0].ref, struct spa_format);
spa_debug_pod(&fmt->pod, map);
spa_debug_format(fmt, map);
do_static_struct (map);
do_static_struct(map);
printf ("media type is enum %d\n", spa_type_is_a (SPA_TYPE__MediaType, SPA_TYPE_ENUM_BASE));
printf ("media sybtype is enum %d\n", spa_type_is_a (SPA_TYPE__MediaSubtype, SPA_TYPE_ENUM_BASE));
printf ("format is enum %d\n", spa_type_is_a (SPA_TYPE__Format, SPA_TYPE_ENUM_BASE));
printf ("format is pod %d\n", spa_type_is_a (SPA_TYPE__Format, SPA_TYPE_POD_BASE));
printf ("format is object %d\n", spa_type_is_a (SPA_TYPE__Format, SPA_TYPE_POD_OBJECT_BASE));
printf("media type is enum %d\n", spa_type_is_a(SPA_TYPE__MediaType, SPA_TYPE_ENUM_BASE));
printf("media sybtype is enum %d\n",
spa_type_is_a(SPA_TYPE__MediaSubtype, SPA_TYPE_ENUM_BASE));
printf("format is enum %d\n", spa_type_is_a(SPA_TYPE__Format, SPA_TYPE_ENUM_BASE));
printf("format is pod %d\n", spa_type_is_a(SPA_TYPE__Format, SPA_TYPE_POD_BASE));
printf("format is object %d\n", spa_type_is_a(SPA_TYPE__Format, SPA_TYPE_POD_OBJECT_BASE));
return 0;
return 0;
}

View file

@ -34,92 +34,89 @@
#include <lib/debug.h>
#include <lib/mapper.h>
int
main (int argc, char *argv[])
int main(int argc, char *argv[])
{
struct spa_pod_builder b = { NULL, };
struct spa_pod_frame frame[4];
uint8_t buffer[1024];
struct spa_pod *obj;
struct spa_pod_iter i;
struct spa_type_map *map = spa_type_map_get_default ();
struct spa_pod_builder b = { NULL, };
struct spa_pod_frame frame[4];
uint8_t buffer[1024];
struct spa_pod *obj;
struct spa_pod_iter i;
struct spa_type_map *map = spa_type_map_get_default();
b.data = buffer;
b.size = 1024;
b.data = buffer;
b.size = 1024;
spa_pod_builder_push_object (&b, &frame[0], 0, 0);
spa_pod_builder_push_object(&b, &frame[0], 0, 0);
uint32_t formats[] = { 1, 2 };
spa_pod_builder_push_prop (&b, &frame[1],
1, SPA_POD_PROP_RANGE_ENUM);
spa_pod_builder_int (&b, 1);
spa_pod_builder_int (&b, formats[0]);
spa_pod_builder_int (&b, formats[1]);
spa_pod_builder_pop (&b, &frame[1]);
uint32_t formats[] = { 1, 2 };
spa_pod_builder_push_prop(&b, &frame[1], 1, SPA_POD_PROP_RANGE_ENUM);
spa_pod_builder_int(&b, 1);
spa_pod_builder_int(&b, formats[0]);
spa_pod_builder_int(&b, formats[1]);
spa_pod_builder_pop(&b, &frame[1]);
spa_pod_builder_push_prop (&b, &frame[1], 2, 0);
spa_pod_builder_int (&b, 42);
spa_pod_builder_pop (&b, &frame[1]);
spa_pod_builder_push_prop(&b, &frame[1], 2, 0);
spa_pod_builder_int(&b, 42);
spa_pod_builder_pop(&b, &frame[1]);
struct spa_rectangle sizes[] = { { 0, 0 }, { 1024, 1024} };
spa_pod_builder_push_prop (&b, &frame[1],
3, SPA_POD_PROP_RANGE_MIN_MAX | SPA_POD_PROP_FLAG_UNSET);
spa_pod_builder_rectangle (&b, 320, 240);
spa_pod_builder_raw (&b, sizes, sizeof (sizes));
spa_pod_builder_pop (&b, &frame[1]);
struct spa_rectangle sizes[] = { {0, 0}, {1024, 1024} };
spa_pod_builder_push_prop(&b, &frame[1],
3, SPA_POD_PROP_RANGE_MIN_MAX | SPA_POD_PROP_FLAG_UNSET);
spa_pod_builder_rectangle(&b, 320, 240);
spa_pod_builder_raw(&b, sizes, sizeof(sizes));
spa_pod_builder_pop(&b, &frame[1]);
spa_pod_builder_push_prop (&b, &frame[1], 4, SPA_POD_PROP_FLAG_READONLY);
spa_pod_builder_push_struct (&b, &frame[2]);
spa_pod_builder_int (&b, 4);
spa_pod_builder_long (&b, 6000);
spa_pod_builder_float (&b, 4.0);
spa_pod_builder_double (&b, 3.14);
spa_pod_builder_string (&b, "test123");
spa_pod_builder_rectangle (&b, 320, 240);
spa_pod_builder_fraction (&b, 25, 1);
spa_pod_builder_push_array (&b, &frame[3]);
spa_pod_builder_int (&b, 4);
spa_pod_builder_int (&b, 5);
spa_pod_builder_int (&b, 6);
spa_pod_builder_pop (&b, &frame[3]);
spa_pod_builder_pop (&b, &frame[2]);
spa_pod_builder_pop (&b, &frame[1]);
spa_pod_builder_pop (&b, &frame[0]);
spa_pod_builder_push_prop(&b, &frame[1], 4, SPA_POD_PROP_FLAG_READONLY);
spa_pod_builder_push_struct(&b, &frame[2]);
spa_pod_builder_int(&b, 4);
spa_pod_builder_long(&b, 6000);
spa_pod_builder_float(&b, 4.0);
spa_pod_builder_double(&b, 3.14);
spa_pod_builder_string(&b, "test123");
spa_pod_builder_rectangle(&b, 320, 240);
spa_pod_builder_fraction(&b, 25, 1);
spa_pod_builder_push_array(&b, &frame[3]);
spa_pod_builder_int(&b, 4);
spa_pod_builder_int(&b, 5);
spa_pod_builder_int(&b, 6);
spa_pod_builder_pop(&b, &frame[3]);
spa_pod_builder_pop(&b, &frame[2]);
spa_pod_builder_pop(&b, &frame[1]);
spa_pod_builder_pop(&b, &frame[0]);
obj = SPA_POD_BUILDER_DEREF (&b, frame[0].ref, struct spa_pod);
spa_debug_pod (obj, map);
obj = SPA_POD_BUILDER_DEREF(&b, frame[0].ref, struct spa_pod);
spa_debug_pod(obj, map);
struct spa_pod_prop *p = spa_pod_object_find_prop ((struct spa_pod_object *)obj, 4);
printf ("%d %d\n", p->body.key, p->body.flags);
spa_debug_pod (&p->body.value, map);
struct spa_pod_prop *p = spa_pod_object_find_prop((struct spa_pod_object *) obj, 4);
printf("%d %d\n", p->body.key, p->body.flags);
spa_debug_pod(&p->body.value, map);
obj = SPA_POD_BUILDER_DEREF (&b, frame[2].ref, struct spa_pod);
obj = SPA_POD_BUILDER_DEREF(&b, frame[2].ref, struct spa_pod);
int32_t vi, *pi;
int64_t vl;
float vf;
double vd;
char *vs;
struct spa_rectangle vr;
struct spa_fraction vfr;
struct spa_pod_array *va;
spa_pod_iter_pod (&i, obj);
spa_pod_iter_get (&i, SPA_POD_TYPE_INT, &vi,
SPA_POD_TYPE_LONG, &vl,
SPA_POD_TYPE_FLOAT, &vf,
SPA_POD_TYPE_DOUBLE, &vd,
SPA_POD_TYPE_STRING, &vs,
SPA_POD_TYPE_RECTANGLE, &vr,
SPA_POD_TYPE_FRACTION, &vfr,
SPA_POD_TYPE_ARRAY, &va,
0);
int32_t vi, *pi;
int64_t vl;
float vf;
double vd;
char *vs;
struct spa_rectangle vr;
struct spa_fraction vfr;
struct spa_pod_array *va;
spa_pod_iter_pod(&i, obj);
spa_pod_iter_get(&i, SPA_POD_TYPE_INT, &vi,
SPA_POD_TYPE_LONG, &vl,
SPA_POD_TYPE_FLOAT, &vf,
SPA_POD_TYPE_DOUBLE, &vd,
SPA_POD_TYPE_STRING, &vs,
SPA_POD_TYPE_RECTANGLE, &vr,
SPA_POD_TYPE_FRACTION, &vfr, SPA_POD_TYPE_ARRAY, &va, 0);
printf ("%u %lu %f %g %s %ux%u %u/%u\n", vi, vl, vf, vd, vs, vr.width, vr.height, vfr.num, vfr.denom);
SPA_POD_ARRAY_BODY_FOREACH (&va->body, SPA_POD_BODY_SIZE (va), pi) {
printf ("%d\n", *pi);
}
printf("%u %lu %f %g %s %ux%u %u/%u\n", vi, vl, vf, vd, vs, vr.width, vr.height, vfr.num,
vfr.denom);
SPA_POD_ARRAY_BODY_FOREACH(&va->body, SPA_POD_BODY_SIZE(va), pi) {
printf("%d\n", *pi);
}
return 0;
return 0;
}

View file

@ -38,463 +38,454 @@
#include <lib/props.h>
struct type {
uint32_t node;
uint32_t props;
uint32_t format;
uint32_t props_device;
uint32_t props_freq;
uint32_t props_volume;
uint32_t props_min_latency;
uint32_t props_live;
struct spa_type_meta meta;
struct spa_type_data data;
struct spa_type_media_type media_type;
struct spa_type_media_subtype media_subtype;
struct spa_type_format_audio format_audio;
struct spa_type_audio_format audio_format;
struct spa_type_event_node event_node;
struct spa_type_command_node command_node;
uint32_t node;
uint32_t props;
uint32_t format;
uint32_t props_device;
uint32_t props_freq;
uint32_t props_volume;
uint32_t props_min_latency;
uint32_t props_live;
struct spa_type_meta meta;
struct spa_type_data data;
struct spa_type_media_type media_type;
struct spa_type_media_subtype media_subtype;
struct spa_type_format_audio format_audio;
struct spa_type_audio_format audio_format;
struct spa_type_event_node event_node;
struct spa_type_command_node command_node;
};
static inline void
init_type (struct type *type, struct spa_type_map *map)
static inline void init_type(struct type *type, struct spa_type_map *map)
{
type->node = spa_type_map_get_id (map, SPA_TYPE__Node);
type->props = spa_type_map_get_id (map, SPA_TYPE__Props);
type->format = spa_type_map_get_id (map, SPA_TYPE__Format);
type->props_device = spa_type_map_get_id (map, SPA_TYPE_PROPS__device);
type->props_freq = spa_type_map_get_id (map, SPA_TYPE_PROPS__frequency);
type->props_volume = spa_type_map_get_id (map, SPA_TYPE_PROPS__volume);
type->props_min_latency = spa_type_map_get_id (map, SPA_TYPE_PROPS__minLatency);
type->props_live = spa_type_map_get_id (map, SPA_TYPE_PROPS__live);
spa_type_meta_map (map, &type->meta);
spa_type_data_map (map, &type->data);
spa_type_media_type_map (map, &type->media_type);
spa_type_media_subtype_map (map, &type->media_subtype);
spa_type_format_audio_map (map, &type->format_audio);
spa_type_audio_format_map (map, &type->audio_format);
spa_type_event_node_map (map, &type->event_node);
spa_type_command_node_map (map, &type->command_node);
type->node = spa_type_map_get_id(map, SPA_TYPE__Node);
type->props = spa_type_map_get_id(map, SPA_TYPE__Props);
type->format = spa_type_map_get_id(map, SPA_TYPE__Format);
type->props_device = spa_type_map_get_id(map, SPA_TYPE_PROPS__device);
type->props_freq = spa_type_map_get_id(map, SPA_TYPE_PROPS__frequency);
type->props_volume = spa_type_map_get_id(map, SPA_TYPE_PROPS__volume);
type->props_min_latency = spa_type_map_get_id(map, SPA_TYPE_PROPS__minLatency);
type->props_live = spa_type_map_get_id(map, SPA_TYPE_PROPS__live);
spa_type_meta_map(map, &type->meta);
spa_type_data_map(map, &type->data);
spa_type_media_type_map(map, &type->media_type);
spa_type_media_subtype_map(map, &type->media_subtype);
spa_type_format_audio_map(map, &type->format_audio);
spa_type_audio_format_map(map, &type->audio_format);
spa_type_event_node_map(map, &type->event_node);
spa_type_command_node_map(map, &type->command_node);
}
struct buffer {
struct spa_buffer buffer;
struct spa_meta metas[2];
struct spa_meta_header header;
struct spa_meta_ringbuffer rb;
struct spa_data datas[1];
struct spa_chunk chunks[1];
struct spa_buffer buffer;
struct spa_meta metas[2];
struct spa_meta_header header;
struct spa_meta_ringbuffer rb;
struct spa_data datas[1];
struct spa_chunk chunks[1];
};
struct data {
struct spa_type_map *map;
struct spa_log *log;
struct spa_loop data_loop;
struct type type;
struct spa_type_map *map;
struct spa_log *log;
struct spa_loop data_loop;
struct type type;
struct spa_support support[4];
uint32_t n_support;
struct spa_support support[4];
uint32_t n_support;
struct spa_node *sink;
struct spa_port_io source_sink_io[1];
struct spa_node *sink;
struct spa_port_io source_sink_io[1];
struct spa_node *source;
struct spa_buffer *source_buffers[1];
struct buffer source_buffer[1];
struct spa_node *source;
struct spa_buffer *source_buffers[1];
struct buffer source_buffer[1];
bool running;
pthread_t thread;
bool running;
pthread_t thread;
struct spa_source sources[16];
unsigned int n_sources;
struct spa_source sources[16];
unsigned int n_sources;
bool rebuild_fds;
struct pollfd fds[16];
unsigned int n_fds;
bool rebuild_fds;
struct pollfd fds[16];
unsigned int n_fds;
};
#define BUFFER_SIZE 4096
static void
init_buffer (struct data *data, struct spa_buffer **bufs, struct buffer *ba, int n_buffers, size_t size)
init_buffer(struct data *data, struct spa_buffer **bufs, struct buffer *ba, int n_buffers,
size_t size)
{
int i;
int i;
for (i = 0; i < n_buffers; i++) {
struct buffer *b = &ba[i];
bufs[i] = &b->buffer;
for (i = 0; i < n_buffers; i++) {
struct buffer *b = &ba[i];
bufs[i] = &b->buffer;
b->buffer.id = i;
b->buffer.n_metas = 2;
b->buffer.metas = b->metas;
b->buffer.n_datas = 1;
b->buffer.datas = b->datas;
b->buffer.id = i;
b->buffer.n_metas = 2;
b->buffer.metas = b->metas;
b->buffer.n_datas = 1;
b->buffer.datas = b->datas;
b->header.flags = 0;
b->header.seq = 0;
b->header.pts = 0;
b->header.dts_offset = 0;
b->metas[0].type = data->type.meta.Header;
b->metas[0].data = &b->header;
b->metas[0].size = sizeof (b->header);
b->header.flags = 0;
b->header.seq = 0;
b->header.pts = 0;
b->header.dts_offset = 0;
b->metas[0].type = data->type.meta.Header;
b->metas[0].data = &b->header;
b->metas[0].size = sizeof(b->header);
spa_ringbuffer_init (&b->rb.ringbuffer, size);
b->metas[1].type = data->type.meta.Ringbuffer;
b->metas[1].data = &b->rb;
b->metas[1].size = sizeof (b->rb);
spa_ringbuffer_init(&b->rb.ringbuffer, size);
b->metas[1].type = data->type.meta.Ringbuffer;
b->metas[1].data = &b->rb;
b->metas[1].size = sizeof(b->rb);
b->datas[0].type = data->type.data.MemPtr;
b->datas[0].flags = 0;
b->datas[0].fd = -1;
b->datas[0].mapoffset = 0;
b->datas[0].maxsize = size;
b->datas[0].data = malloc (size);
b->datas[0].chunk = &b->chunks[0];
b->datas[0].chunk->offset = 0;
b->datas[0].chunk->size = size;
b->datas[0].chunk->stride = 0;
}
b->datas[0].type = data->type.data.MemPtr;
b->datas[0].flags = 0;
b->datas[0].fd = -1;
b->datas[0].mapoffset = 0;
b->datas[0].maxsize = size;
b->datas[0].data = malloc(size);
b->datas[0].chunk = &b->chunks[0];
b->datas[0].chunk->offset = 0;
b->datas[0].chunk->size = size;
b->datas[0].chunk->stride = 0;
}
}
static int
make_node (struct data *data, struct spa_node **node, const char *lib, const char *name)
static int make_node(struct data *data, struct spa_node **node, const char *lib, const char *name)
{
struct spa_handle *handle;
int res;
void *hnd;
spa_handle_factory_enum_func_t enum_func;
unsigned int i;
uint32_t state = 0;
struct spa_handle *handle;
int res;
void *hnd;
spa_handle_factory_enum_func_t enum_func;
unsigned int i;
uint32_t state = 0;
if ((hnd = dlopen (lib, RTLD_NOW)) == NULL) {
printf ("can't load %s: %s\n", lib, dlerror());
return SPA_RESULT_ERROR;
}
if ((enum_func = dlsym (hnd, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)) == NULL) {
printf ("can't find enum function\n");
return SPA_RESULT_ERROR;
}
if ((hnd = dlopen(lib, RTLD_NOW)) == NULL) {
printf("can't load %s: %s\n", lib, dlerror());
return SPA_RESULT_ERROR;
}
if ((enum_func = dlsym(hnd, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)) == NULL) {
printf("can't find enum function\n");
return SPA_RESULT_ERROR;
}
for (i = 0; ;i++) {
const struct spa_handle_factory *factory;
void *iface;
for (i = 0;; i++) {
const struct spa_handle_factory *factory;
void *iface;
if ((res = enum_func (&factory, state++)) < 0) {
if (res != SPA_RESULT_ENUM_END)
printf ("can't enumerate factories: %d\n", res);
break;
}
if (strcmp (factory->name, name))
continue;
if ((res = enum_func(&factory, state++)) < 0) {
if (res != SPA_RESULT_ENUM_END)
printf("can't enumerate factories: %d\n", res);
break;
}
if (strcmp(factory->name, name))
continue;
handle = calloc (1, factory->size);
if ((res = spa_handle_factory_init (factory, handle, NULL, data->support, data->n_support)) < 0) {
printf ("can't make factory instance: %d\n", res);
return res;
}
if ((res = spa_handle_get_interface (handle, data->type.node, &iface)) < 0) {
printf ("can't get interface %d\n", res);
return res;
}
*node = iface;
return SPA_RESULT_OK;
}
return SPA_RESULT_ERROR;
handle = calloc(1, factory->size);
if ((res =
spa_handle_factory_init(factory, handle, NULL, data->support,
data->n_support)) < 0) {
printf("can't make factory instance: %d\n", res);
return res;
}
if ((res = spa_handle_get_interface(handle, data->type.node, &iface)) < 0) {
printf("can't get interface %d\n", res);
return res;
}
*node = iface;
return SPA_RESULT_OK;
}
return SPA_RESULT_ERROR;
}
static void on_sink_event(struct spa_node *node, struct spa_event *event, void *user_data)
{
printf("got event %d\n", SPA_EVENT_TYPE(event));
}
static void on_sink_need_input(struct spa_node *node, void *user_data)
{
struct data *data = user_data;
int res;
res = spa_node_process_output(data->source);
if (res != SPA_RESULT_HAVE_BUFFER)
printf("got process_output error from source %d\n", res);
if ((res = spa_node_process_input(data->sink)) < 0)
printf("got process_input error from sink %d\n", res);
}
static void
on_sink_event (struct spa_node *node, struct spa_event *event, void *user_data)
on_sink_reuse_buffer(struct spa_node *node, uint32_t port_id, uint32_t buffer_id, void *user_data)
{
printf ("got event %d\n", SPA_EVENT_TYPE (event));
}
static void
on_sink_need_input (struct spa_node *node, void *user_data)
{
struct data *data = user_data;
int res;
res = spa_node_process_output (data->source);
if (res != SPA_RESULT_HAVE_BUFFER)
printf ("got process_output error from source %d\n", res);
if ((res = spa_node_process_input (data->sink)) < 0)
printf ("got process_input error from sink %d\n", res);
}
static void
on_sink_reuse_buffer (struct spa_node *node, uint32_t port_id, uint32_t buffer_id, void *user_data)
{
struct data *data = user_data;
data->source_sink_io[0].buffer_id = buffer_id;
struct data *data = user_data;
data->source_sink_io[0].buffer_id = buffer_id;
}
static const struct spa_node_callbacks sink_callbacks = {
&on_sink_event,
&on_sink_need_input,
NULL,
&on_sink_reuse_buffer
&on_sink_event,
&on_sink_need_input,
NULL,
&on_sink_reuse_buffer
};
static int
do_add_source (struct spa_loop *loop,
struct spa_source *source)
static int do_add_source(struct spa_loop *loop, struct spa_source *source)
{
struct data *data = SPA_CONTAINER_OF (loop, struct data, data_loop);
struct data *data = SPA_CONTAINER_OF(loop, struct data, data_loop);
data->sources[data->n_sources] = *source;
data->n_sources++;
data->rebuild_fds = true;
data->sources[data->n_sources] = *source;
data->n_sources++;
data->rebuild_fds = true;
return SPA_RESULT_OK;
return SPA_RESULT_OK;
}
static int
do_update_source (struct spa_source *source)
static int do_update_source(struct spa_source *source)
{
return SPA_RESULT_OK;
return SPA_RESULT_OK;
}
static void
do_remove_source (struct spa_source *source)
static void do_remove_source(struct spa_source *source)
{
}
static int
do_invoke (struct spa_loop *loop,
spa_invoke_func_t func,
uint32_t seq,
size_t size,
void *data,
void *user_data)
do_invoke(struct spa_loop *loop,
spa_invoke_func_t func, uint32_t seq, size_t size, void *data, void *user_data)
{
return func (loop, false, seq, size, data, user_data);
return func(loop, false, seq, size, data, user_data);
}
static int
make_nodes (struct data *data, const char *device)
static int make_nodes(struct data *data, const char *device)
{
int res;
struct spa_props *props;
struct spa_pod_builder b = { 0 };
struct spa_pod_frame f[2];
uint8_t buffer[128];
int res;
struct spa_props *props;
struct spa_pod_builder b = { 0 };
struct spa_pod_frame f[2];
uint8_t buffer[128];
if ((res = make_node (data, &data->sink,
"build/spa/plugins/alsa/libspa-alsa.so",
"alsa-sink")) < 0) {
printf ("can't create alsa-sink: %d\n", res);
return res;
}
spa_node_set_callbacks (data->sink, &sink_callbacks, sizeof (sink_callbacks), data);
if ((res = make_node(data, &data->sink,
"build/spa/plugins/alsa/libspa-alsa.so", "alsa-sink")) < 0) {
printf("can't create alsa-sink: %d\n", res);
return res;
}
spa_node_set_callbacks(data->sink, &sink_callbacks, sizeof(sink_callbacks), data);
spa_pod_builder_init (&b, buffer, sizeof (buffer));
spa_pod_builder_props (&b, &f[0], data->type.props,
SPA_POD_PROP (&f[1], data->type.props_device, 0, SPA_POD_TYPE_STRING, 1, device ? device : "hw:0"),
SPA_POD_PROP (&f[1], data->type.props_min_latency, 0, SPA_POD_TYPE_INT, 1, 64));
props = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_props);
spa_pod_builder_init(&b, buffer, sizeof(buffer));
spa_pod_builder_props(&b, &f[0], data->type.props,
SPA_POD_PROP(&f[1], data->type.props_device, 0, SPA_POD_TYPE_STRING, 1,
device ? device : "hw:0"),
SPA_POD_PROP(&f[1], data->type.props_min_latency, 0, SPA_POD_TYPE_INT, 1,
64));
props = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_props);
if ((res = spa_node_set_props (data->sink, props)) < 0)
printf ("got set_props error %d\n", res);
if ((res = spa_node_set_props(data->sink, props)) < 0)
printf("got set_props error %d\n", res);
if ((res = make_node (data, &data->source,
"build/spa/plugins/audiotestsrc/libspa-audiotestsrc.so",
"audiotestsrc")) < 0) {
printf ("can't create audiotestsrc: %d\n", res);
return res;
}
if ((res = make_node(data, &data->source,
"build/spa/plugins/audiotestsrc/libspa-audiotestsrc.so",
"audiotestsrc")) < 0) {
printf("can't create audiotestsrc: %d\n", res);
return res;
}
spa_pod_builder_init (&b, buffer, sizeof (buffer));
spa_pod_builder_props (&b, &f[0], data->type.props,
SPA_POD_PROP (&f[1], data->type.props_live, 0, SPA_POD_TYPE_BOOL, 1, false));
props = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_props);
spa_pod_builder_init(&b, buffer, sizeof(buffer));
spa_pod_builder_props(&b, &f[0], data->type.props,
SPA_POD_PROP(&f[1], data->type.props_live, 0, SPA_POD_TYPE_BOOL, 1,
false));
props = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_props);
if ((res = spa_node_set_props (data->source, props)) < 0)
printf ("got set_props error %d\n", res);
return res;
if ((res = spa_node_set_props(data->source, props)) < 0)
printf("got set_props error %d\n", res);
return res;
}
static int
negotiate_formats (struct data *data)
static int negotiate_formats(struct data *data)
{
int res;
struct spa_format *format, *filter;
uint32_t state = 0;
struct spa_pod_builder b = { 0 };
struct spa_pod_frame f[2];
uint8_t buffer[256];
int res;
struct spa_format *format, *filter;
uint32_t state = 0;
struct spa_pod_builder b = { 0 };
struct spa_pod_frame f[2];
uint8_t buffer[256];
spa_pod_builder_init (&b, buffer, sizeof (buffer));
spa_pod_builder_format (&b, &f[0], data->type.format,
data->type.media_type.audio, data->type.media_subtype.raw,
SPA_POD_PROP (&f[1], data->type.format_audio.format, 0,
SPA_POD_TYPE_ID, 1,
data->type.audio_format.S16),
SPA_POD_PROP (&f[1], data->type.format_audio.layout, 0,
SPA_POD_TYPE_INT, 1,
SPA_AUDIO_LAYOUT_INTERLEAVED),
SPA_POD_PROP (&f[1], data->type.format_audio.rate, 0,
SPA_POD_TYPE_INT, 1,
44100),
SPA_POD_PROP (&f[1], data->type.format_audio.channels, 0,
SPA_POD_TYPE_INT, 1,
2));
filter = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_format);
spa_pod_builder_init(&b, buffer, sizeof(buffer));
spa_pod_builder_format(&b, &f[0], data->type.format,
data->type.media_type.audio,
data->type.media_subtype.raw,
SPA_POD_PROP(&f[1], data->type.format_audio.format, 0, SPA_POD_TYPE_ID, 1,
data->type.audio_format.S16),
SPA_POD_PROP(&f[1], data->type.format_audio.layout, 0, SPA_POD_TYPE_INT, 1,
SPA_AUDIO_LAYOUT_INTERLEAVED),
SPA_POD_PROP(&f[1], data->type.format_audio.rate, 0, SPA_POD_TYPE_INT, 1,
44100),
SPA_POD_PROP(&f[1], data->type.format_audio.channels, 0, SPA_POD_TYPE_INT, 1,
2));
filter = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_format);
if ((res = spa_node_port_enum_formats (data->sink, SPA_DIRECTION_INPUT, 0, &format, filter, state)) < 0)
return res;
if ((res =
spa_node_port_enum_formats(data->sink, SPA_DIRECTION_INPUT, 0, &format, filter,
state)) < 0)
return res;
if ((res = spa_node_port_set_format (data->sink, SPA_DIRECTION_INPUT, 0, 0, format)) < 0)
return res;
if ((res = spa_node_port_set_format(data->sink, SPA_DIRECTION_INPUT, 0, 0, format)) < 0)
return res;
data->source_sink_io[0] = SPA_PORT_IO_INIT;
data->source_sink_io[0] = SPA_PORT_IO_INIT;
spa_node_port_set_io (data->source, SPA_DIRECTION_OUTPUT, 0, &data->source_sink_io[0]);
spa_node_port_set_io (data->sink, SPA_DIRECTION_INPUT, 0, &data->source_sink_io[0]);
spa_node_port_set_io(data->source, SPA_DIRECTION_OUTPUT, 0, &data->source_sink_io[0]);
spa_node_port_set_io(data->sink, SPA_DIRECTION_INPUT, 0, &data->source_sink_io[0]);
if ((res = spa_node_port_set_format (data->source, SPA_DIRECTION_OUTPUT, 0, 0, format)) < 0)
return res;
if ((res = spa_node_port_set_format(data->source, SPA_DIRECTION_OUTPUT, 0, 0, format)) < 0)
return res;
init_buffer (data, data->source_buffers, data->source_buffer, 1, BUFFER_SIZE);
if ((res = spa_node_port_use_buffers (data->sink, SPA_DIRECTION_INPUT, 0, data->source_buffers, 1)) < 0)
return res;
if ((res = spa_node_port_use_buffers (data->source, SPA_DIRECTION_OUTPUT, 0, data->source_buffers, 1)) < 0)
return res;
init_buffer(data, data->source_buffers, data->source_buffer, 1, BUFFER_SIZE);
if ((res =
spa_node_port_use_buffers(data->sink, SPA_DIRECTION_INPUT, 0, data->source_buffers,
1)) < 0)
return res;
if ((res =
spa_node_port_use_buffers(data->source, SPA_DIRECTION_OUTPUT, 0, data->source_buffers,
1)) < 0)
return res;
return SPA_RESULT_OK;
return SPA_RESULT_OK;
}
static void *
loop (void *user_data)
static void *loop(void *user_data)
{
struct data *data = user_data;
struct data *data = user_data;
printf ("enter thread %d\n", data->n_sources);
while (data->running) {
int i, r;
printf("enter thread %d\n", data->n_sources);
while (data->running) {
int i, r;
/* rebuild */
if (data->rebuild_fds) {
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
data->fds[i].fd = p->fd;
data->fds[i].events = p->mask;
}
data->n_fds = data->n_sources;
data->rebuild_fds = false;
}
/* rebuild */
if (data->rebuild_fds) {
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
data->fds[i].fd = p->fd;
data->fds[i].events = p->mask;
}
data->n_fds = data->n_sources;
data->rebuild_fds = false;
}
r = poll ((struct pollfd *) data->fds, data->n_fds, -1);
if (r < 0) {
if (errno == EINTR)
continue;
break;
}
if (r == 0) {
fprintf (stderr, "select timeout");
break;
}
r = poll((struct pollfd *) data->fds, data->n_fds, -1);
if (r < 0) {
if (errno == EINTR)
continue;
break;
}
if (r == 0) {
fprintf(stderr, "select timeout");
break;
}
/* after */
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
p->rmask = 0;
if (data->fds[i].revents & POLLIN)
p->rmask |= SPA_IO_IN;
if (data->fds[i].revents & POLLOUT)
p->rmask |= SPA_IO_OUT;
if (data->fds[i].revents & POLLHUP)
p->rmask |= SPA_IO_HUP;
if (data->fds[i].revents & POLLERR)
p->rmask |= SPA_IO_ERR;
}
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
if (p->rmask)
p->func (p);
}
}
printf ("leave thread\n");
/* after */
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
p->rmask = 0;
if (data->fds[i].revents & POLLIN)
p->rmask |= SPA_IO_IN;
if (data->fds[i].revents & POLLOUT)
p->rmask |= SPA_IO_OUT;
if (data->fds[i].revents & POLLHUP)
p->rmask |= SPA_IO_HUP;
if (data->fds[i].revents & POLLERR)
p->rmask |= SPA_IO_ERR;
}
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
if (p->rmask)
p->func(p);
}
}
printf("leave thread\n");
return NULL;
return NULL;
}
static void
run_async_sink (struct data *data)
static void run_async_sink(struct data *data)
{
int res;
int err;
int res;
int err;
{
struct spa_command cmd = SPA_COMMAND_INIT (data->type.command_node.Start);
if ((res = spa_node_send_command (data->source, &cmd)) < 0)
printf ("got source error %d\n", res);
if ((res = spa_node_send_command (data->sink, &cmd)) < 0)
printf ("got sink error %d\n", res);
}
{
struct spa_command cmd = SPA_COMMAND_INIT(data->type.command_node.Start);
if ((res = spa_node_send_command(data->source, &cmd)) < 0)
printf("got source error %d\n", res);
if ((res = spa_node_send_command(data->sink, &cmd)) < 0)
printf("got sink error %d\n", res);
}
data->running = true;
if ((err = pthread_create (&data->thread, NULL, loop, data)) != 0) {
printf ("can't create thread: %d %s", err, strerror (err));
data->running = false;
}
data->running = true;
if ((err = pthread_create(&data->thread, NULL, loop, data)) != 0) {
printf("can't create thread: %d %s", err, strerror(err));
data->running = false;
}
printf ("sleeping for 1000 seconds\n");
sleep (1000);
printf("sleeping for 1000 seconds\n");
sleep(1000);
if (data->running) {
data->running = false;
pthread_join (data->thread, NULL);
}
if (data->running) {
data->running = false;
pthread_join(data->thread, NULL);
}
{
struct spa_command cmd = SPA_COMMAND_INIT (data->type.command_node.Pause);
if ((res = spa_node_send_command (data->sink, &cmd)) < 0)
printf ("got sink error %d\n", res);
if ((res = spa_node_send_command (data->source, &cmd)) < 0)
printf ("got source error %d\n", res);
}
{
struct spa_command cmd = SPA_COMMAND_INIT(data->type.command_node.Pause);
if ((res = spa_node_send_command(data->sink, &cmd)) < 0)
printf("got sink error %d\n", res);
if ((res = spa_node_send_command(data->source, &cmd)) < 0)
printf("got source error %d\n", res);
}
}
int
main (int argc, char *argv[])
int main(int argc, char *argv[])
{
struct data data = { NULL };
int res;
const char *str;
struct data data = { NULL };
int res;
const char *str;
data.map = spa_type_map_get_default();
data.log = spa_log_get_default();
data.data_loop.size = sizeof (struct spa_loop);
data.data_loop.add_source = do_add_source;
data.data_loop.update_source = do_update_source;
data.data_loop.remove_source = do_remove_source;
data.data_loop.invoke = do_invoke;
data.map = spa_type_map_get_default();
data.log = spa_log_get_default();
data.data_loop.size = sizeof(struct spa_loop);
data.data_loop.add_source = do_add_source;
data.data_loop.update_source = do_update_source;
data.data_loop.remove_source = do_remove_source;
data.data_loop.invoke = do_invoke;
if ((str = getenv ("SPA_DEBUG")))
data.log->level = atoi (str);
if ((str = getenv("SPA_DEBUG")))
data.log->level = atoi(str);
data.support[0].type = SPA_TYPE__TypeMap;
data.support[0].data = data.map;
data.support[1].type = SPA_TYPE__Log;
data.support[1].data = data.log;
data.support[2].type = SPA_TYPE_LOOP__DataLoop;
data.support[2].data = &data.data_loop;
data.support[3].type = SPA_TYPE_LOOP__MainLoop;
data.support[3].data = &data.data_loop;
data.n_support = 4;
data.support[0].type = SPA_TYPE__TypeMap;
data.support[0].data = data.map;
data.support[1].type = SPA_TYPE__Log;
data.support[1].data = data.log;
data.support[2].type = SPA_TYPE_LOOP__DataLoop;
data.support[2].data = &data.data_loop;
data.support[3].type = SPA_TYPE_LOOP__MainLoop;
data.support[3].data = &data.data_loop;
data.n_support = 4;
init_type (&data.type, data.map);
init_type(&data.type, data.map);
if ((res = make_nodes (&data, argc > 1 ? argv[1] : NULL)) < 0) {
printf ("can't make nodes: %d\n", res);
return -1;
}
if ((res = negotiate_formats (&data)) < 0) {
printf ("can't negotiate nodes: %d\n", res);
return -1;
}
if ((res = make_nodes(&data, argc > 1 ? argv[1] : NULL)) < 0) {
printf("can't make nodes: %d\n", res);
return -1;
}
if ((res = negotiate_formats(&data)) < 0) {
printf("can't negotiate nodes: %d\n", res);
return -1;
}
run_async_sink (&data);
run_async_sink(&data);
}

View file

@ -39,564 +39,551 @@
#include <lib/mapper.h>
struct type {
uint32_t node;
uint32_t props;
uint32_t format;
uint32_t props_device;
uint32_t SDL_Texture;
struct spa_type_meta meta;
struct spa_type_data data;
struct spa_type_media_type media_type;
struct spa_type_media_subtype media_subtype;
struct spa_type_format_video format_video;
struct spa_type_video_format video_format;
struct spa_type_event_node event_node;
struct spa_type_command_node command_node;
uint32_t node;
uint32_t props;
uint32_t format;
uint32_t props_device;
uint32_t SDL_Texture;
struct spa_type_meta meta;
struct spa_type_data data;
struct spa_type_media_type media_type;
struct spa_type_media_subtype media_subtype;
struct spa_type_format_video format_video;
struct spa_type_video_format video_format;
struct spa_type_event_node event_node;
struct spa_type_command_node command_node;
};
static inline void
init_type (struct type *type, struct spa_type_map *map)
static inline void init_type(struct type *type, struct spa_type_map *map)
{
type->node = spa_type_map_get_id (map, SPA_TYPE__Node);
type->props = spa_type_map_get_id (map, SPA_TYPE__Props);
type->format = spa_type_map_get_id (map, SPA_TYPE__Format);
type->props_device = spa_type_map_get_id (map, SPA_TYPE_PROPS__device);
type->SDL_Texture = spa_type_map_get_id (map, SPA_TYPE_POINTER_BASE "SDL_Texture");
spa_type_meta_map (map, &type->meta);
spa_type_data_map (map, &type->data);
spa_type_media_type_map (map, &type->media_type);
spa_type_media_subtype_map (map, &type->media_subtype);
spa_type_format_video_map (map, &type->format_video);
spa_type_video_format_map (map, &type->video_format);
spa_type_event_node_map (map, &type->event_node);
spa_type_command_node_map (map, &type->command_node);
type->node = spa_type_map_get_id(map, SPA_TYPE__Node);
type->props = spa_type_map_get_id(map, SPA_TYPE__Props);
type->format = spa_type_map_get_id(map, SPA_TYPE__Format);
type->props_device = spa_type_map_get_id(map, SPA_TYPE_PROPS__device);
type->SDL_Texture = spa_type_map_get_id(map, SPA_TYPE_POINTER_BASE "SDL_Texture");
spa_type_meta_map(map, &type->meta);
spa_type_data_map(map, &type->data);
spa_type_media_type_map(map, &type->media_type);
spa_type_media_subtype_map(map, &type->media_subtype);
spa_type_format_video_map(map, &type->format_video);
spa_type_video_format_map(map, &type->video_format);
spa_type_event_node_map(map, &type->event_node);
spa_type_command_node_map(map, &type->command_node);
}
#define MAX_BUFFERS 8
struct buffer {
struct spa_buffer buffer;
struct spa_meta metas[2];
struct spa_meta_header header;
struct spa_meta_pointer ptr;
struct spa_data datas[1];
struct spa_chunk chunks[1];
struct spa_buffer buffer;
struct spa_meta metas[2];
struct spa_meta_header header;
struct spa_meta_pointer ptr;
struct spa_data datas[1];
struct spa_chunk chunks[1];
};
struct data {
struct type type;
struct type type;
struct spa_type_map *map;
struct spa_log *log;
struct spa_loop data_loop;
struct spa_type_map *map;
struct spa_log *log;
struct spa_loop data_loop;
struct spa_support support[4];
uint32_t n_support;
struct spa_support support[4];
uint32_t n_support;
struct spa_node *source;
struct spa_port_io source_output[1];
struct spa_node *source;
struct spa_port_io source_output[1];
SDL_Renderer *renderer;
SDL_Window *window;
SDL_Texture *texture;
SDL_Renderer *renderer;
SDL_Window *window;
SDL_Texture *texture;
bool use_buffer;
bool use_buffer;
bool running;
pthread_t thread;
bool running;
pthread_t thread;
struct spa_source sources[16];
unsigned int n_sources;
struct spa_source sources[16];
unsigned int n_sources;
bool rebuild_fds;
struct pollfd fds[16];
unsigned int n_fds;
bool rebuild_fds;
struct pollfd fds[16];
unsigned int n_fds;
struct spa_buffer *bp[MAX_BUFFERS];
struct buffer buffers[MAX_BUFFERS];
unsigned int n_buffers;
struct spa_buffer *bp[MAX_BUFFERS];
struct buffer buffers[MAX_BUFFERS];
unsigned int n_buffers;
};
static int
make_node (struct data *data, struct spa_node **node, const char *lib, const char *name)
static int make_node(struct data *data, struct spa_node **node, const char *lib, const char *name)
{
struct spa_handle *handle;
int res;
void *hnd;
spa_handle_factory_enum_func_t enum_func;
unsigned int i;
uint32_t state = 0;
struct spa_handle *handle;
int res;
void *hnd;
spa_handle_factory_enum_func_t enum_func;
unsigned int i;
uint32_t state = 0;
if ((hnd = dlopen (lib, RTLD_NOW)) == NULL) {
printf ("can't load %s: %s\n", lib, dlerror());
return SPA_RESULT_ERROR;
}
if ((enum_func = dlsym (hnd, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)) == NULL) {
printf ("can't find enum function\n");
return SPA_RESULT_ERROR;
}
if ((hnd = dlopen(lib, RTLD_NOW)) == NULL) {
printf("can't load %s: %s\n", lib, dlerror());
return SPA_RESULT_ERROR;
}
if ((enum_func = dlsym(hnd, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)) == NULL) {
printf("can't find enum function\n");
return SPA_RESULT_ERROR;
}
for (i = 0; ;i++) {
const struct spa_handle_factory *factory;
void *iface;
for (i = 0;; i++) {
const struct spa_handle_factory *factory;
void *iface;
if ((res = enum_func (&factory, state)) < 0) {
if (res != SPA_RESULT_ENUM_END)
printf ("can't enumerate factories: %d\n", res);
break;
}
if (strcmp (factory->name, name))
continue;
if ((res = enum_func(&factory, state)) < 0) {
if (res != SPA_RESULT_ENUM_END)
printf("can't enumerate factories: %d\n", res);
break;
}
if (strcmp(factory->name, name))
continue;
handle = calloc (1, factory->size);
if ((res = spa_handle_factory_init (factory, handle, NULL, data->support, data->n_support)) < 0) {
printf ("can't make factory instance: %d\n", res);
return res;
}
if ((res = spa_handle_get_interface (handle, data->type.node, &iface)) < 0) {
printf ("can't get interface %d\n", res);
return res;
}
*node = iface;
return SPA_RESULT_OK;
}
return SPA_RESULT_ERROR;
handle = calloc(1, factory->size);
if ((res =
spa_handle_factory_init(factory, handle, NULL, data->support,
data->n_support)) < 0) {
printf("can't make factory instance: %d\n", res);
return res;
}
if ((res = spa_handle_get_interface(handle, data->type.node, &iface)) < 0) {
printf("can't get interface %d\n", res);
return res;
}
*node = iface;
return SPA_RESULT_OK;
}
return SPA_RESULT_ERROR;
}
static void
handle_events (struct data *data)
static void handle_events(struct data *data)
{
SDL_Event event;
while (SDL_PollEvent (&event)) {
switch (event.type) {
case SDL_QUIT:
exit (0);
break;
}
}
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
exit(0);
break;
}
}
}
static void
on_source_event (struct spa_node *node, struct spa_event *event, void *user_data)
static void on_source_event(struct spa_node *node, struct spa_event *event, void *user_data)
{
struct data *data = user_data;
struct data *data = user_data;
handle_events (data);
handle_events(data);
printf ("got event %d\n", SPA_EVENT_TYPE (event));
printf("got event %d\n", SPA_EVENT_TYPE(event));
}
static void
on_source_have_output (struct spa_node *node, void *user_data)
static void on_source_have_output(struct spa_node *node, void *user_data)
{
struct data *data = user_data;
int res;
struct spa_buffer *b;
void *sdata, *ddata;
int sstride, dstride;
int i;
uint8_t *src, *dst;
struct spa_meta *metas;
struct spa_data *datas;
struct spa_port_io *io = &data->source_output[0];
struct data *data = user_data;
int res;
struct spa_buffer *b;
void *sdata, *ddata;
int sstride, dstride;
int i;
uint8_t *src, *dst;
struct spa_meta *metas;
struct spa_data *datas;
struct spa_port_io *io = &data->source_output[0];
handle_events (data);
handle_events(data);
b = data->bp[io->buffer_id];
b = data->bp[io->buffer_id];
metas = b->metas;
datas = b->datas;
metas = b->metas;
datas = b->datas;
if (metas[1].type == data->type.meta.Pointer &&
((struct spa_meta_pointer *)metas[1].data)->type == data->type.SDL_Texture) {
SDL_Texture *texture;
texture = ((struct spa_meta_pointer *)metas[1].data)->ptr;
if (metas[1].type == data->type.meta.Pointer &&
((struct spa_meta_pointer *) metas[1].data)->type == data->type.SDL_Texture) {
SDL_Texture *texture;
texture = ((struct spa_meta_pointer *) metas[1].data)->ptr;
SDL_UnlockTexture(texture);
SDL_UnlockTexture(texture);
SDL_RenderClear (data->renderer);
SDL_RenderCopy (data->renderer, texture, NULL, NULL);
SDL_RenderPresent (data->renderer);
SDL_RenderClear(data->renderer);
SDL_RenderCopy(data->renderer, texture, NULL, NULL);
SDL_RenderPresent(data->renderer);
if (SDL_LockTexture (texture, NULL, &sdata, &sstride) < 0) {
fprintf (stderr, "Couldn't lock texture: %s\n", SDL_GetError());
return;
}
datas[0].type = data->type.data.MemPtr;
datas[0].flags = 0;
datas[0].fd = -1;
datas[0].mapoffset = 0;
datas[0].maxsize = sstride * 240;
datas[0].data = sdata;
datas[0].chunk->offset = 0;
datas[0].chunk->size = sstride * 240;
datas[0].chunk->stride = sstride;
} else {
if (SDL_LockTexture (data->texture, NULL, &ddata, &dstride) < 0) {
fprintf (stderr, "Couldn't lock texture: %s\n", SDL_GetError());
return;
}
sdata = datas[0].data;
sstride = datas[0].chunk->stride;
if (SDL_LockTexture(texture, NULL, &sdata, &sstride) < 0) {
fprintf(stderr, "Couldn't lock texture: %s\n", SDL_GetError());
return;
}
datas[0].type = data->type.data.MemPtr;
datas[0].flags = 0;
datas[0].fd = -1;
datas[0].mapoffset = 0;
datas[0].maxsize = sstride * 240;
datas[0].data = sdata;
datas[0].chunk->offset = 0;
datas[0].chunk->size = sstride * 240;
datas[0].chunk->stride = sstride;
} else {
if (SDL_LockTexture(data->texture, NULL, &ddata, &dstride) < 0) {
fprintf(stderr, "Couldn't lock texture: %s\n", SDL_GetError());
return;
}
sdata = datas[0].data;
sstride = datas[0].chunk->stride;
for (i = 0; i < 240; i++) {
src = ((uint8_t*)sdata + i * sstride);
dst = ((uint8_t*)ddata + i * dstride);
memcpy (dst, src, SPA_MIN (sstride, dstride));
}
SDL_UnlockTexture(data->texture);
for (i = 0; i < 240; i++) {
src = ((uint8_t *) sdata + i * sstride);
dst = ((uint8_t *) ddata + i * dstride);
memcpy(dst, src, SPA_MIN(sstride, dstride));
}
SDL_UnlockTexture(data->texture);
SDL_RenderClear (data->renderer);
SDL_RenderCopy (data->renderer, data->texture, NULL, NULL);
SDL_RenderPresent (data->renderer);
}
SDL_RenderClear(data->renderer);
SDL_RenderCopy(data->renderer, data->texture, NULL, NULL);
SDL_RenderPresent(data->renderer);
}
io->status = SPA_RESULT_NEED_BUFFER;
io->status = SPA_RESULT_NEED_BUFFER;
if ((res = spa_node_process_output (data->source)) < 0)
printf ("got pull error %d\n", res);
if ((res = spa_node_process_output(data->source)) < 0)
printf("got pull error %d\n", res);
}
static const struct spa_node_callbacks source_callbacks = {
&on_source_event,
NULL,
&on_source_have_output,
NULL
&on_source_event,
NULL,
&on_source_have_output,
NULL
};
static int
do_add_source (struct spa_loop *loop,
struct spa_source *source)
static int do_add_source(struct spa_loop *loop, struct spa_source *source)
{
struct data *data = SPA_CONTAINER_OF (loop, struct data, data_loop);
struct data *data = SPA_CONTAINER_OF(loop, struct data, data_loop);
data->sources[data->n_sources] = *source;
data->n_sources++;
data->rebuild_fds = true;
data->sources[data->n_sources] = *source;
data->n_sources++;
data->rebuild_fds = true;
return SPA_RESULT_OK;
return SPA_RESULT_OK;
}
static int
do_update_source (struct spa_source *source)
static int do_update_source(struct spa_source *source)
{
return SPA_RESULT_OK;
return SPA_RESULT_OK;
}
static void
do_remove_source (struct spa_source *source)
static void do_remove_source(struct spa_source *source)
{
}
static int
do_invoke (struct spa_loop *loop,
spa_invoke_func_t func,
uint32_t seq,
size_t size,
void *data,
void *user_data)
do_invoke(struct spa_loop *loop,
spa_invoke_func_t func, uint32_t seq, size_t size, void *data, void *user_data)
{
return func (loop, false, seq, size, data, user_data);
return func(loop, false, seq, size, data, user_data);
}
static int
make_nodes (struct data *data, const char *device)
static int make_nodes(struct data *data, const char *device)
{
int res;
struct spa_props *props;
struct spa_pod_builder b = { 0 };
struct spa_pod_frame f[2];
uint8_t buffer[256];
int res;
struct spa_props *props;
struct spa_pod_builder b = { 0 };
struct spa_pod_frame f[2];
uint8_t buffer[256];
if ((res = make_node (data, &data->source, "build/spa/plugins/v4l2/libspa-v4l2.so", "v4l2-source")) < 0) {
printf ("can't create v4l2-source: %d\n", res);
return res;
}
spa_node_set_callbacks (data->source, &source_callbacks, sizeof (source_callbacks), data);
if ((res =
make_node(data, &data->source, "build/spa/plugins/v4l2/libspa-v4l2.so",
"v4l2-source")) < 0) {
printf("can't create v4l2-source: %d\n", res);
return res;
}
spa_node_set_callbacks(data->source, &source_callbacks, sizeof(source_callbacks), data);
spa_pod_builder_init (&b, buffer, sizeof (buffer));
spa_pod_builder_props (&b, &f[0], data->type.props,
SPA_POD_PROP (&f[1], data->type.props_device, 0,
SPA_POD_TYPE_STRING, 1,
device ? device : "/dev/video0"));
props = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_props);
spa_pod_builder_init(&b, buffer, sizeof(buffer));
spa_pod_builder_props(&b, &f[0], data->type.props,
SPA_POD_PROP(&f[1], data->type.props_device, 0, SPA_POD_TYPE_STRING, 1,
device ? device : "/dev/video0"));
props = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_props);
if ((res = spa_node_set_props (data->source, props)) < 0)
printf ("got set_props error %d\n", res);
if ((res = spa_node_set_props(data->source, props)) < 0)
printf("got set_props error %d\n", res);
return res;
return res;
}
static int
alloc_buffers (struct data *data)
static int alloc_buffers(struct data *data)
{
int i;
int i;
for (i = 0; i < MAX_BUFFERS; i++) {
struct buffer *b = &data->buffers[i];
SDL_Texture *texture;
void *ptr;
int stride;
for (i = 0; i < MAX_BUFFERS; i++) {
struct buffer *b = &data->buffers[i];
SDL_Texture *texture;
void *ptr;
int stride;
data->bp[i] = &b->buffer;
data->bp[i] = &b->buffer;
texture = SDL_CreateTexture (data->renderer,
SDL_PIXELFORMAT_YUY2,
SDL_TEXTUREACCESS_STREAMING,
320, 240);
if (!texture) {
printf ("can't create texture: %s\n", SDL_GetError ());
return SPA_RESULT_ERROR;
}
if (SDL_LockTexture (texture, NULL, &ptr, &stride) < 0) {
fprintf (stderr, "Couldn't lock texture: %s\n", SDL_GetError());
return SPA_RESULT_ERROR;
}
texture = SDL_CreateTexture(data->renderer,
SDL_PIXELFORMAT_YUY2,
SDL_TEXTUREACCESS_STREAMING, 320, 240);
if (!texture) {
printf("can't create texture: %s\n", SDL_GetError());
return SPA_RESULT_ERROR;
}
if (SDL_LockTexture(texture, NULL, &ptr, &stride) < 0) {
fprintf(stderr, "Couldn't lock texture: %s\n", SDL_GetError());
return SPA_RESULT_ERROR;
}
b->buffer.id = i;
b->buffer.n_metas = 2;
b->buffer.metas = b->metas;
b->buffer.n_datas = 1;
b->buffer.datas = b->datas;
b->buffer.id = i;
b->buffer.n_metas = 2;
b->buffer.metas = b->metas;
b->buffer.n_datas = 1;
b->buffer.datas = b->datas;
b->header.flags = 0;
b->header.seq = 0;
b->header.pts = 0;
b->header.dts_offset = 0;
b->metas[0].type = data->type.meta.Header;
b->metas[0].data = &b->header;
b->metas[0].size = sizeof (b->header);
b->header.flags = 0;
b->header.seq = 0;
b->header.pts = 0;
b->header.dts_offset = 0;
b->metas[0].type = data->type.meta.Header;
b->metas[0].data = &b->header;
b->metas[0].size = sizeof(b->header);
b->ptr.type = data->type.SDL_Texture;
b->ptr.ptr = texture;
b->metas[1].type = data->type.meta.Pointer;
b->metas[1].data = &b->ptr;
b->metas[1].size = sizeof (b->ptr);
b->ptr.type = data->type.SDL_Texture;
b->ptr.ptr = texture;
b->metas[1].type = data->type.meta.Pointer;
b->metas[1].data = &b->ptr;
b->metas[1].size = sizeof(b->ptr);
b->datas[0].type = data->type.data.MemPtr;
b->datas[0].flags = 0;
b->datas[0].fd = -1;
b->datas[0].mapoffset = 0;
b->datas[0].maxsize = stride * 240;
b->datas[0].data = ptr;
b->datas[0].chunk = &b->chunks[0];
b->datas[0].chunk->offset = 0;
b->datas[0].chunk->size = stride * 240;
b->datas[0].chunk->stride = stride;
}
data->n_buffers = MAX_BUFFERS;
b->datas[0].type = data->type.data.MemPtr;
b->datas[0].flags = 0;
b->datas[0].fd = -1;
b->datas[0].mapoffset = 0;
b->datas[0].maxsize = stride * 240;
b->datas[0].data = ptr;
b->datas[0].chunk = &b->chunks[0];
b->datas[0].chunk->offset = 0;
b->datas[0].chunk->size = stride * 240;
b->datas[0].chunk->stride = stride;
}
data->n_buffers = MAX_BUFFERS;
return spa_node_port_use_buffers (data->source, SPA_DIRECTION_OUTPUT, 0, data->bp, data->n_buffers);
return spa_node_port_use_buffers(data->source, SPA_DIRECTION_OUTPUT, 0, data->bp,
data->n_buffers);
}
static int
negotiate_formats (struct data *data)
static int negotiate_formats(struct data *data)
{
int res;
const struct spa_port_info *info;
struct spa_format *format;
struct spa_pod_frame f[2];
uint8_t buffer[256];
struct spa_pod_builder b = SPA_POD_BUILDER_INIT (buffer, sizeof (buffer));
int res;
const struct spa_port_info *info;
struct spa_format *format;
struct spa_pod_frame f[2];
uint8_t buffer[256];
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
data->source_output[0] = SPA_PORT_IO_INIT;
data->source_output[0] = SPA_PORT_IO_INIT;
if ((res = spa_node_port_set_io (data->source, SPA_DIRECTION_OUTPUT, 0, &data->source_output[0])) < 0)
return res;
if ((res =
spa_node_port_set_io(data->source, SPA_DIRECTION_OUTPUT, 0,
&data->source_output[0])) < 0)
return res;
#if 0
void *state = NULL;
void *state = NULL;
if ((res = spa_node_port_enum_formats (data->source, 0, &format, NULL, &state)) < 0)
return res;
if ((res = spa_node_port_enum_formats(data->source, 0, &format, NULL, &state)) < 0)
return res;
#else
spa_pod_builder_format (&b, &f[0], data->type.format,
data->type.media_type.video, data->type.media_subtype.raw,
SPA_POD_PROP (&f[1], data->type.format_video.format, 0,
SPA_POD_TYPE_ID, 1,
data->type.video_format.YUY2),
SPA_POD_PROP (&f[1], data->type.format_video.size, 0,
SPA_POD_TYPE_RECTANGLE, 1,
320, 240),
SPA_POD_PROP (&f[1], data->type.format_video.framerate, 0,
SPA_POD_TYPE_FRACTION, 1,
25, 1));
format = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_format);
spa_pod_builder_format(&b, &f[0], data->type.format,
data->type.media_type.video, data->type.media_subtype.raw,
SPA_POD_PROP(&f[1], data->type.format_video.format, 0,
SPA_POD_TYPE_ID, 1,
data->type.video_format.YUY2),
SPA_POD_PROP(&f[1], data->type.format_video.size, 0,
SPA_POD_TYPE_RECTANGLE, 1,
320, 240),
SPA_POD_PROP(&f[1], data->type.format_video.framerate, 0,
SPA_POD_TYPE_FRACTION, 1, 25, 1));
format = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_format);
#endif
if ((res = spa_node_port_set_format (data->source, SPA_DIRECTION_OUTPUT, 0, 0, format)) < 0)
return res;
if ((res = spa_node_port_set_format(data->source, SPA_DIRECTION_OUTPUT, 0, 0, format)) < 0)
return res;
if ((res = spa_node_port_get_info (data->source, SPA_DIRECTION_OUTPUT, 0, &info)) < 0)
return res;
if ((res = spa_node_port_get_info(data->source, SPA_DIRECTION_OUTPUT, 0, &info)) < 0)
return res;
if (data->use_buffer) {
if ((res = alloc_buffers (data)) < 0)
return res;
} else {
unsigned int n_buffers;
if (data->use_buffer) {
if ((res = alloc_buffers(data)) < 0)
return res;
} else {
unsigned int n_buffers;
data->texture = SDL_CreateTexture (data->renderer,
SDL_PIXELFORMAT_YUY2,
SDL_TEXTUREACCESS_STREAMING,
320, 240);
if (!data->texture) {
printf ("can't create texture: %s\n", SDL_GetError ());
return -1;
}
n_buffers = MAX_BUFFERS;
if ((res = spa_node_port_alloc_buffers (data->source, SPA_DIRECTION_OUTPUT, 0, NULL, 0, data->bp, &n_buffers)) < 0) {
printf ("can't allocate buffers: %s\n", SDL_GetError ());
return -1;
}
data->n_buffers = n_buffers;
}
return SPA_RESULT_OK;
data->texture = SDL_CreateTexture(data->renderer,
SDL_PIXELFORMAT_YUY2,
SDL_TEXTUREACCESS_STREAMING, 320, 240);
if (!data->texture) {
printf("can't create texture: %s\n", SDL_GetError());
return -1;
}
n_buffers = MAX_BUFFERS;
if ((res =
spa_node_port_alloc_buffers(data->source, SPA_DIRECTION_OUTPUT, 0, NULL, 0,
data->bp, &n_buffers)) < 0) {
printf("can't allocate buffers: %s\n", SDL_GetError());
return -1;
}
data->n_buffers = n_buffers;
}
return SPA_RESULT_OK;
}
static void *
loop (void *user_data)
static void *loop(void *user_data)
{
struct data *data = user_data;
struct data *data = user_data;
printf ("enter thread\n");
while (data->running) {
int i, r;
printf("enter thread\n");
while (data->running) {
int i, r;
/* rebuild */
if (data->rebuild_fds) {
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
data->fds[i].fd = p->fd;
data->fds[i].events = p->mask;
}
data->n_fds = data->n_sources;
data->rebuild_fds = false;
}
/* rebuild */
if (data->rebuild_fds) {
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
data->fds[i].fd = p->fd;
data->fds[i].events = p->mask;
}
data->n_fds = data->n_sources;
data->rebuild_fds = false;
}
r = poll ((struct pollfd *) data->fds, data->n_fds, -1);
if (r < 0) {
if (errno == EINTR)
continue;
break;
}
if (r == 0) {
fprintf (stderr, "select timeout");
break;
}
r = poll((struct pollfd *) data->fds, data->n_fds, -1);
if (r < 0) {
if (errno == EINTR)
continue;
break;
}
if (r == 0) {
fprintf(stderr, "select timeout");
break;
}
/* after */
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
p->rmask = 0;
if (data->fds[i].revents & POLLIN)
p->rmask |= SPA_IO_IN;
if (data->fds[i].revents & POLLOUT)
p->rmask |= SPA_IO_OUT;
if (data->fds[i].revents & POLLHUP)
p->rmask |= SPA_IO_HUP;
if (data->fds[i].revents & POLLERR)
p->rmask |= SPA_IO_ERR;
}
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
if (p->rmask)
p->func (p);
}
}
printf ("leave thread\n");
return NULL;
/* after */
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
p->rmask = 0;
if (data->fds[i].revents & POLLIN)
p->rmask |= SPA_IO_IN;
if (data->fds[i].revents & POLLOUT)
p->rmask |= SPA_IO_OUT;
if (data->fds[i].revents & POLLHUP)
p->rmask |= SPA_IO_HUP;
if (data->fds[i].revents & POLLERR)
p->rmask |= SPA_IO_ERR;
}
for (i = 0; i < data->n_sources; i++) {
struct spa_source *p = &data->sources[i];
if (p->rmask)
p->func(p);
}
}
printf("leave thread\n");
return NULL;
}
static void
run_async_source (struct data *data)
static void run_async_source(struct data *data)
{
int res;
int err;
int res;
int err;
{
struct spa_command cmd = SPA_COMMAND_INIT (data->type.command_node.Start);
if ((res = spa_node_send_command (data->source, &cmd)) < 0)
printf ("got error %d\n", res);
}
{
struct spa_command cmd = SPA_COMMAND_INIT(data->type.command_node.Start);
if ((res = spa_node_send_command(data->source, &cmd)) < 0)
printf("got error %d\n", res);
}
data->running = true;
if ((err = pthread_create (&data->thread, NULL, loop, data)) != 0) {
printf ("can't create thread: %d %s", err, strerror (err));
data->running = false;
}
data->running = true;
if ((err = pthread_create(&data->thread, NULL, loop, data)) != 0) {
printf("can't create thread: %d %s", err, strerror(err));
data->running = false;
}
sleep (10000);
sleep(10000);
if (data->running) {
data->running = false;
pthread_join (data->thread, NULL);
}
if (data->running) {
data->running = false;
pthread_join(data->thread, NULL);
}
{
struct spa_command cmd = SPA_COMMAND_INIT (data->type.command_node.Pause);
if ((res = spa_node_send_command (data->source, &cmd)) < 0)
printf ("got error %d\n", res);
}
{
struct spa_command cmd = SPA_COMMAND_INIT(data->type.command_node.Pause);
if ((res = spa_node_send_command(data->source, &cmd)) < 0)
printf("got error %d\n", res);
}
}
int
main (int argc, char *argv[])
int main(int argc, char *argv[])
{
struct data data = { 0 };
int res;
const char *str;
struct data data = { 0 };
int res;
const char *str;
data.use_buffer = true;
data.use_buffer = true;
data.map = spa_type_map_get_default ();
data.log = spa_log_get_default ();
data.map = spa_type_map_get_default();
data.log = spa_log_get_default();
if ((str = getenv ("SPA_DEBUG")))
data.log->level = atoi (str);
if ((str = getenv("SPA_DEBUG")))
data.log->level = atoi(str);
data.data_loop.size = sizeof (struct spa_loop);
data.data_loop.add_source = do_add_source;
data.data_loop.update_source = do_update_source;
data.data_loop.remove_source = do_remove_source;
data.data_loop.invoke = do_invoke;
data.data_loop.size = sizeof(struct spa_loop);
data.data_loop.add_source = do_add_source;
data.data_loop.update_source = do_update_source;
data.data_loop.remove_source = do_remove_source;
data.data_loop.invoke = do_invoke;
data.support[0].type = SPA_TYPE__TypeMap;
data.support[0].data = data.map;
data.support[1].type = SPA_TYPE__Log;
data.support[1].data = data.log;
data.support[2].type = SPA_TYPE_LOOP__DataLoop;
data.support[2].data = &data.data_loop;
data.support[3].type = SPA_TYPE_LOOP__MainLoop;
data.support[3].data = &data.data_loop;
data.n_support = 4;
data.support[0].type = SPA_TYPE__TypeMap;
data.support[0].data = data.map;
data.support[1].type = SPA_TYPE__Log;
data.support[1].data = data.log;
data.support[2].type = SPA_TYPE_LOOP__DataLoop;
data.support[2].data = &data.data_loop;
data.support[3].type = SPA_TYPE_LOOP__MainLoop;
data.support[3].data = &data.data_loop;
data.n_support = 4;
init_type (&data.type, data.map);
init_type(&data.type, data.map);
if (SDL_Init (SDL_INIT_VIDEO) < 0) {
printf ("can't initialize SDL: %s\n", SDL_GetError ());
return -1;
}
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("can't initialize SDL: %s\n", SDL_GetError());
return -1;
}
if (SDL_CreateWindowAndRenderer (320, 240, SDL_WINDOW_RESIZABLE, &data.window, &data.renderer)) {
printf ("can't create window: %s\n", SDL_GetError ());
return -1;
}
if (SDL_CreateWindowAndRenderer
(320, 240, SDL_WINDOW_RESIZABLE, &data.window, &data.renderer)) {
printf("can't create window: %s\n", SDL_GetError());
return -1;
}
if ((res = make_nodes (&data, argv[1])) < 0) {
printf ("can't make nodes: %d\n", res);
return -1;
}
if ((res = negotiate_formats (&data)) < 0) {
printf ("can't negotiate nodes: %d\n", res);
return -1;
}
if ((res = make_nodes(&data, argv[1])) < 0) {
printf("can't make nodes: %d\n", res);
return -1;
}
if ((res = negotiate_formats(&data)) < 0) {
printf("can't negotiate nodes: %d\n", res);
return -1;
}
run_async_source (&data);
run_async_source(&data);
SDL_DestroyRenderer (data.renderer);
SDL_DestroyRenderer(data.renderer);
return 0;
return 0;
}