# Upgrading to v0.11

Improvements in v0.11 required some breaking changes, so here comes the guide that will help you adjust your code to the new API. See the [changelog](https://github.com/membraneframework/membrane_core/releases/tag/v0.11.0) for details.

## Deps upgrade

Update `membrane_core` to `v0.11`
```elixir 
defp deps do
   [
     {:membrane_core, "~> 0.11.0"},
     ...
   ]
end
```

## Use the new way of interaction with `Membrane.Pipeline`

Use the new return type of `Membrane.Pipeline.start/3` and `Membrane.Pipeline.start_link/3`

```diff
- {:ok, pid} = Membrane.Pipeline.start_link(...)
- send(pid, :message)
+ {:ok, _pipeline_supervisor, pipeline} = Membrane.Pipeline.start_link(...)
+ send(pipeline, :message)
```

Now, when you get `EXIT` signal from `pipeline`, it means only that the pipeline process is dead.
When you get `EXIT` signal from `pipeline_supervisor`, it means that the pipeline,
all its children, descendants and utilities are dead.

In tests, it's best to use `Membrane.Testing.Pipeline.start_link_supervised!/1`. See the _Testing_ section for details.

## Update format of tuples returned from callbacks

Update type of tuples returned from callbacks to `{actions, state}`
If callback returns:

 * `{:ok, state}`, change it to `{[], state}`

```diff
- {:ok, state}
+ {[], state}
```

 * `{{:ok, actions}, state}`, change it to `{actions, state}`

```diff
- {{:ok, event: {pad, event}}, state}
+ {[event: {pad, event}], state}
```

 * `{:error, reason}` or `{{:error, reason}, state}`, raise an error, instead of returning value from callback

```diff
- {:error, :something_went_wrong}
+ raise "Something went wrong!"
```

## Update callbacks

Add `context` argument to `handle_init`

```diff
- def handle_init(options) do
+ def handle_init(_context, options) do
```

Instead of `handle_stopped_to_prepared/2`, implement `handle_setup/2`

```diff
- def handle_stopped_to_prepared(ctx, state) do
+ def handle_setup(ctx, state) do
```

In general, `handle_init` should cover simple tasks like parsing options, while `handle_setup` is there for complex and long-lasting operations. See the docs for details.

___

Rename `handle_prepared_to_playing/2` to `handle_playing/2`

```diff
- def handle_prepared_to_playing(ctx, state) do
+ def handle_playing(ctx, state) do
```

Remove `handle_playing_to_prepared/2`, `handle_prepared_to_stopped/2` and `handle_shutdown/2`. Instead, use `Membrane.ResourceGuard`, `Membrane.UtilitySupervisor` or `handle_terminate_request/2`:

```diff
- def handle_stopped_to_prepared(_ctx, state) do
-  resource = create_resource()
-  {:ok, %{state | resource: resource}}
- end
- ...
- def handle_prepared_to_stopped(_ctx, state) do
-  cleanup(state.resource)
- end
+ def handle_setup(ctx, state) do
+  resource = create_resource()
+  # The resource will be automatically cleaned up when the component terminates
+  # unless you do that earlier by calling `Membrane.Resource.cleanup/2`
+  Membrane.ResourceGuard.register(
+    ctx.resource_guard,
+    fn -> cleanup(resource)
+  end)
+  {[], %{state | resource: resource}}
+ end
```

```diff
- def handle_stopped_to_prepared(_ctx, state) do
-  {:ok, pid} = GenServer.start_link(SomeServer, options)
-  {:ok, %{state | utility: pid}}
- end
- ...
- def handle_prepared_to_stopped(_ctx, state) do
-  GenServer.stop(state.utility)
- end
+ def handle_setup(ctx, state) do
+  Membrane.UtilitySupervisor.start_link_child(ctx.utility_supervisor, SomeServer)
+  {[], %{state | utility: pid}}
+ end
```

```diff
- def handle_prepared_to_stopped(_ctx, state) do
-   do_some_work(state)
-   {:ok, state}
- end
+ def handle_terminate_request(ctx, state) do
+   # This will only be called upon graceful termination,
+   # i.e. `Membrane.Pipeline.terminate/1`, termination of parent
+   # or being removed by parent (`remove_child` action).
+   # Won't be called if component crashes.
+   do_some_work(state)
+
+   # You can defer component termination by not returning `:terminate`
+   # from this callback and returning it later instead.
+   {[terminate: :normal], state}
+ end
```

Rename `handle_other/3` into `handle_info/3` (unless your `handle_other/3` was used to receive message from parent - if so, see subsection about `handle_parent_notification/3` below)

```diff 
@impl true
- def handle_other(message, _ctx, state) do
+ def handle_info(message, _ctx, state) do
```

Rename `playback_state` to `playback` in contexts. Rely on `:stopped` instead of `:prepared`

```diff
- def handle_other(message, %{playback_state: :playing}, state) do
+ def handle_info(message, %{playback: :playing}, state) do
```

```diff
- def handle_other(message, %{playback_state: :prepared}, state) do
+ def handle_info(message, %{playback: :stopped}, state) do
```

In elements, rename `handle_caps/4` to `handle_stream_format/4`

```diff
- def handle_caps(pad_ref, caps, ctx, state) do
+ def handle_stream_format(pad_ref, stream_format, ctx, state) do
```

In pipelines and bins, change arguments in `handle_element_start_of_stream` and `handle_element_end_of_stream`, since till now on they accept children name and pad reference as two separate arguments instead of storing them as tuple in the first argument.

```diff
use Membrane.Pipeline
...
@impl true
- def handle_element_end_of_stream({child_name, pad_ref}, context, state)
+ def handle_element_end_of_stream(child_name, pad_ref, context, state)
```

In pipelines and bins, rename `handle_notification/4` into `handle_child_notification/4`

```diff
@impl true
- def handle_notification(notification, child, context, state) do
+ def handle_child_notification(notification, child, context, state) do
```
___

In elements and bins, add an implementation of `handle_parent_notification/3` in place of the `handle_other/3` that were responsible for receiving messages from the parents.

```diff
@impl true
- def handle_other(parent_notification, context, state) do
+ def handle_parent_notification(parent_notification, context, state) do
```

## Rename actions returned from callbacks

In elements:
* `:caps` -> `:stream_format`
* `:notify` -> `:notify_parent`
  
In bins:
* `:notify` -> `:notify_parent`
* `:forward` -> `:notify_child`

In pipelines:
* `:forward` -> `:notify_child`


```diff
- {{:ok, caps: %My.Format{freq: 1}}, state}
+ {[stream_format: %My.Format{freq: 1}], state}
```


```diff
use Membrane.Bin
...
- {{:ok, [forward: {child, :response}]}, state}
+ {[notify_child: {child, :response}], state}
```

## Update pads definitions

Instead of using `:caps`, use `:accepted_format` option.
Option `:accepted_format` can receive:

 * Module name

```diff
- caps: My.Format
+ accepted_format: My.Format 
```

 * Elixir pattern

```diff
- caps: {My.Format, field: one_of([:some, :enumeration])}
+ accepted_format: %My.Format{field: value} when value in [:some, :enumeration]
```

```diff
- caps: :any
+ accepted_format: _any
```

 * Call to `any_of` function. You can pass there as many arguments, as you want. Each argument should be an Elixir pattern or a module name

```diff
- caps: [My.Format, My.Another.Format]
+ accepted_format: any_of(My.Format, My.Another.Format)
```

```diff
- caps: [My.Format, {My.Another.Format, field: :strict_value}, My.Yet.Another.Format]
+ accepted_format: any_of(My.Format, %My.Another.Format{field: :strict_value}, My.Yet.Another.Format)
```

## Update options definitions

This section applies to options defined via `def_options` macro and pad options defined in `def_input_pad` or `def_output_pad`.

___

Remove `:type` key and related value from the options definitions. Add `:spec` instead, if it hasn't been added before, and proper `:inspector`, if the option has a default value, that shouldn't be inspected by `inspect/1` during generating docs.

```diff 
- def_options tick_interval: [
-                 type: :time, 
-                 default: Membrane.Time.seconds(1)
-             ],
-             process: [
-                 type: :pid
-             ]
+ def_options tick_interval: [
+                 spec: Membrane.Time.t(),
+                 default: Membrane.Time.seconds(1),
+                 inspector: &Membrane.Time.inspect/1
+             ],
+             process: [
+                 spec: pid()
+             ] 
```

## Membrane.Time functions

Rename `Membrane.Time.to_<unit name>/1` into `Membrane.Time.round_to_<unit name>/1`:
```diff
- rounded_time = Membrane.Time.to_seconds(time)
+ rounded_time = Membrane.Time.round_to_seconds(time)
```

## Update the children definitions
Children definitions syntax (previously known as `ParentSpec`, after the name of a structure used to define children), that was used in `Membrane.Pipeline.Action.spec_t` and `Membrane.Bin.Action.spec_t` actions, has changed. 
Since there are quite a few changes concerning children definition, we have decided to present them in the subsections below.

### Update children names
We have restricted the available names for the children. Previously, the children name could be of `any()` type, now it is specified as follows: `tuple() | atom()`.
In case you have used a child name that does not match the new children names specification, you can wrap that name into a tuple, i.e.:
```diff
- child_name = [:why_would, :i_use, :a_list, :as_a, :child_name?]
+ child_name = {:child_name, [:why_would, :i_use, :a_list, :as_a, :child_name?]}
```

### Update the children and links definition
Rename the following function calls:
* `Membrane.ParentSpec.link/1` -> `Membrane.ChildrenSpec.get_child/1`
* `Membrane.ParentSpec.link/2` -> `Membrane.ChildrenSpec.child/2`
* `Membrane.ParentSpec.link_bin_input/1` -> `Membrane.ChildrenSpec.bin_input/1`
* `Membrane.ParentSpec.to/2` -> `Membrane.ChildrenSpec.get_child/2`
* `Membrane.ParentSpec.to/3` -> `Membrane.ChildrenSpec.child/4`
* `Membrane.ParentSpec.to_bin_output/2` -> `Membrane.ChildrenSpec.bin_output/2`

```diff
- import Membrane.ParentSpec
- children = %{source: SomeSource, filter: SomeFilter}
- links = [link(:source) |> to(:another_filter, SomeFilter) |> to(:filter) |> to(:sink, SomeSink)]
+ import Membrane.ChildrenSpec
+ structure = [
+   child(:source, SomeSource),
+   child(:filter, SomeFilter),
+   get_child(:source) |> child(:another_filter, SomeFilter) |> get_child(:filter) |> child(:sink, SomeSink)
+ ]
```

### Substitute the `Membrane.ParentSpec` structure with a tuple 
`%Membrane.ParentSpec{children: children, links: links, options...}` should be changed into `{structure, options...}` with the `children` and `links` defined as
described in the step above. Note, that there is no distinguishement between `children` and `links` - 
the children and links can be concatenated, so in case you have a separate `children` and `links` lists, simply merge them.

```diff
- spec = %Membrane.ParentSpec{children: children, links: links, node: another_node, log_metadata: metadata}
+ spec = {structure, node: another_node, log_metadata: metadata}
```

Below there is an example that aggregates the changes that need to be done to concerning the `:spec` action preparation: 
```diff
- children = %{source: SomeSource, filter: SomeFilter}
- links = [link(:source) |> to(:another_filter, SomeFilter) |> to(:filter) |> to(:sink, SomeSink)]
- spec = Membrane.ParentSpec{children: children, links: links, crash_group: {:first_group, :temporary}, node: another_node}
+ structure = [
+   child(:source, SomeSource),
+   child(:filter, SomeFilter),
+   get_child(:source) |> child(:another_filter, SomeFilter) |> get_child(:filter) |> child(:sink, SomeSink)
  ]
+ spec = {structure, crash_group: {:first_group, :temporary}, node: another_node}
- {{:ok, spec: spec}, %{}}
+ {[spec: spec], %{}}
```

## Testing

Instead of using `Membrane.Testing.Pipeline.start_link/1`, use `Membrane.Testing.Pipeline.start_link_supervised!/1`
```diff
- {:ok, pipeline} = Membrane.Testing.Pipeline.start_link(options)
+ pipeline = Membrane.Testing.Pipeline.start_link_supervised!(options)
+ # The pipeline will be shut down at the end of the test.
```
___

The `Membrane.Testing.Pipeline.options()` has also changed - now there is no more separate `:links` and `:children` fields. Instead, you need to
use a `:structure` field:
```diff
- {:ok, pipeline} = Membrane.Testing.Pipeline.start_link(children: children, links: links)
+ {:ok, pipeline} = Membrane.Testing.Pipeline.start_link(structure: structure)
```

___

In order to wait for the `Membrane.Testing.Pipeline` to get into the `:playing` playback, use `assert_pipeline_play/2` instead of `assert_pipeline_playback_changed/4`:

```diff
- assert_pipeline_playback_changed(pipeline, :prepared, :playing)
+ assert_pipeline_play(pipeline)
```