View Source Upgrading to v1.0.0-rc0

Between v0.11 and v1.0.0-rc0 some breaking changes have occurred, so here comes the guide that will help you adjust your code to the new API. See the changelog for detailed description of the changes.

Deps upgrade

Update membrane_core to v1.0.0-rc0

defp deps do
   [
     {:membrane_core, "~> 1.0.0-rc0"},
     ...
   ]
end

Remove the pipeline's :playback action

There is no more :playback action available, as the pipeline will start playing automatically once its setup is completed. If you need to start the pipeline as soon as possible, simply do not return the :playback action in Membrane.Pipeline.handle_init/2 or Membrane.Pipeline.handle_setup/2 callbacks:

@impl true
def handle_setup(_ctx, state) do
  ...
- {[playback: :playing], state}
+ {[], state}
end

In case you need to defer the moment the pipeline starts playing, and for this purpose you have returned :playback action in some other callback than handle_init or handle_setup, now you need to do two things - first, mark the setup as incomplete with Membrane.Pipeline.Action.setup/0 action returned from handle_setup, to prevent it from automatically changing the playback to :playing:

+ @impl true
+ def handle_setup(_ctx, state) do
+   {[setup: :incomplete], state}
+ end

Then, you need to return setup: :complete instead of playback: :playing action in a callback after which completion you want your pipeline to start playing:

@impl true
def handle_info(:now_start_playing, _ctx, state) do
...
- {[playback: playing], state}
+ {[setup: :complete], state}
end

Note that the :setup action is also available in elements and bins and its main purpose is to handle long, asynchronous initialization of a component. See Membrane.Bin.Action.setup/0 and Membrane.Element.Action.setup/0.

Rename handle_process and handle_write into handle_buffer

Names of the callbacks that are used to process buffers have been unified. This applies to:

  • Membrane.Filter.handle_process/4 and Membrane.Filter.handle_process_list/4
  • Membrane.Endpoint.handle_write/4 and Membrane.Endpoint.handle_write_list/4
  • Membrane.Sink.handle_write/4 and Membrane.Sink.handle_write_list/4

and they became Membrane.Element.WithInputPads.handle_buffer/4 and Membrane.Element.WithInputPads.handle_buffers_batch/4, respectively:

  @impl true
- def handle_process(pad, buffer, ctx, state) do
+ def handle_buffer(pad, buffer, ctx, state) do
    ...
  end
  @impl true
- def handle_process_list(pad, buffers, ctx, state) do
+ def handle_buffers_batch(pad, buffers, ctx, state) do
    ...
  end

Change mode and demand_mode options to flow_control in pads' definitions in elements

For input pads, change:

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:

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 Membrane.Pad.element_spec/0 for details.

Remove mode and demand_unit from pads definitions in bins

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 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:

@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.

@impl true
- def handle_pad_added(_pad, %{direction: :input}, state) do
+ def handle_pad_added(Pad.ref(:input, _id), _ctx, state) do
  ...
end

Check Membrane.Element.CallbackContext.t/0, Membrane.Bin.CallbackContext.t/0 and 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

- pipeline = Membrane.RemoteControlled.Pipeline.start_link!()
+ pipeline = Membrane.RCPipeline.start_link!()

Same goes for Membrane.RemoteControlled.Message -> Membrane.RCMessage

receive do
- %Membrane.RemoteControlled.Message.Notification{data: data} -> data
+ %Membrane.RCMessage.Notification{data: data} -> data
end

Use Membrane.Time.as_<unit>(time, :round) instead of Membrane.Time.round_to_<unit>(time)

- 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:

- Membrane.Time.round_to_timebase(time, timebase)
+ Membrane.Time.divide_by_timebase(time, timebase)

Check Membrane.Time for details.

Remove _t suffix when referring to Membrane types

- Membrane.Pad.ref_t()
+ Membrane.Pad.ref()