-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement soft corcking #586
Changes from 6 commits
0e43d19
858c2bf
513f490
72b7bc5
0e1b518
318fa17
db97e77
cc7dad6
177341e
d918e12
c8707b9
a863b81
ee3860a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
varsill marked this conversation as resolved.
Show resolved
Hide resolved
|
varsill marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -11,6 +11,8 @@ defmodule Membrane.Integration.DemandsTest do | |||||
alias Membrane.Testing | ||||||
alias Membrane.Testing.{Pipeline, Sink, Source} | ||||||
|
||||||
require Membrane.Pad, as: Pad | ||||||
|
||||||
defp assert_buffers_received(range, pid) do | ||||||
Enum.each(range, fn i -> | ||||||
assert_sink_buffer(pid, :sink, %Buffer{payload: <<^i::16>> <> <<255>>}) | ||||||
|
@@ -149,14 +151,16 @@ defmodule Membrane.Integration.DemandsTest do | |||||
def sleep_time(), do: @sleep_time | ||||||
|
||||||
@impl true | ||||||
def handle_playing(_ctx, state) do | ||||||
{[stream_format: {:output, %StreamFormat{}}], state} | ||||||
def handle_playing(_ctx, _default_state) do | ||||||
{[stream_format: {:output, %StreamFormat{}}], %{counter: 0}} | ||||||
end | ||||||
|
||||||
@impl true | ||||||
def handle_demand(:output, _size, _unit, _ctx, state) do | ||||||
Process.sleep(@sleep_time) | ||||||
{[buffer: {:output, %Membrane.Buffer{payload: ""}}, redemand: :output], state} | ||||||
|
||||||
actions = [buffer: {:output, %Membrane.Buffer{payload: state.counter}}, redemand: :output] | ||||||
{actions, Map.update!(state, :counter, &(&1 + 1))} | ||||||
end | ||||||
end | ||||||
|
||||||
|
@@ -198,12 +202,14 @@ defmodule Membrane.Integration.DemandsTest do | |||||
Process.sleep(500) | ||||||
|
||||||
for _i <- 1..10 do | ||||||
# during sleep below source should send about 100 buffers | ||||||
# during sleep below source should send around 100 buffers | ||||||
Process.sleep(100 * RedemandingSource.sleep_time()) | ||||||
|
||||||
Testing.Pipeline.execute_actions(pipeline, notify_child: {:sink, :pause_auto_demand}) | ||||||
|
||||||
assert_pipeline_notified(pipeline, :sink, {:buff_no, buff_no}) | ||||||
# sink should receive aropund 100 buffers, but the boundary is set to 70, in case of eg. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
# slowdown of the source when running all tests in the project asynchronously | ||||||
assert buff_no > 70 | ||||||
varsill marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
# during sleep below source should send up to about auto_demand_size = 10 buffers | ||||||
|
@@ -212,9 +218,80 @@ defmodule Membrane.Integration.DemandsTest do | |||||
Testing.Pipeline.execute_actions(pipeline, notify_child: {:sink, :resume_auto_demand}) | ||||||
|
||||||
assert_pipeline_notified(pipeline, :sink, {:buff_no, buff_no}) | ||||||
# sink should probably receive between 5 and 15 buffers, but the boundary is set to 25, | ||||||
# to handle the case when eg. there is a delay in receiving the notification from the | ||||||
# pipeline by the :sink | ||||||
assert buff_no < 25 | ||||||
end | ||||||
|
||||||
Testing.Pipeline.terminate(pipeline) | ||||||
end | ||||||
|
||||||
defmodule Funnel do | ||||||
use Membrane.Filter | ||||||
|
||||||
def_input_pad :input, accepted_format: _any, flow_control: :auto, availability: :on_request | ||||||
def_output_pad :output, accepted_format: _any, flow_control: :auto | ||||||
|
||||||
def_options pads_upperbounds: [spec: map()] | ||||||
|
||||||
@impl true | ||||||
def handle_init(_ctx, %{pads_upperbounds: pads_upperbounds}) do | ||||||
{[], %{pads_upperbounds: pads_upperbounds, pads_counters: %{}}} | ||||||
end | ||||||
|
||||||
@impl true | ||||||
def handle_pad_added(pad, _ctx, state) do | ||||||
{[], put_in(state, [:pads_counters, pad], 0)} | ||||||
end | ||||||
|
||||||
@impl true | ||||||
def handle_buffer(pad, buffer, ctx, state) do | ||||||
buffer = %Membrane.Buffer{buffer | metadata: pad} | ||||||
|
||||||
{pad_counter, state} = get_and_update_in(state, [:pads_counters, pad], &{&1, &1 + 1}) | ||||||
|
||||||
pad_upperbound = Map.get(state.pads_upperbounds, pad, :infinity) | ||||||
|
||||||
actions = | ||||||
if pad_counter > pad_upperbound and not ctx.pads[pad].auto_demand_paused? do | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that |
||||||
[pause_auto_demand: pad, buffer: {:output, buffer}] | ||||||
else | ||||||
[buffer: {:output, buffer}] | ||||||
end | ||||||
|
||||||
{actions, state} | ||||||
end | ||||||
|
||||||
@impl true | ||||||
def handle_end_of_stream(_pad, ctx, state) do | ||||||
actions = | ||||||
Map.values(ctx.pads) | ||||||
|> Enum.filter(&(&1.direction == :output and not &1.end_of_stream?)) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AFAIK, there is only one pad with direction |
||||||
|> Enum.map(&{:end_of_stream, &1.ref}) | ||||||
|
||||||
{actions, state} | ||||||
end | ||||||
end | ||||||
|
||||||
test "funnel pausing auto demands on one of its pads" do | ||||||
spec = [ | ||||||
child({:source, :a}, RedemandingSource) | ||||||
|> via_in(Pad.ref(:input, :a), auto_demand_size: 10) | ||||||
|> child(:funnel, %Funnel{pads_upperbounds: %{Pad.ref(:input, :a) => 100}}) | ||||||
|> child(:sink, %Testing.Sink{autodemand: true}), | ||||||
child({:source, :b}, RedemandingSource) | ||||||
|> via_in(Pad.ref(:input, :b), auto_demand_size: 10) | ||||||
|> get_child(:funnel) | ||||||
] | ||||||
|
||||||
pipeline = Testing.Pipeline.start_link_supervised!(spec: spec) | ||||||
|
||||||
assert_sink_buffer(pipeline, :sink, %{payload: 100, metadata: Pad.ref(:input, :a)}) | ||||||
assert_sink_buffer(pipeline, :sink, %{payload: 100, metadata: Pad.ref(:input, :b)}) | ||||||
assert_sink_buffer(pipeline, :sink, %{payload: 500, metadata: Pad.ref(:input, :b)}, 8000) | ||||||
refute_sink_buffer(pipeline, :sink, %{payload: 200, metadata: Pad.ref(:input, :a)}, 5000) | ||||||
|
||||||
Testing.Pipeline.terminate(pipeline) | ||||||
end | ||||||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.