Skip to content

Commit

Permalink
lifecycle guide wip
Browse files Browse the repository at this point in the history
  • Loading branch information
FelonEkonom committed Dec 20, 2024
1 parent 2eeb21e commit 01e330e
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 4 deletions.
57 changes: 57 additions & 0 deletions guides/components_lifecycle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Lifecycle of Membrane Components

Lifecycle of Membrane Components is strictly related to execution of Membrane callbacks withing these Components.
Although there are some differences between lifecycles of Membrane Pipelines, Bins and Elements, they are very similar to each other.
So let's take a look at what the component lifecycle looks like and what are the differences depending on the type of the Component we are dealing with.

## Initialization
The first callback, that is executed in every Membrane Component, is handle_init/2.
handle_init is always executed synchronously and blocks the parent component (the exception is Membrane Pipeline, that never has a parent component), so it's good to avoid heavy computations within it.
`handle_init` is a good place to spawn pipeline's or bin's children in the `:spec` action.

## Setup
The next callback after handle_init is `handle_setup`, that is executed asynchronusly and it is a good place to e.g. setup some resources or execute other heavy operations, that are necessary
for the element to play.

## Linking the pads
If the Component had some pads with `availability: :on_request` linked in the same `spec`, where it was spawned, the appropriate `handle_pad_added` callbacks will be invoked between `handle_setup` and `handle_playing`.
Linking the pad with `availability: :on_request` in the another spec than the one that spawns the element might result in invoking `handle_pad_added` after `handle_playing`.

## Playing
After setup is completed, the component might now enter `:playing` playback, by invoking `handle_playing` callback.
Note:
- components spawned within a single `spec` will always enter `:playing` state in the same moment - it means, if setup of one of them takes longer than other, the rest will wait on the component that is the last.
- Elements and Bins always wait with execution of `handle_playing` until their parent enters `playing` playback.
- by default, after `handle_setup` callback the component's setup is considered as completed. But this behaviour can be changed by returning `setup: :incomplete` action from `handle_setup`. If so, to enter `playing` playback, the component mark its setup as completed by returning `setup: :complete` from another callback, e.g. `handle_info/3`.

## Processing the data (applies only to `Elements`)
After execution of `handle_playing`, Elements are now ready to process the data that flows through the pads.

### Events
The first type of the items that can be sent via Elements' pads are `events`. Handling an event takes place in `hanlde_event`. Event can be sent both upstream and downstream the direction of the pad.

### Stream formats
Stream format specifies what type of the data will be sent in `Membrane.Buffer`'s. The stream format must be sent before first `Membrane.Buffer` and is handled in `handle_stream_format`

### Start of stream
This callback (`handle_start_of_stream`) will be invoked just before handling the first `Membrane.Buffer` incoming from the specific input pad.

### Buffers
The core of the multimedia processing. `Membrane.Buffer`'s contain multimedia payload, but they also may have information about some metadata or timestamps. Handling them takes place in `handle_buffer` callback.

## After processing the data
If the element decides, that it won't send any more buffers on the specific pad, it can send `:end_of_stream` there. It will be received by the linked element in `handle_end_of_stream` callback.
When the element receives `end_of_stream` callback, it's parent (Bin or Pipeline) will be also notified about it in `handle_element_end_of_stream` callback.

## Terminating
Usually the last callback executed within a Membrane Component is `handle_terminate_request`. By default it returns `terminate: :normal` action, which ends the lifespan of the component (with reason `:normal`).
You can change this behaviour by overriding defeault impelmentation of this callback, but remember tho return `terminate: reason` in another place! Otherwise, your Pipeline will have problems with getting termianted.

## Callbacks not strictly related to the lifecycle
Not all the callbacks are restricted to occur in specific moments in the Membrane Component lifecycle.

### Handling parent/child notification
`handle_parent_notification` and `handle_child_notification` are the 2 callbacks that can during the whole Component's lifecycle. They are responsible for handling nofications sent from respectively parent or child Component.

