From 9ed9980fa2ce1343b55914f865a0b8c79dcf1bd3 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 25 May 2021 13:08:04 +1000 Subject: [PATCH] doc: change the tutorials to doxygen sources While doxygen can handle markdown pages, support for it is very limited: markdown pages can only be included as a whole page, they get an automatic title (custom titles are possible but aren't standard markdown) and it's not possible to use \subpage without messing with the markdown again. Any markdown page will thus end up as separate item in the doxygen output, not really suitable for generating a good page hiearchy. Let's switch the tutorial to use doxygen directly instead of markdown, short of using code/endcode instead of markdown's ``` there isn't that much difference anyway but it allows us to structure things nicer in the online docs. --- doc/meson.build | 14 +++---- doc/tutorial-index.md | 16 -------- doc/tutorial.dox | 13 ++++++ doc/{tutorial1.md => tutorial1.dox} | 27 ++++++------- doc/{tutorial2.md => tutorial2.dox} | 41 +++++++++---------- doc/{tutorial3.md => tutorial3.dox} | 54 ++++++++++++------------- doc/{tutorial4.md => tutorial4.dox} | 40 +++++++++--------- doc/{tutorial5.md => tutorial5.dox} | 63 ++++++++++++++--------------- doc/{tutorial6.md => tutorial6.dox} | 30 +++++++------- 9 files changed, 145 insertions(+), 153 deletions(-) delete mode 100644 doc/tutorial-index.md create mode 100644 doc/tutorial.dox rename doc/{tutorial1.md => tutorial1.dox} (67%) rename doc/{tutorial2.md => tutorial2.dox} (92%) rename doc/{tutorial3.md => tutorial3.dox} (92%) rename doc/{tutorial4.md => tutorial4.dox} (95%) rename doc/{tutorial5.md => tutorial5.dox} (93%) rename doc/{tutorial6.md => tutorial6.dox} (92%) diff --git a/doc/meson.build b/doc/meson.build index 7eb7281b4..268a4a777 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -48,13 +48,13 @@ extra_docs = [ 'pipewire-design.md', 'pipewire-architecture.md', 'pipewire-objects-design.md', - 'tutorial-index.md', - 'tutorial1.md', - 'tutorial2.md', - 'tutorial3.md', - 'tutorial4.md', - 'tutorial5.md', - 'tutorial6.md', + 'tutorial.dox', + 'tutorial1.dox', + 'tutorial2.dox', + 'tutorial3.dox', + 'tutorial4.dox', + 'tutorial5.dox', + 'tutorial6.dox', 'spa-index.md', 'spa-design.md', 'spa-pod.md', diff --git a/doc/tutorial-index.md b/doc/tutorial-index.md deleted file mode 100644 index ed76f3616..000000000 --- a/doc/tutorial-index.md +++ /dev/null @@ -1,16 +0,0 @@ -# Tutorial - The PipeWire API - -Welcome to the PipeWire tutorial. The goal is to learn -PipeWire API step-by-step with simple short examples. - -1) Getting started ([tutorial 1](tutorial1.md)). - -2) Enumerating objects ([tutorial 2](tutorial2.md)). - -3) Forcing a roundtrip ([tutorial 3](tutorial3.md)). - -4) Playing a tone with `pw_stream` ([tutorial 4](tutorial4.md)). - -5) Capture video frames with `pw_stream` ([tutorial 5](tutorial5.md)). - -6) Bind to an object ([tutorial 6](tutorial6.md)). diff --git a/doc/tutorial.dox b/doc/tutorial.dox new file mode 100644 index 000000000..f1262b253 --- /dev/null +++ b/doc/tutorial.dox @@ -0,0 +1,13 @@ +/** \page page_tutorial Tutorial - The PipeWire API + +Welcome to the PipeWire tutorial. The goal is to learn +PipeWire API step-by-step with simple short examples. + +- \subpage page_tutorial1 +- \subpage page_tutorial2 +- \subpage page_tutorial3 +- \subpage page_tutorial4 +- \subpage page_tutorial5 +- \subpage page_tutorial6 + +*/ diff --git a/doc/tutorial1.md b/doc/tutorial1.dox similarity index 67% rename from doc/tutorial1.md rename to doc/tutorial1.dox index 80c8c43b7..e2230862d 100644 --- a/doc/tutorial1.md +++ b/doc/tutorial1.dox @@ -1,6 +1,7 @@ -# Tutorial - Part 1: Getting started +/** \page page_tutorial1 Tutorial - Part 1: Getting started -[[index]](tutorial-index.md) [[next]](tutorial2.md) + +\ref page_tutorial "Index" | \ref page_tutorial2 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 @@ -10,7 +11,7 @@ environment. Let get started with the simplest application. -```c +\code{.c} #include int main(int argc, char *argv[]) @@ -23,7 +24,7 @@ int main(int argc, char *argv[]) pw_get_library_version()); return 0; } -``` +\endcode Before you can use any PipeWire functions, you need to call `pw_init()`. @@ -32,17 +33,15 @@ Before you can use any PipeWire functions, you need to call `pw_init()`. To compile the simple test application, copy it into a test1.c file and use: -``` -gcc -Wall test1.c -o test1 $(pkg-config --cflags --libs libpipewire-0.3) -``` + gcc -Wall test1.c -o test1 $(pkg-config --cflags --libs libpipewire-0.3) then run it with: -``` -# ./test1 -Compiled with libpipewire 0.3.5 -Linked with libpipewire 0.3.5 -# -``` + # ./test1 + Compiled with libpipewire 0.3.5 + Linked with libpipewire 0.3.5 + # -[[index]](tutorial-index.md) [[next]](tutorial2.md) +\ref page_tutorial "Index" | \ref page_tutorial2 + +*/ diff --git a/doc/tutorial2.md b/doc/tutorial2.dox similarity index 92% rename from doc/tutorial2.md rename to doc/tutorial2.dox index e9ff30ea6..19af9f407 100644 --- a/doc/tutorial2.md +++ b/doc/tutorial2.dox @@ -1,14 +1,13 @@ -# Tutorial - Part 2: Enumerating objects - -[[previous]](tutorial1.md) [[index]](tutorial-index.md) [[next]](tutorial3.md) +/** \page page_tutorial2 Tutorial - Part 2: Enumerating objects +\ref page_tutorial1 | \ref page_tutorial "Index" | \ref page_tutorial3 In this tutorial we show how to connect to a PipeWire daemon and enumerate the objects that it has. Let take a look at the following application to start. -```c +\code{.c} #include static void registry_event_global(void *data, uint32_t id, @@ -58,14 +57,12 @@ int main(int argc, char *argv[]) return 0; } -``` +\endcode To compile the simple test application, copy it into a tutorial2.c file and use: -``` -gcc -Wall tutorial2.c -o tutorial2 $(pkg-config --cflags --libs libpipewire-0.3) -``` + gcc -Wall tutorial2.c -o tutorial2 $(pkg-config --cflags --libs libpipewire-0.3) Let's break this down: @@ -73,11 +70,11 @@ 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 +\code{.c} ... pw_init(&argc, &argv); ... -``` +\endcode Next we need to create one of the `struct pw_loop` wrappers. PipeWire ships with 2 types of mainloop implementations. We will use the @@ -93,7 +90,7 @@ 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 +\code{.c} struct pw_main_loop *loop; struct pw_context *context; @@ -101,7 +98,7 @@ us to connect to a PipeWire daemon: context = pw_context_new(pw_main_loop_get_loop(loop), NULL /* properties */, 0 /* user_data size */); -``` +\endcode It is possible to give extra properties when making the mainloop or context to tweak its features and functionality. It is also possible @@ -115,12 +112,12 @@ the code easier to read. With the context we can now connect to the PipeWire daemon: -```c +\code{.c} struct pw_core *core; core = pw_context_connect(context, NULL /* properties */, 0 /* user_data size */); -``` +\endcode 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 @@ -131,7 +128,7 @@ 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 +\code{.c} struct pw_registry *registry; struct spa_hook registry_listener; @@ -141,7 +138,7 @@ we're going to handle them on the registry object. spa_zero(registry_listener); pw_registry_add_listener(registry, ®istry_listener, ®istry_events, NULL); -``` +\endcode From the core we get the registry proxy object and when we use `pw_registry_add_listener()` to listen for events. We need a @@ -152,7 +149,7 @@ events we want to listen to. This is how we define the event handler and the function to handle the events: -```c +\code{.c} static const struct pw_registry_events registry_events = { PW_VERSION_REGISTRY_EVENTS, .global = registry_event_global, @@ -164,18 +161,18 @@ static void registry_event_global(void *data, uint32_t id, { printf("object: id:%u type:%s/%d\n", id, type, version); } -``` +\endcode Now that everything is set up we can start the mainloop and let the communication between client and server continue: -```c +\code{.c} pw_main_loop_run(loop); -``` +\endcode 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) +\ref page_tutorial1 | \ref page_tutorial "Index" | \ref page_tutorial3 +*/ diff --git a/doc/tutorial3.md b/doc/tutorial3.dox similarity index 92% rename from doc/tutorial3.md rename to doc/tutorial3.dox index a08ee680b..3b0ee5021 100644 --- a/doc/tutorial3.md +++ b/doc/tutorial3.dox @@ -1,16 +1,16 @@ -# Tutorial - Part 3: Forcing a roundtrip +/** \page page_tutorial3 Tutorial - Part 3: Forcing a roundtrip -[[previous]](tutorial2.md) [[index]](tutorial-index.md) [[next]](tutorial4.md) +\ref page_tutorial2 | \ref page_tutorial "Index" | \ref page_tutorial4 In this tutorial we show how to force a roundtrip to the server to make sure an action completed. -We'll change our example from [Tutorial 2](tutorial2.md) slightly +We'll change our example from \ref page_tutorial2 "Tutorial2" slightly and add the extra code to implement the roundtrip. Let's take the following small method first: -```c +\code{.c} static int roundtrip(struct pw_core *core, struct pw_main_loop *loop) { struct spa_hook core_listener; @@ -39,22 +39,22 @@ static int roundtrip(struct pw_core *core, struct pw_main_loop *loop) spa_hook_remove(&core_listener); return 0; } -``` +\endcode Let's take a look at what this method does. -```c +\code{.c} struct spa_hook core_listener; spa_zero(core_listener); pw_core_add_listener(core, &core_listener, &core_events, NULL); -``` +\endcode First of all we add a listener for the events of the core object. We are only interested in the `done` event in this tutorial. This is the event handler: -```c +\code{.c} int pending, done = 0; void core_event_done(void *object, uint32_t id, int seq) { @@ -67,7 +67,7 @@ tutorial. This is the event handler: PW_VERSION_CORE_EVENTS, .done = core_event_done, }; -``` +\endcode When the done event is received for an object with id `PW_ID_CORE` and a certain sequence number `seq`, this function will set the done @@ -75,9 +75,9 @@ variable to 1 and call `pw_main_loop_quit()`. Next we do: -```c +\code{.c} pending = pw_core_sync(core, PW_ID_CORE, 0); -``` +\endcode This triggers the `sync` method on the core object with id `PW_ID_CORE` and sequence number 0. @@ -96,20 +96,20 @@ method in the sequence number. We then run the mainloop to send the messages to the server and receive the events: -```c +\code{.c} while (!done) { pw_main_loop_run(loop); } -``` +\endcode When we get the done event, we can compare it to the sync method and then we know that we did a complete roundtrip and there are no more pending methods on the server. We can quit the mainloop and remove the listener: -```c +\code{.c} spa_hook_remove(&core_listener); -``` +\endcode If we add this roundtrip method to our code and call it instead of the `pw_main_loop_run()` we will exit the program after all previous methods @@ -118,7 +118,7 @@ completed and thus that we also received all events for the globals on the server. -```c +\code{.c} #include static int roundtrip(struct pw_core *core, struct pw_main_loop *loop) @@ -196,22 +196,20 @@ int main(int argc, char *argv[]) return 0; } -``` +\endcode To compile the simple test application, copy it into a tutorial3.c file and use: -``` -gcc -Wall tutorial3.c -o tutorial3 $(pkg-config --cflags --libs libpipewire-0.3) -``` + gcc -Wall tutorial3.c -o tutorial3 $(pkg-config --cflags --libs libpipewire-0.3) Now that our program completes, we can take a look at how we can destroy the objects we created. Let's destroy each of them in reverse order that we created them: -```c +\code{.c} pw_proxy_destroy((struct pw_proxy*)registry); -``` +\endcode The registry is a proxy and can be destroyed with the generic proxy destroy method. After destroying the object, you should not use it anymore. It is @@ -219,18 +217,20 @@ an error to destroy an object more than once. We can disconnect from the server with: -```c +\code{.c} pw_core_disconnect(core); -``` +\endcode This will also destroy the core proxy object and will remove the proxies that might have been created on this connection. We can finally destroy our context and mainloop to conclude this tutorial: -```c +\code{.c} pw_context_destroy(context); pw_main_loop_destroy(loop); -``` +\endcode -[[previous]](tutorial2.md) [[index]](tutorial-index.md) [[next]](tutorial4.md) +\ref page_tutorial2 | \ref page_tutorial "Index" | \ref page_tutorial4 + +*/ diff --git a/doc/tutorial4.md b/doc/tutorial4.dox similarity index 95% rename from doc/tutorial4.md rename to doc/tutorial4.dox index 0d9490340..dd9bc56b8 100644 --- a/doc/tutorial4.md +++ b/doc/tutorial4.dox @@ -1,12 +1,12 @@ -# Tutorial - Part 4: Playing a tone +/** \page page_tutorial4 Tutorial - Part 4: Playing a tone -[[previous]](tutorial3.md) [[index]](tutorial-index.md) [[next]](tutorial5.md) +\ref page_tutorial3 | \ref page_tutorial "Index" | \ref page_tutorial5 In this tutorial we show how to use a stream to play a tone. Let's take a look at the code before we break it down: -```c +\code{.c} #include #include @@ -110,19 +110,17 @@ int main(int argc, char *argv[]) return 0; } -``` +\endcode Save as tutorial4.c and compile with: -``` -gcc -Wall tutorial4.c -o tutorial4 -lm $(pkg-config --cflags --libs libpipewire-0.3) -``` + gcc -Wall tutorial4.c -o tutorial4 -lm $(pkg-config --cflags --libs libpipewire-0.3) We start with the usual boilerplate, `pw_init()` and a `pw_main_loop_new()`. We're going to store our objects in a structure so that we can pass them around in callbacks later. -```c +\code{.c} struct data { struct pw_main_loop *loop; struct pw_stream *stream; @@ -136,13 +134,13 @@ int main(int argc, char *argv[]) pw_init(&argc, &argv); data.loop = pw_main_loop_new(NULL); -``` +\endcode Next we create a stream object. It takes the mainloop as first argument and a stream name as the second. Next we provide some properties for the stream and a callback + data. -```c +\code{.c} data.stream = pw_stream_new_simple( pw_main_loop_get_loop(data.loop), "audio-src", @@ -153,7 +151,7 @@ and a callback + data. NULL), &stream_events, &data); -``` +\endcode We are using `pw_stream_new_simple()` but there is also a `pw_stream_new()` that takes an existing `struct pw_core` as the first argument and that requires you @@ -176,18 +174,18 @@ later. This is the event structure that we use to listen for events: -```c +\code{.c} static const struct pw_stream_events stream_events = { PW_VERSION_STREAM_EVENTS, .process = on_process, }; -``` +\endcode We are for the moment only interested now in the `process` event. This event is called whenever we need to produce more data. We'll see how that function is implemented but first we need to setup the format of the stream: -```c +\code{.c} const struct spa_pod *params[1]; uint8_t buffer[1024]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); @@ -200,7 +198,7 @@ is implemented but first we need to setup the format of the stream: .format = SPA_AUDIO_FORMAT_S16, .channels = DEFAULT_CHANNELS, .rate = DEFAULT_RATE )); -``` +\endcode This is using a `struct spa_pod_builder` to make a `struct spa_pod *` object in the buffer array on the stack. The parameter is of type `SPA_PARAM_EnumFormat` @@ -213,7 +211,7 @@ make these POD objects. Now we're ready to connect the stream and run the main loop: -```c +\code{.c} pw_stream_connect(data.stream, PW_DIRECTION_OUTPUT, PW_ID_ANY, @@ -223,7 +221,7 @@ Now we're ready to connect the stream and run the main loop: params, 1); pw_main_loop_run(data.loop); -``` +\endcode To connect we specify that we have a `PW_DIRECTION_OUTPUT` stream. `PW_ID_ANY` means that we are ok with connecting to any consumer. Next we set some flags: @@ -252,7 +250,7 @@ The main program flow of the process function is: * adjust buffer with number of written bytes, offset, stride, * `pw_stream_queue_buffer()` to queue the buffer for playback. -```c +\code{.c} static void on_process(void *userdata) { struct data *data = userdata; @@ -289,7 +287,7 @@ static void on_process(void *userdata) pw_stream_queue_buffer(data->stream, b); } -``` +\endcode Check out the docs for [buffers](spa-buffer.md) for more information about how to work with buffers. @@ -298,4 +296,6 @@ Try to change the number of channels, samplerate or format; the stream will automatically convert to the format on the server. -[[previous]](tutorial3.md) [[index]](tutorial-index.md) [[next]](tutorial5.md) +\ref page_tutorial3 | \ref page_tutorial "Index" | \ref page_tutorial5 + +*/ diff --git a/doc/tutorial5.md b/doc/tutorial5.dox similarity index 93% rename from doc/tutorial5.md rename to doc/tutorial5.dox index d9c1c4892..c1016e29e 100644 --- a/doc/tutorial5.md +++ b/doc/tutorial5.dox @@ -1,17 +1,17 @@ -# Tutorial - Part 5: Capturing video frames +/** \page page_tutorial5 Tutorial - Part 5: Capturing video frames -[[previous]](tutorial4.md) [[index]](tutorial-index.md) [[next]](tutorial6.md) +\ref page_tutorial4 | \ref page_tutorial "Index" | \ref page_tutorial6 In this tutorial we show how to use a stream to capture a stream of video frames. Even though we are now working with a different media type and we are capturing instead of playback, you will see that this -example is very similar to the previous [tutorial 4](tutorial4.md). +example is very similar to \ref page_tutorial4. Let's take a look at the code before we break it down: -```c +\code{.c} #include #include #include @@ -140,21 +140,18 @@ int main(int argc, char *argv[]) return 0; } -``` +\endcode Save as tutorial5.c and compile with: -``` -gcc -Wall tutorial5.c -o tutorial5 -lm $(pkg-config --cflags --libs libpipewire-0.3) -``` + gcc -Wall tutorial5.c -o tutorial5 -lm $(pkg-config --cflags --libs libpipewire-0.3) -Most of the application is structured like the previous -[tutorial 4](tutorial4.md). +Most of the application is structured like \ref page_tutorial4. We create a stream object with different properties to make it a Camera Video Capture stream. -```c +\code{.c} data.stream = pw_stream_new_simple( pw_main_loop_get_loop(data.loop), "video-capture", @@ -165,24 +162,24 @@ Video Capture stream. NULL), &stream_events, &data); -``` +\endcode In addition to the `process` event, we are also going to listen to a new event, `param_changed`: -```c +\code{.c} static const struct pw_stream_events stream_events = { PW_VERSION_STREAM_EVENTS, .param_changed = on_param_changed, .process = on_process, }; -``` +\endcode Because we capture a stream of a wide range of different video formats and resolutions, we have to describe our accepted formats in a different way: -```c +\code{.c} const struct spa_pod *params[1]; uint8_t buffer[1024]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); @@ -207,7 +204,7 @@ a different way: &SPA_FRACTION(25, 1), &SPA_FRACTION(0, 1), &SPA_FRACTION(1000, 1))); -``` +\endcode This is using a `struct spa_pod_builder` to make a `struct spa_pod *` object in the buffer array on the stack. The parameter is of type `SPA_PARAM_EnumFormat` @@ -220,7 +217,7 @@ We have an enumeration of formats, we need to first give the amount of enumerati that follow, then the default (preferred) value, followed by alternatives in order of preference: -```c +\code{.c} SPA_FORMAT_VIDEO_format, SPA_POD_CHOICE_ENUM_Id(7, SPA_VIDEO_FORMAT_RGB, /* default */ SPA_VIDEO_FORMAT_RGB, /* alternative 1 */ @@ -229,17 +226,17 @@ of preference: SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_YUY2, SPA_VIDEO_FORMAT_I420), -``` +\endcode We also have a `RANGE` of values for the size. We need to give a default (preferred) size and then a min and max value: -```c +\code{.c} SPA_FORMAT_VIDEO_size, SPA_POD_CHOICE_RANGE_Rectangle( &SPA_RECTANGLE(320, 240), /* default */ &SPA_RECTANGLE(1, 1), /* min */ &SPA_RECTANGLE(4096, 4096)), /* max */ -``` +\endcode We have something similar for the framerate. @@ -251,7 +248,7 @@ POD objects. Now we're ready to connect the stream and run the main loop: -```c +\code{.c} pw_stream_connect(data.stream, PW_DIRECTION_INPUT, argc > 1 ? (uint32_t)atoi(argv[1]) : PW_ID_ANY, @@ -260,7 +257,7 @@ Now we're ready to connect the stream and run the main loop: params, 1); pw_main_loop_run(data.loop); -``` +\endcode To connect we specify that we have a `PW_DIRECTION_INPUT` stream. `PW_ID_ANY` means that we are ok with connecting to any producer. We also allow the user @@ -283,14 +280,14 @@ connected. Let's take a look at how we can parse the format in the `param_changed` event: -```c +\code{.c} static void on_param_changed(void *userdata, uint32_t id, const struct spa_pod *param) { struct data *data = userdata; if (param == NULL || id != SPA_PARAM_Format) return; -``` +\endcode First check if there is a param. A NULL param means that it is cleared. The id of the param tells you what param it is. We are only interested in Format @@ -301,7 +298,7 @@ of the right type. In our example this will always be true but when your EnumFormat contains different media types or subtypes, this is how you can parse them: -```c +\code{.c} if (spa_format_parse(param, &data->format.media_type, &data->format.media_subtype) < 0) @@ -310,13 +307,13 @@ parse them: if (data->format.media_type != SPA_MEDIA_TYPE_video || data->format.media_subtype != SPA_MEDIA_SUBTYPE_raw) return; -``` +\endcode For the `video/raw` media type/subtype there is a utility function to parse out the values into a `struct spa_video_info`. This makes it easier to deal with. -```c +\code{.c} if (spa_format_video_raw_parse(param, &data->format.info.raw) < 0) return; @@ -331,16 +328,16 @@ to deal with. /** prepare to render video of this size */ } -``` +\endcode In this example we dump the video size and parameters but in a real playback or capture application you might want to set up the screen or encoder to deal with the format. After negotiation, the process function is called for each new frame. Check out -[tutorial 4](tutorial4.md) for another example. +\ref page_tutorial4 for another example. -```c +\code{.c} static void on_process(void *userdata) { struct data *data = userdata; @@ -361,9 +358,11 @@ static void on_process(void *userdata) pw_stream_queue_buffer(data->stream, b); } -``` +\endcode In a real playback application, one would do something with the data, like copy it to the screen or encode it into a file. -[[previous]](tutorial4.md) [[index]](tutorial-index.md) [[next]](tutorial6.md) +\ref page_tutorial4 | \ref page_tutorial "Index" | \ref page_tutorial6 + +*/ diff --git a/doc/tutorial6.md b/doc/tutorial6.dox similarity index 92% rename from doc/tutorial6.md rename to doc/tutorial6.dox index 6148026e9..82ef26f3f 100644 --- a/doc/tutorial6.md +++ b/doc/tutorial6.dox @@ -1,13 +1,13 @@ -# Tutorial - Part 6: Binding objects +/** \page page_tutorial6 Tutorial - Part 6: Binding objects -[[previous]](tutorial5.md) [[index]](tutorial-index.md) +\ref page_tutorial5 | \ref page_tutorial "Index" In this tutorial we show how to bind to an object so that we can receive events and call methods on the object. Let take a look at the following application to start. -```c +\code{.c} #include struct data { @@ -94,22 +94,20 @@ int main(int argc, char *argv[]) return 0; } -``` +\endcode To compile the simple test application, copy it into a tutorial6.c file and use: -``` -gcc -Wall tutorial6.c -o tutorial6 $(pkg-config --cflags --libs libpipewire-0.3) -``` + gcc -Wall tutorial6.c -o tutorial6 $(pkg-config --cflags --libs libpipewire-0.3) -Most of this is the same as [tutorial 2](tutorial2.md) where we simply +Most of this is the same as \ref page_tutorial2 where we simply enumerated all objects on the server. Instead of just printing the object id and some other properties, in this example we also bind to the object. We use the `pw_registry_bind()` method on our registry object like this: -```c +\code{.c} static void registry_event_global(void *_data, uint32_t id, uint32_t permissions, const char *type, uint32_t version, const struct spa_dict *props) @@ -124,7 +122,7 @@ static void registry_event_global(void *_data, uint32_t id, /* ... */ } } -``` +\endcode We bind to the first client object that we see. This gives us a pointer to a `struct pw_proxy` that we can also cast to a `struct pw_client`. @@ -138,7 +136,7 @@ listen to the info event on the client object that is emitted right after we bind to it or when it changes. This is not very different from the registry listener we added before: -```c +\code{.c} static void client_info(void *object, const struct pw_client_info *info) { struct data *data = object; @@ -167,7 +165,7 @@ static void registry_event_global(void *_data, uint32_t id, &client_events, data); /* ... */ } -``` +\endcode We're also quitting the mainloop after we get the info to nicely stop our tutorial application. @@ -175,13 +173,15 @@ our tutorial application. When we stop the application, don't forget to destroy all proxies that you created. Otherwise, they will be leaked: -```c +\code{.c} /* ... */ pw_proxy_destroy((struct pw_proxy *)data.client); /* ... */ return 0; } -``` +\endcode -[[previous]](tutorial5.md) [[index]](tutorial-index.md) +\ref page_tutorial5 | \ref page_tutorial "Index" + +*/