diff --git a/guides/upgrading/v1.0.0.md b/guides/upgrading/v1.0.0.md new file mode 100644 index 000000000..6d484d4a8 --- /dev/null +++ b/guides/upgrading/v1.0.0.md @@ -0,0 +1,181 @@ +# Upgrading to v1.0.0 + +Comparing to v0.12, v1.0.0 introduces some minor changes in the public API of the framework. This guide was created to help you migrate to v1.0.0 of `membrane_core`. + +### Deps + +Update `membrane_core` to `v1.0.0` +```elixir +defp deps do + [ + {:membrane_core, "~> 1.0.0"}, + ... + ] +end +``` + +### Rename `handle_process/4` and `handle_write/4` into `handle_buffer/4` + +Names of the callbacks that are used to process buffers have been unified. This applies to: +* _Membrane.Filter.handle_process/4_ +* _Membrane.Endpoint.handle_write/4_ +* _Membrane.Sink.handle_write/4_ + +and they became `c:Membrane.Element.WithInputPads.handle_buffer/4` + +```diff + @impl true +- def handle_process(pad, buffer, ctx, state) do ++ def handle_buffer(pad, buffer, ctx, state) do + ... + end +``` + +### Remove `handle_process_list/4` and `handle_write_list/4` callback + +Since `v1.0.0`, you have to handle every single buffer separately in `handle_buffer/4` callback, instead of handling whole list of buffers in this in `handle_process_list/4` or `handle_write_list/4`. + +```diff +@impl true +- def handle_process_list(pad_ref, buffers_list, ctx, state) do ++ def handle_buffer(pad_ref, buffer, ctx, state) do + ... +end +``` + +```diff +@impl true +- def handle_write_list(pad_ref, buffers_list, ctx, state) do ++ def handle_buffer(pad_ref, buffer, ctx, state) do + ... +end +``` + +### Change `mode` and `demand_mode` options to `flow_control` in pads' definitions in elements + +For input pads, change: + +```diff +use Membrane.Filter +# or Sink or Endpoint + +- def_input_pad :input, mode: :push, ... ++ def_input_pad :input, flow_control: :push, ... + +- def_input_pad :input, mode: :pull, demand_mode: :auto, demand_unit: :buffers, ... ++ def_input_pad :input, ... +# (because `flow_control: :auto` is the default whenever available - currently in Filters) +# Note that having `flow_control: :auto` doesn't allow to pass `demand_unit`, +# as it's determined automatically + +- def_input_pad :input, mode: :pull, demand_unit: :buffers, ... ++ def_input_pad :input, flow_control: :manual, demand_unit: :buffers, ... +``` + +Same goes for output pads: + +```diff +use Membrane.Filter +# or Source or Endpoint + +- def_output_pad :output, mode: :push, ... ++ def_output_pad :output, flow_control: :push, ... + +- def_output_pad :output, mode: :pull, demand_mode: :auto, ... ++ def_output_pad :output, ... + +- def_output_pad :output, mode: :pull, ... ++ def_output_pad :output, flow_control: :manual, ... +``` + +Check `t:Membrane.Pad.element_spec/0` for details. + +### Remove `mode` and `demand_unit` from pads definitions in bins + +```diff +use Membrane.Bin + +- def_input_pad :input, mode: :pull, demand_unit: :buffers, ... ++ def_input_pad :input, ... + +- def_output_pad :output, mode: :push, ... ++ def_output_pad :output, ... +``` + +Check `t:Membrane.Pad.bin_spec/0` for details. + +### Don't refer to callback contexts as to structs + +Callback contexts are now plain maps instead of structs. So, for example, if you happen to have a match like below, convert it to a match on a map: + +```diff +@impl true +- def handle_info(message, %Membrane.Element.CallbackContext.Info{pads: pads}, state) do ++ def handle_info(message, %{pads: pads}, state) do + ... +end +``` + +Additionally, there's no `direction` field anymore in the callback context for `handle_pad_added` and `handle_pad_removed` - the direction can be determined by the pad name. All other fields remain the same. + +```diff +@impl true +- def handle_pad_added(_pad, %{direction: :input}, state) do ++ def handle_pad_added(Pad.ref(:input, _id), _ctx, state) do + ... +end +``` + +Check `t:Membrane.Element.CallbackContext.t/0`, `t:Membrane.Bin.CallbackContext.t/0` and `t:Membrane.Pipeline.CallbackContext.t/0` for outline of what can be found in the contexts. Additionally, each callback that provides extra fields in the context, has them mentioned in its docs. + +### Use `Membrane.RCPipeline` instead of `Membrane.RemoteControlled.Pipeline` + +```diff +- pipeline = Membrane.RemoteControlled.Pipeline.start_link!() ++ pipeline = Membrane.RCPipeline.start_link!() +``` + +Same goes for `Membrane.RemoteControlled.Message` -> `Membrane.RCMessage` + +```diff +receive do +- %Membrane.RemoteControlled.Message.Notification{data: data} -> data ++ %Membrane.RCMessage.Notification{data: data} -> data +end +``` + +### Use `Membrane.Time.as_(time, :round)` instead of `Membrane.Time.round_to_(time)` + +```diff +- Membrane.Time.round_to_milliseconds(time) ++ Membrane.Time.as_milliseconds(time, :round) +``` + +There is one exception for `round_to_timebase`, which changed to `divide_by_timebase`: +```diff +- Membrane.Time.round_to_timebase(time, timebase) ++ Membrane.Time.divide_by_timebase(time, timebase) +``` + +Check `Membrane.Time` for details. + +### Implement you own `start/*`, `start_link/*` or `terminate/1` function (if you want to) + +Until `v1.0.0-rc0` and `v0.12`, Membrane has generated `start/2`, `start_link/2`, and `terminate/1` functions in modules using `Membrane.Pipeline`, if code developer hadn't done it explicitly. Since `v1.0.0`, if you want to have these functions implemented in your pipeline module, you have to implement them on your own. Alternatively, you can always call `Membrane.Pipeline.start(YourPipelineModule, init_arg, opts)`, `Membrane.Pipeline.start_link(YourPipelineModule, init_arg, opts)`, and `Membrane.Pipeline.terminate(pipeline_pid)` from beyond `YourPipelineModule` without wrapping it into public functions. + +### Rename `:structure` option passed to the `Membrane.Testing.Pipeline` into `:spec` + +```diff +import Membrane.ChildrenSpec + +spec = + child(:source, %Membrane.Testing.Source{some_field: some_arg}) + |> child(:sink), %Membrane.Testing.Sink{another_filed: another_arg} + +- pipeline = Membrane.Testing.Pipeline.start_link_supervised(structure: spec) ++ pipeline = Membrane.Testing.Pipeline.start_link_supervised(spec: spec) +``` + +### Adjust to possibility of receiving `end of stream` on pads, that haven't received `start of stream` yet. + +Since `v1.0.0`, Membrane will execute `c:Membrane.Element.WithInputPads.handle_end_of_stream/3` for all pads, including these having `start_of_stream?: false`. diff --git a/mix.exs b/mix.exs index e437091d9..2d17e3e3a 100644 --- a/mix.exs +++ b/mix.exs @@ -66,6 +66,7 @@ defmodule Membrane.Mixfile do "guides/upgrading/v0.11.md", "guides/upgrading/v1.0.0-rc0.md", "guides/upgrading/v1.0.0-rc1.md", + "guides/upgrading/v1.0.0.md", LICENSE: [title: "License"] ], formatters: ["html"],