Skip to content

Make demand action accept timestamps & write manual timestamps guide#1079

Merged
FelonEkonom merged 53 commits intomasterfrom
time-on-demands
Apr 22, 2026
Merged

Make demand action accept timestamps & write manual timestamps guide#1079
FelonEkonom merged 53 commits intomasterfrom
time-on-demands

Conversation

@FelonEkonom
Copy link
Copy Markdown
Member

@FelonEkonom FelonEkonom commented Feb 25, 2026

Closes #1072
Closes #1081

@FelonEkonom FelonEkonom changed the title Demand in timestamps Make demand action accept timestamps Feb 25, 2026
@FelonEkonom FelonEkonom self-assigned this Mar 9, 2026
@FelonEkonom FelonEkonom changed the title Make demand action accept timestamps Make demand action accept timestamps, write manual timestamps guide Mar 9, 2026
@FelonEkonom FelonEkonom marked this pull request as ready for review March 9, 2026 15:10
@FelonEkonom FelonEkonom requested a review from mat-hek as a code owner March 9, 2026 15:10
@FelonEkonom FelonEkonom marked this pull request as draft March 9, 2026 15:12
@FelonEkonom FelonEkonom requested review from mat-hek and varsill April 15, 2026 10:46
Comment thread lib/membrane/buffer/metric.ex Outdated
Comment on lines +18 to +22
[%Buffer{}] | [],
non_neg_integer | Membrane.Time.t(),
first_consumed_buffer :: Buffer.t() | nil,
last_consumed_buffer :: Buffer.t() | nil
) :: {[%Buffer{}] | [], [%Buffer{}] | []}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[%Buffer{}] | [],
non_neg_integer | Membrane.Time.t(),
first_consumed_buffer :: Buffer.t() | nil,
last_consumed_buffer :: Buffer.t() | nil
) :: {[%Buffer{}] | [], [%Buffer{}] | []}
[%Buffer{}],
non_neg_integer | Membrane.Time.t(),
first_consumed_buffer :: Buffer.t() | nil,
last_consumed_buffer :: Buffer.t() | nil
) :: {[%Buffer{}], [%Buffer{}]}

[first | rest] = buffers

_last =
Enum.reduce(rest, first, fn
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Iterating over all buffers multiple times may introduce some overhead. We do it here and in assert_non_nil_timestamps and split_timestamp_buffers. I'd do that once if possible.

Comment thread lib/membrane/core/metric.ex Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it a copy of Membrane.Core.Element.ManualFlowController.BufferMetric?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it was a leftover I missed

@FelonEkonom FelonEkonom requested a review from mat-hek April 21, 2026 16:12
Copy link
Copy Markdown
Contributor

@varsill varsill left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Comments concerning just the guide]

the demanded value.

Timestamp demand units are only applicable to **input pads with manual flow
control**. Output pads do not support them. If an input pad uses a timestamp
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean that currently it just describes the scenario when output pad's demand unit in unspecified - what if output pad's demand unit is explicitly set as :bytes (or :buffers)?


The canonical pattern for a filter with both pads using manual flow control is:

- **[`handle_demand/5`](`c:Membrane.Element.WithOutputPads.handle_demand/5`)** — propagate the demand upstream by returning a [`:demand`](`t:Membrane.Element.Action.demand/0`) action on the input pad.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's mention that demand might be modified (just as it's multiplied by 2 in the example below)

### Redemand

Sometimes producing all demanded buffers at once is not possible or not
desired — for example when the element generates one buffer at a time. In that
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"when the element generates one buffer at a time" - it's a little bit obscure to me, do you mean: "the previous element"?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBH in my mind the element generates one buffer at a time is the same as the one that receives demand, you can think about Membrane.Source scenario

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have rephrased the sentence so maybe now it will sound better

Comment on lines +88 to +92
desired — for example when the element generates one buffer at a time. In that
case, return the [`:redemand`](`t:Membrane.Element.Action.redemand/0`) action
alongside the buffer. Membrane will then invoke
[`handle_demand/5`](`c:Membrane.Element.WithOutputPads.handle_demand/5`) again
with the demand reduced by the size of what was just sent.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about this one?
I think that concerning "we shouldn't return :redemand from handle_demand in Filters" - you can add a tiny note at the end of the "## Filters with manual flow control" section

@varsill varsill self-requested a review April 22, 2026 07:53
@FelonEkonom
Copy link
Copy Markdown
Member Author

FelonEkonom commented Apr 22, 2026

@varsill IDK why but for some reason I cannot reply to some of your comments

How about this one?
I think that concerning "we shouldn't return :redemand from handle_demand in Filters" - you can add a tiny note at the end of the "## Filters with manual flow control" section

There is already #### Do not use redemand in a filter's handle_demand {: .warning} in line 475

I mean that currently it just describes the scenario when output pad's demand unit in unspecified - what if output pad's demand unit is explicitly set as :bytes (or :buffers)?

I tried to add this information to this paragrapgh with Claude, but it is hard to me to figure out how to mention that information in this place without interrupting the paragragraph flow. If you have any specific commit suggestion, you can tell me

Comment thread lib/membrane/buffer/metric/byte_size.ex Outdated
Comment thread lib/membrane/buffer/metric.ex
Comment thread lib/membrane/core/child/pads_specs.ex Outdated
Comment thread lib/membrane/core/child/pads_specs.ex Outdated
Comment thread lib/membrane/pad.ex Outdated
Comment thread lib/membrane/core/element/manual_flow_controller/buffer_metric.ex Outdated
Comment thread lib/membrane/core/element/manual_flow_controller/buffer_metric.ex Outdated

# ---------------------------------------------------------------------------
# Private helpers
# ---------------------------------------------------------------------------
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like the fact that we dispatch do_split_buffers to do_split_bytes and do_split_timestamp_buffers - these functions split buffers based on demand unit, so I would call them: do_split_buffers_by_bytesize and do_split_buffers_by_timestamp

Comment on lines +198 to +200
Demanding a #{timestamp_name(unit)} that is not greater than the elapsed one \
won't result in handling any further buffers, until the element demands a #{timestamp_name(unit)} \
greater than the elapsed one. \
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the same information is repeated twice in this sentence

Comment on lines +209 to +212
This may lead to unexpected behavior in elements that have input pad with flow \
control set to `:manual` and demand unit set to `:timestamp`, `{:timestamp, :dts}` \
`{:timestamp, :pts}` or `{:timestamp, :dts_or_pts}`.
Pad reference: #{inspect(pad_ref)}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to say that it might lead to unexpacted behaviour in "input pad with flow
control set to :manual and demand unit set to :timestamp, {:timestamp, :dts}
{:timestamp, :pts} or {:timestamp, :dts_or_pts}. " since we are already talking about a very specific pad with such timestamp demand unit?

@FelonEkonom FelonEkonom requested a review from varsill April 22, 2026 13:49
Comment thread lib/membrane/core/child/pads_specs.ex Outdated
accepted_formats_str: [],
flow_control: flow_control_spec(direction, component),
flow_control: flow_control_spec_constraints(direction, component),
demand_unit: demand_unit_spec(direction, component),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same for others i.e. demand_unit_spec_constraints and max_instances_spec_constraints

@FelonEkonom FelonEkonom merged commit 87f95b7 into master Apr 22, 2026
5 of 6 checks passed
@FelonEkonom FelonEkonom deleted the time-on-demands branch April 22, 2026 14:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Guide about manual demands Time on demands, demands on time 🤔

3 participants