### Handling messages from non-Membrane processes
There is also a `handle_info` callback in all of the Membrane Components and `handle_call` in Membrane Pipelines, that can be invoked in every moment, when the Component is alive. Their function is annalogical as in the `GenServer`.
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ defmodule Membrane.Mixfile do
{:bunch, "~> 1.6"},
{:ratio, "~> 3.0 or ~> 4.0"},
# Development
{:ex_doc, "~> 0.28", only: :dev, runtime: false},
{:ex_doc, "~> 0.35", only: :dev, runtime: false},
{:makeup_diff, "~> 0.1", only: :dev, runtime: false},
{:dialyxir, "~> 1.1", only: :dev, runtime: false},
{:credo, "~> 1.7", only: :dev, runtime: false},
Expand Down
6 changes: 3 additions & 3 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"bunch": {:hex, :bunch, "1.6.1", "5393d827a64d5f846092703441ea50e65bc09f37fd8e320878f13e63d410aec7", [:mix], [], "hexpm", "286cc3add551628b30605efbe2fca4e38cc1bea89bcd0a1a7226920b3364fe4a"},
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
"coerce": {:hex, :coerce, "1.0.1", "211c27386315dc2894ac11bc1f413a0e38505d808153367bd5c6e75a4003d096", [:mix], [], "hexpm", "b44a691700f7a1a15b4b7e2ff1fa30bebd669929ac8aa43cffe9e2f8bf051cf1"},
"credo": {:hex, :credo, "1.7.8", "9722ba1681e973025908d542ec3d95db5f9c549251ba5b028e251ad8c24ab8c5", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cb9e87cc64f152f3ed1c6e325e7b894dea8f5ef2e41123bd864e3cd5ceb44968"},
"dialyxir": {:hex, :dialyxir, "1.4.4", "fb3ce8741edeaea59c9ae84d5cec75da00fa89fe401c72d6e047d11a61f65f70", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "cd6111e8017ccd563e65621a4d9a4a1c5cd333df30cebc7face8029cacb4eff6"},
"credo": {:hex, :credo, "1.7.10", "6e64fe59be8da5e30a1b96273b247b5cf1cc9e336b5fd66302a64b25749ad44d", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "71fbc9a6b8be21d993deca85bf151df023a3097b01e09a2809d460348561d8cd"},
"dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"},
"earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"},
"erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"},
"ex_doc": {:hex, :ex_doc, "0.35.1", "de804c590d3df2d9d5b8aec77d758b00c814b356119b3d4455e4b8a8687aecaf", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "2121c6402c8d44b05622677b761371a759143b958c6c19f6558ff64d0aed40df"},
Expand All @@ -16,7 +16,7 @@
"makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"},
"makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"},
"mox": {:hex, :mox, "1.2.0", "a2cd96b4b80a3883e3100a221e8adc1b98e4c3a332a8fc434c39526babafd5b3", [:mix], [{:nimble_ownership, "~> 1.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}], "hexpm", "c7b92b3cc69ee24a7eeeaf944cd7be22013c52fcb580c1f33f50845ec821089a"},
"nimble_ownership": {:hex, :nimble_ownership, "1.0.0", "3f87744d42c21b2042a0aa1d48c83c77e6dd9dd357e425a038dd4b49ba8b79a1", [:mix], [], "hexpm", "7c16cc74f4e952464220a73055b557a273e8b1b7ace8489ec9d86e9ad56cb2cc"},
"nimble_ownership": {:hex, :nimble_ownership, "1.0.1", "f69fae0cdd451b1614364013544e66e4f5d25f36a2056a9698b793305c5aa3a6", [:mix], [], "hexpm", "3825e461025464f519f3f3e4a1f9b68c47dc151369611629ad08b636b73bb22d"},
"nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
"numbers": {:hex, :numbers, "5.2.4", "f123d5bb7f6acc366f8f445e10a32bd403c8469bdbce8ce049e1f0972b607080", [:mix], [{:coerce, "~> 1.0", [hex: :coerce, repo: "hexpm", optional: false]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "eeccf5c61d5f4922198395bf87a465b6f980b8b862dd22d28198c5e6fab38582"},
"qex": {:hex, :qex, "0.5.1", "0d82c0f008551d24fffb99d97f8299afcb8ea9cf99582b770bd004ed5af63fd6", [:mix], [], "hexpm", "935a39fdaf2445834b95951456559e9dc2063d0a055742c558a99987b38d6bab"},
Expand Down

0 comments on commit 01e330e

Please sign in to comment.