2017-07-25 19:52:31 +02:00
|
|
|
/* PipeWire
|
|
|
|
|
* Copyright (C) 2017 Wim Taymans <wim.taymans@gmail.com>
|
|
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* Library General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
|
* License along with this library; if not, write to the
|
|
|
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
|
|
|
* Boston, MA 02110-1301, USA.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <sys/mman.h>
|
2017-08-27 12:12:14 +02:00
|
|
|
#include <signal.h>
|
2017-07-25 19:52:31 +02:00
|
|
|
|
|
|
|
|
#include <spa/type-map.h>
|
|
|
|
|
#include <spa/format-utils.h>
|
|
|
|
|
#include <spa/video/format-utils.h>
|
|
|
|
|
#include <spa/format-builder.h>
|
|
|
|
|
#include <spa/props.h>
|
|
|
|
|
#include <spa/lib/debug.h>
|
|
|
|
|
|
|
|
|
|
#include <pipewire/pipewire.h>
|
|
|
|
|
#include <pipewire/module.h>
|
|
|
|
|
#include <pipewire/node-factory.h>
|
|
|
|
|
|
|
|
|
|
struct type {
|
|
|
|
|
uint32_t format;
|
|
|
|
|
uint32_t props;
|
|
|
|
|
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;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static inline void init_type(struct type *type, struct spa_type_map *map)
|
|
|
|
|
{
|
|
|
|
|
type->format = spa_type_map_get_id(map, SPA_TYPE__Format);
|
|
|
|
|
type->props = spa_type_map_get_id(map, SPA_TYPE__Props);
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct data {
|
|
|
|
|
struct type type;
|
|
|
|
|
|
|
|
|
|
bool running;
|
|
|
|
|
struct pw_loop *loop;
|
|
|
|
|
|
|
|
|
|
struct pw_core *core;
|
2017-08-04 10:18:54 +02:00
|
|
|
struct pw_type *t;
|
2017-07-25 19:52:31 +02:00
|
|
|
|
|
|
|
|
struct pw_remote *remote;
|
2017-08-08 16:56:29 +02:00
|
|
|
struct spa_hook remote_listener;
|
2017-07-25 19:52:31 +02:00
|
|
|
|
|
|
|
|
struct pw_node *node;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void make_node(struct data *data)
|
|
|
|
|
{
|
|
|
|
|
struct pw_node_factory *factory;
|
|
|
|
|
struct pw_properties *props;
|
|
|
|
|
|
|
|
|
|
factory = pw_core_find_node_factory(data->core, "spa-node-factory");
|
|
|
|
|
props = pw_properties_new("spa.library.name", "v4l2/libspa-v4l2",
|
|
|
|
|
"spa.factory.name", "v4l2-source", NULL);
|
|
|
|
|
data->node = pw_node_factory_create_node(factory, NULL, "v4l2-source", props);
|
|
|
|
|
|
|
|
|
|
pw_remote_export(data->remote, data->node);
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-04 10:18:54 +02:00
|
|
|
static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remote_state state, const char *error)
|
2017-07-25 19:52:31 +02:00
|
|
|
{
|
2017-08-04 10:18:54 +02:00
|
|
|
struct data *data = _data;
|
2017-07-25 19:52:31 +02:00
|
|
|
|
2017-08-04 10:18:54 +02:00
|
|
|
switch (state) {
|
2017-07-25 19:52:31 +02:00
|
|
|
case PW_REMOTE_STATE_ERROR:
|
2017-08-04 10:18:54 +02:00
|
|
|
printf("remote error: %s\n", error);
|
2017-07-25 19:52:31 +02:00
|
|
|
data->running = false;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PW_REMOTE_STATE_CONNECTED:
|
2017-08-25 18:59:01 +02:00
|
|
|
printf("remote state: \"%s\"\n", pw_remote_state_as_string(state));
|
2017-07-25 19:52:31 +02:00
|
|
|
make_node(data);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2017-08-04 10:18:54 +02:00
|
|
|
printf("remote state: \"%s\"\n", pw_remote_state_as_string(state));
|
2017-07-25 19:52:31 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-04 16:49:13 +02:00
|
|
|
static const struct pw_remote_events remote_events = {
|
|
|
|
|
PW_VERSION_REMOTE_EVENTS,
|
2017-08-04 10:18:54 +02:00
|
|
|
.state_changed = on_state_changed,
|
|
|
|
|
};
|
2017-07-25 19:52:31 +02:00
|
|
|
|
2017-08-27 12:12:14 +02:00
|
|
|
static void do_quit(void *data, int signal_number)
|
|
|
|
|
{
|
|
|
|
|
struct data *d = data;
|
|
|
|
|
d->running = false;
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-25 19:52:31 +02:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
struct data data = { 0, };
|
|
|
|
|
|
|
|
|
|
pw_init(&argc, &argv);
|
|
|
|
|
|
2017-08-08 18:22:44 +02:00
|
|
|
data.loop = pw_loop_new(NULL);
|
2017-08-27 12:12:14 +02:00
|
|
|
pw_loop_add_signal(data.loop, SIGINT, do_quit, &data);
|
|
|
|
|
pw_loop_add_signal(data.loop, SIGTERM, do_quit, &data);
|
|
|
|
|
|
2017-07-25 19:52:31 +02:00
|
|
|
data.running = true;
|
|
|
|
|
data.core = pw_core_new(data.loop, NULL);
|
2017-08-04 10:18:54 +02:00
|
|
|
data.t = pw_core_get_type(data.core);
|
2017-07-25 19:52:31 +02:00
|
|
|
data.remote = pw_remote_new(data.core, NULL);
|
|
|
|
|
|
|
|
|
|
pw_module_load(data.core, "libpipewire-module-spa-node-factory", NULL);
|
|
|
|
|
|
2017-08-04 10:18:54 +02:00
|
|
|
init_type(&data.type, data.t->map);
|
2017-07-25 19:52:31 +02:00
|
|
|
|
2017-08-04 10:18:54 +02:00
|
|
|
spa_debug_set_type_map(data.t->map);
|
2017-07-25 19:52:31 +02:00
|
|
|
|
2017-08-04 16:49:13 +02:00
|
|
|
pw_remote_add_listener(data.remote, &data.remote_listener, &remote_events, &data);
|
2017-07-25 19:52:31 +02:00
|
|
|
|
|
|
|
|
pw_remote_connect(data.remote);
|
|
|
|
|
|
|
|
|
|
pw_loop_enter(data.loop);
|
|
|
|
|
while (data.running) {
|
2017-08-27 12:12:14 +02:00
|
|
|
pw_loop_iterate(data.loop, 100);
|
2017-07-25 19:52:31 +02:00
|
|
|
}
|
|
|
|
|
pw_loop_leave(data.loop);
|
|
|
|
|
|
2017-08-27 12:12:14 +02:00
|
|
|
pw_remote_destroy(data.remote);
|
|
|
|
|
if (data.node)
|
|
|
|
|
pw_node_destroy(data.node);
|
|
|
|
|
pw_core_destroy(data.core);
|
2017-07-25 19:52:31 +02:00
|
|
|
pw_loop_destroy(data.loop);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|