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
.
Update membrane_core
to v1.0.0
defp deps do
[
{:membrane_core, "~> 1.0.0"},
...
]
end
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
@impl true
- def handle_process(pad, buffer, ctx, state) do
+ def handle_buffer(pad, buffer, ctx, state) do
...
end
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
.
@impl true
- def handle_process_list(pad_ref, buffers_list, ctx, state) do
+ def handle_buffer(pad_ref, buffer, ctx, state) do
...
end
@impl true
- def handle_write_list(pad_ref, buffers_list, ctx, state) do
+ def handle_buffer(pad_ref, buffer, ctx, state) do
...
end
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 t:Membrane.Pad.element_spec/0
for details.
Now, if definition of pad in element does specify type of
Now, the default value of flow_control
option in def_input_pad
and def_output_pad
in Elements is :auto
. Until v0.12.9
, pads that sepcified neither flow_control
, mode
nor demand_mode
explicitly would have :manual
flow_control
. Therefore, :manual
pads that haven't specified flow_control
value, now have to do it explicitly.
- def_output_pad :output, accepted_format: %MyStruct{field: :value}
+ def_output_pad :output, accepted_format: %MyStruct{field: :value}, flow_control: :manual
- def_input_pad :input, accepted_format: %MyStruct{field: :value}, demand_unit: :buffers
+ def_input_pad :input, accepted_format: %MyStruct{field: :value}, demand_unit: :buffers, flow_control: :manual
Moreover, you can remove flow_control: :auto
from the pad definitions, if you want to.
- def_input_pad :input, accepted_format: %MyStruct{field: :value}, flow_control: :auto
+ def_input_pad :input, accepted_format: %MyStruct{field: :value}
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.
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 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.
- 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
- 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.
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.
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
.