Packages
membrane_core
1.2.0-rc1
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.7
1.2.6
1.2.5
retired
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.2.0-rc1
1.1.2
1.1.1
1.1.0
1.1.0-rc1
1.1.0-rc0
1.0.1
1.0.0
1.0.0-rc1
1.0.0-rc0
0.12.9
0.12.8
0.12.7
0.12.6
0.12.5
0.12.4
0.12.3
0.12.2
0.12.1
0.12.0
retired
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.2
0.10.1
0.10.0
0.9.0
0.8.2
0.8.1
0.8.0
0.7.0
0.6.1
0.6.0
0.5.3
0.5.2
0.5.1
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.2
0.2.1
0.2.0
0.1.1
0.1.0
Membrane Multimedia Framework (Core)
Current section
Files
Jump to
Current section
Files
lib/membrane/core/timer.ex
defmodule Membrane.Core.Timer do
@moduledoc false
alias Membrane.Clock
alias Membrane.Core.Message
alias Membrane.Time
require Membrane.Core.Message
@type id :: any()
@type interval :: Ratio.t() | Time.non_neg() | :no_interval
@type t :: %__MODULE__{
id: id,
interval: interval,
init_time: Time.t(),
clock: Clock.t(),
next_tick_time: Time.t(),
ratio: Clock.ratio(),
timer_ref: reference() | nil,
awaiting_message?: boolean()
}
@enforce_keys [:interval, :clock, :init_time, :id]
defstruct @enforce_keys ++
[next_tick_time: 0, ratio: Ratio.new(1), timer_ref: nil, awaiting_message?: false]
@spec start(id, interval, Clock.t()) :: t
def start(id, interval, clock) do
%__MODULE__{id: id, interval: interval, init_time: Time.monotonic_time(), clock: clock}
|> tick
end
@spec stop(t) :: :ok
def stop(%__MODULE__{interval: :no_interval}) do
:ok
end
def stop(%__MODULE__{timer_ref: timer_ref}) do
_time_left = Process.cancel_timer(timer_ref)
:ok
end
@spec update_ratio(t, Clock.ratio()) :: t
def update_ratio(timer, ratio) do
%__MODULE__{timer | ratio: ratio}
end
@spec handle_message_arrived(t) :: t
def handle_message_arrived(%__MODULE__{awaiting_message?: true} = timer) do
%{timer | awaiting_message?: false}
end
@spec tick(t) :: t
def tick(%__MODULE__{} = timer)
when timer.awaiting_message? or timer.interval == :no_interval do
timer
end
def tick(timer) do
%__MODULE__{
id: id,
interval: interval,
init_time: init_time,
next_tick_time: next_tick_time,
ratio: ratio
} = timer
next_tick_time = Ratio.add(Ratio.new(next_tick_time), Ratio.new(interval))
# Next tick time converted to BEAM clock time
beam_next_tick_time =
Ratio.add(Ratio.new(init_time), Ratio.div(next_tick_time, ratio))
|> Ratio.floor()
|> Time.as_milliseconds(:round)
timer_ref =
Process.send_after(self(), Message.new(:timer_tick, id), beam_next_tick_time, abs: true)
%__MODULE__{
timer
| next_tick_time: next_tick_time |> Ratio.floor(),
timer_ref: timer_ref,
awaiting_message?: true
}
end
@spec set_interval(t, interval) :: t
def set_interval(%__MODULE__{interval: :no_interval} = timer, interval) do
%__MODULE__{timer | interval: interval}
|> tick()
end
def set_interval(timer, interval) do
%__MODULE__{timer | interval: interval}
end
end