summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorWim Taymans <wtaymans@redhat.com>2020-06-11 15:32:52 +0200
committerWim Taymans <wtaymans@redhat.com>2020-06-11 15:32:52 +0200
commit44efab6c3157c1ca1501905d6b5750c66f267200 (patch)
treece8c8a1c915f8a757fce2cadcec39e280f216427 /doc
parent0ee5feab674f02105c7e1c6c8ae1680b0d51707d (diff)
docs: more tutorial
Diffstat (limited to 'doc')
-rw-r--r--doc/tutorial-index.md4
-rw-r--r--doc/tutorial1.md5
-rw-r--r--doc/tutorial2.md119
3 files changed, 122 insertions, 6 deletions
diff --git a/doc/tutorial-index.md b/doc/tutorial-index.md
index e494787c..d2feec37 100644
--- a/doc/tutorial-index.md
+++ b/doc/tutorial-index.md
@@ -3,6 +3,6 @@
Welcome to the PipeWire tutorial. The goal is to learn to
PipeWire API step-by-step with simple short examples.
-1) Getting started [tutorial 1](tutorial1.md).
+1) Getting started ([tutorial 1](tutorial1.md)).
-2) Enumerating objects [tutorial 2](tutorial2.md).
+2) Enumerating objects ([tutorial 2](tutorial2.md)).
diff --git a/doc/tutorial1.md b/doc/tutorial1.md
index 98889756..1e952299 100644
--- a/doc/tutorial1.md
+++ b/doc/tutorial1.md
@@ -1,4 +1,6 @@
-# Tutorial 1
+[index](tutorial-index.md) [next](tutorial2.md)
+
+# Getting started (Tutorial 1)
In this tutorial we show the basics of a simple PipeWire application.
Use this tutorial to get started and help you set up your development
@@ -43,3 +45,4 @@ Linked with libpipewire 0.3.5
#
```
+[index](tutorial-index.md) [next](tutorial2.md)
diff --git a/doc/tutorial2.md b/doc/tutorial2.md
index 53ce179e..cc20dfd1 100644
--- a/doc/tutorial2.md
+++ b/doc/tutorial2.md
@@ -1,10 +1,10 @@
-# Tutorial 2
+[previous](tutorial1.md) [index](tutorial-index.md) [next](tutorial3.md)
+
+# Enumerating objects (Tutorial 2)
In this tutorial we show how to connect to a PipeWire daemon and
enumerate the objects that it has.
-## Initialization
-
Let take a look at the following application to start.
```c
@@ -65,3 +65,116 @@ use:
```
gcc -Wall test2.c -o test2 $(pkg-config --cflags --libs libpipewire-0.3)
```
+
+Let's break this down:
+
+First we need to initialize the PipeWire library with `pw_init()` as we
+saw in the previous tutorial. This will load and configure the right
+modules and setup logging and other tasks.
+
+```c
+ ...
+ pw_init(&argc, &argv);
+ ...
+```
+
+Next we need to create one of the `struct pw_loop` wrappers. PipeWire
+ships with 2 types of mainloop implementations. We will use the
+`struct pw_main_loop` implementation, we will see later how we can
+use the `struct pw_thread_loop` implementation as well.
+
+The mainloop is an abstraction of a big poll loop, wiating for events
+to occur and things to do. Most of the PipeWire work will actually
+be performed in the context of this loop and so we need to make one
+first.
+
+We then need to make a new context object with the loop. This context
+object will manage the resources for us and will make it possible for
+us to connect to a PipeWire daemon:
+
+```c
+ struct pw_main_loop *loop;
+ struct pw_context *context;
+
+ loop = pw_main_loop_new(NULL /* properties */);
+ context = pw_context_new(pw_main_loop_get_loop(loop),
+ NULL /* properties */,
+ 0 /* user_data size */);
+```
+
+It is possible to give extra properties when making the mainloop or
+context to tweak its features and functionality. It is also possible
+to add extra data to the allocated objects for your user data. It will
+stay alive for as long as the object is alive. We will use this
+feature later.
+
+A real implementation would also need to check if the allocation
+succeeded and do some error handling, but we leave that out to make
+the code easier to read.
+
+With the context we can now connect to the PipeWire daemon:
+
+```c
+ struct pw_core *core;
+ core = pw_context_connect(context,
+ NULL /* properties */,
+ 0 /* user_data size */);
+```
+
+This creates a socket between the client and the server and makes
+a proxy object (with ID 0) for the core. Don't forget to check the
+result here, a NULL value means that the connection failed.
+
+At this point we can send messages to the server and receive events.
+For now we're not going to handle events on this core proxy but
+we're going to handle them on the registry object.
+
+
+```c
+ struct pw_registry *registry;
+ struct spa_hook registry_listener;
+
+ registry = pw_core_get_registry(core, PW_VERSION_REGISTRY,
+ 0 /* user_data size */);
+
+ spa_zero(registry_listener);
+ pw_registry_add_listener(registry, &registry_listener,
+ &registry_events, NULL);
+```
+
+From the core we get the registry proxy object and when we use
+`pw_registry_add_listener()` to listen for events. We need a
+small `struct spa_hook` to keep track of the listener and a
+reference to the `struct pw_registry_events` that contains the
+events we want to listen to.
+
+This is how we define the event handler and the function to
+handle the events:
+
+```c
+static const struct pw_registry_events registry_events = {
+ PW_VERSION_REGISTRY_EVENTS,
+ .global = registry_event_global,
+};
+
+static void registry_event_global(void *data, uint32_t id,
+ uint32_t permissions, const char *type, uint32_t version,
+ const struct spa_dict *props)
+{
+ printf("object: id:%u type:%s/%d\n", id, type, version);
+}
+```
+
+Now that everything is set up we can start the mainloop and let
+the communication between client and server continue:
+
+```c
+ pw_main_loop_run(loop);
+```
+
+Since we don't call `pw_main_loop_quit()` anywhere, this loop will
+continue forever. In the next tutorial we'll see how we can nicely
+exit our application after we received all server objects.
+
+
+[previous](tutorial1.md) [index](tutorial-index.md) [next](tutorial3.md)