View Source Membrane.ChildrenSpec (Membrane Core v0.11.0)

A module with functionalities that allow to represent a topology of a pipeline/bin.

The children specification (commonly refered as a "children_spec") is represented by the following type: t/0. It consists of two parts - a chilren structure and the children specification options.

The children specification describes the desired topology and can be incorporated into a pipeline or a bin by returning Membrane.Pipeline.Action.spec_t/0 or Membrane.Bin.Action.spec_t/0 action, respectively. This commonly happens within Membrane.Pipeline.handle_init/2 and Membrane.Bin.handle_init/2, but can be done in any other callback also.

children-structure

Children structure

The children structure allows specifying the children that need to be spawned in the action, as well as links between the children (both the children spawned in that action, and already existing children).

The children's processes are spawned with the use of child/3 and child/4 functions. These two functions can be used for spawning nodes of a link in an inline manner:

structure = [child(:source, Source) |> child(:filter, %Filter{option: 1}) |> child(:sink, Sink)]

or just to spawn children processes, without linking the newly created children:

structure = [child(:source, Source),
  child(:filter, Filter),
  child(:sink, Sink)]

In case you need to refer to an already existing child (which could be spawned, i.e. in the previous spec_t action), use get_child/1 and get_child/2 functions, as in the example below:

structure = [get_child(:already_existing_source) |> child(:this_filter_will_be_spawned, Filter) |> get_child(:already_existing_sink)]

The child/3 and child/4 functions allow specifying :get_if_exists option. It might be helpful when you are not certain if the child with given name exists, and, therefore, you are unable to choose between get_child and child functions. After setting the get_if_exists: true option in child/3 and child/4 functions you can be sure that in case a child with a given name already exists, you will simply refer to that child instead of respawning it.

structure = [child(:sink, Sink),
  child(:sink, Sink, get_if_exists: true) |> child(:source, Source)]

In the example above you can see, that the :sink child is created in the first element of the structure list. In the second element of that list, the get_if_exists: true option is used within child/3, which will have the same effect as if get_child(:sink) was used. At the same time, if the :sink child wasn't already spawned, it would be created in that link definition.

via_in/2 and via_out/2 functions allow specifying pads' names and parameters. If pads are not specified, name :input is assumed for inputs and :output for outputs.

Sample definition: [ get_child(:source_a) |> get_child(:converter) |> via_in(:input_a, target_queue_size: 20) |> get_child(:mixer), get_child(:source_b) |> via_out(:custom_output) |> via_in(:input_b, options: [mute: true]) |> get_child(:mixer) |> via_in(:input, toilet_capacity: 500) |> get_child(:sink) ]

See the docs for via_in/3 and via_out/3 for details on pad properties that can be set. Links can also contain children's definitions, for example:

[ child(:first_element, %Element.With.Options.Struct{option_a: 42}) |> child(:some_element, Element.Without.Options) |> get_child(:element_specified_before) ]

bins

Bins

For bin boundaries, there are special links allowed. The user should define links between the bin's input and the first child's input (input-input type) and the last child's output and bin output (output-output type). In this case, bin_input/1 and bin_output/2 should be used.

Sample definition:

[ bin_input() |> get_child(:filter1) |> get_child(:filter2) |> bin_output(:custom_output) ]

dynamic-pads

Dynamic pads

In most cases, dynamic pads can be linked the same way as static ones, although in the following situations, an exact pad reference must be passed instead of a name:

  • When that reference is needed later, for example, to handle a notification related to that particular pad instance

pad = Pad.ref(:output, make_ref()) [ get_child(:tee) |> via_out(pad) |> get_child(:sink) ]

@impl true def handlepad_added(Pad.ref(:input, ) = pad, _ctx, state) do structure = [bin_input(pad) |> get_child(:mixer)] {{:ok, spec: structure}, state} end

children-specification-options

Children specification options

stream-sync

Stream sync

:stream_sync field can be used for specifying elements that should start playing at the same moment. An example can be audio and video player sinks. This option accepts either :sinks atom or a list of groups (lists) of elements. Passing :sinks results in synchronizing all sinks in the pipeline, while passing a list of groups of elements synchronizes all elements in each group. It is worth mentioning that to keep the stream synchronized all involved elements need to rely on the same clock.

By default, no elements are synchronized.

Sample definitions:

children = ...
{children, stream_sync: [[:element1, :element2], [:element3, :element4]]}
{children, stream_sync: :sinks}

clock-provider

Clock provider

A clock provider is an element that exports a clock that should be used as the pipeline clock. The pipeline clock is the default clock used by elements' timers. For more information see Membrane.Element.Base.def_clock/1.

crash-groups

Crash groups

A crash group is a logical entity that prevents the whole pipeline from crashing when one of its children crash.

adding-children-to-a-crash-group

Adding children to a crash group

structure = [
  child(:some_element_1, %SomeElement{
    # ...
  },
  child(:some_element_2, %SomeElement{
    # ...
  }
]

spec = {structure, crash_group: {group_id, :temporary}}

The crash group is defined by a two-element tuple, first element is an ID which is of type Membrane.CrashGroup.name_t(), and the second is a mode. Currently, we support only :temporary mode which means that Membrane will not make any attempts to restart crashed child.

In the above snippet, we create new children - :some_element_1 and :some_element_2, we add them to the crash group with id group_id. Crash of :some_element_1 or :some_element_2 propagates only to the rest of the members of the crash group and the pipeline stays alive.

Handling crash of a crash group

When any of the members of the crash group goes down, the callback: handle_crash_group_down/3 is called.

@impl true
def handle_crash_group_down(crash_group_id, ctx, state) do
# do some stuff in reaction to the crash of the group with id crash_group_id
end

Limitations

At this moment crash groups are only useful for elements with dynamic pads. Crash groups work only in pipelines and are not supported in bins.

log-metadata

Log metadata

:log_metadata field can be used to set the Membrane.Logger metadata for all children in given children specification.

nesting-children-specifications

Nesting children specifications

The children specifications can be be nested withing themselves.

Consider the following children specification:

{[
  child(:a, A) |> child(:b, B),
  {child(:c, C), crash_group:
    {:second, :temporary}}
], crash_group: {:first, :temporary, node: some_node}}

Child :c will be spawned in the :second crash group, while children :a and :b will be spawned in the :first crash group. Furthermore, since the inner children specification does not define the :node option, it will be inherited from the outer children specification. That means that child :c will be spawned on the some_node node, along with children :a and :b.

Link to this section Summary

Functions

Begins a link with a bin's pad.

Ends a link with a bin's output.

Used to spawn an unlinked child or to spawn a child at the beggining of a link specification.

Used to spawn a child in the middle of a link specification.

Used to refer to an existing child at a beggining of a link specification.

Used to refer to an existing child in a middle of a link specification.

Specifies input pad name and properties of the subsequent child.

Specifies output pad name and properties of the preceding child.

Link to this section Types

@type child_definition_t() :: struct() | module()
@type child_options_t() :: [{:get_if_exists, boolean()}]
Link to this type

children_spec_options_t()

View Source
@type children_spec_options_t() :: [
  crash_group: Membrane.CrashGroup.t() | nil,
  stream_sync: :sinks | [[Membrane.Child.name_t()]],
  clock_provider: Membrane.Child.name_t() | nil,
  node: node() | nil,
  log_metadata: Keyword.t()
]
@type pad_options_t() :: Keyword.t()
Link to this opaque

structure_builder_t()

View Source (opaque)
@opaque structure_builder_t()
@type t() :: structure_builder_t() | [t()] | {t(), children_spec_options_t()}

Used to describe the inner topology of the pipeline/bin.

Link to this section Functions

Link to this function

bin_input(pad \\ :input)

View Source

Begins a link with a bin's pad.

See the structure section of the moduledoc for more information.

Link to this function

bin_output(builder, pad \\ :output)

View Source

Ends a link with a bin's output.

See the structure section of the moduledoc for more information.

Link to this function

child(child_name, child_definition, opts \\ [])

View Source

Used to spawn an unlinked child or to spawn a child at the beggining of a link specification.

See the structure section of the moduledoc for more information.

Link to this function

child(structure_builder, child_name, child_definition, opts)

View Source

Used to spawn a child in the middle of a link specification.

See the structure section of the moduledoc for more information.

@spec get_child(Membrane.Child.name_t()) :: structure_builder_t()

Used to refer to an existing child at a beggining of a link specification.

See the structure section of the moduledoc for more information.

Link to this function

get_child(structure_builder, child_name)

View Source

Used to refer to an existing child in a middle of a link specification.

See the structure section of the moduledoc for more information.

Link to this function

via_in(builder, pad, props \\ [])

View Source
@spec via_in(structure_builder_t(), Membrane.Pad.name_t() | Membrane.Pad.ref_t(),
  options: pad_options_t(),
  toilet_capacity: number() | nil,
  target_queue_size: number() | nil,
  min_demand_factor: number() | nil,
  auto_demand_size: number() | nil,
  throttling_factor: number() | nil
) :: structure_builder_t() | no_return()

Specifies input pad name and properties of the subsequent child.

The possible properties are:

Additionally, the following properties can be used to adjust the flow control parameters. If set within a bin on an input that connects to the bin input, they will be overridden if set when linking to the bin in its parent.

  • toilet_capacity - Used when a toilet is created, that is for pull input pads that have push output pads linked to them. When a push output produces more buffers than the pull input can consume, the buffers are accumulated in a queue called a toilet. If the toilet size grows above its capacity, it overflows by raising an error.
  • target_queue_size - The size of the queue of the input pad that Membrane will try to maintain. That allows for fulfilling the demands of the element by taking data from the queue while the actual sending of demands is done asynchronously, smoothing the processing. Used only for pads working in pull mode with manual demands. See Membrane.Pad.mode_t/0 and Membrane.Pad.demand_mode_t/0 for more info.
  • min_demand_factor - A factor used to calculate minimal demand (minimal_demand = target_queue_size * min_demand_factor). Membrane won't send smaller demand than minimal demand, to reduce demands' overhead. However, the user will always receive as many buffers, as demanded, all excess buffers will be queued internally. Used only for pads working in pull mode with manual demands. See Membrane.Pad.mode_t/0 and Membrane.Pad.demand_mode_t/0 for more info. Defaults to 0.25 (the default may change in the future).
  • auto_demand_size - Size of automatically generated demands. Used only for pads working in pull mode with automatic demands. See Membrane.Pad.mode_t/0 and Membrane.Pad.demand_mode_t/0 for more info.
  • throttling_factor - an integer specifying how frequently should a sender update the number of buffers in the Toilet. Defaults to 1, meaning, that the sender will update the toilet with each buffer being sent. Setting that factor for elements, which are running on the same node, does not have an impact of performance. However, once the sending element and the receiving element are put on different nodes, the sender updates the toilet with interprocess messages and setting a bigger throttling_factor can reduce the number of messages in the system. At the same time, setting a greater throttling_factor can result in a toilet overflow being detected later.

See the structure section of the moduledoc for more information.

Link to this function

via_out(builder, pad, props \\ [])

View Source

Specifies output pad name and properties of the preceding child.

The possible properties are:

See the structure section of the moduledoc for more information.