Packages
membrane_core
0.12.2
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_controller.ex
defmodule Membrane.Core.TimerController do
@moduledoc false
use Bunch
alias Membrane.Clock
alias Membrane.Core.{CallbackHandler, Component, Timer}
require Membrane.Core.Component
defguardp is_timer_present(timer_id, state)
when is_map_key(state.synchronization.timers, timer_id)
@spec start_timer(Timer.id(), Timer.interval(), Clock.t(), Component.state()) ::
Component.state()
def start_timer(id, _interval, _clock, state) when is_timer_present(id, state) do
raise Membrane.TimerError, "Timer #{inspect(id)} already exists"
end
def start_timer(id, interval, clock, state) do
clock |> Clock.subscribe()
timer = Timer.start(id, interval, clock)
put_in(state, [:synchronization, :timers, id], timer)
end
@spec timer_interval(Timer.id(), Timer.interval(), Component.state()) ::
Component.state()
def timer_interval(id, interval, state) do
with {:ok, timer} <- state.synchronization.timers |> Map.fetch(id) do
put_in(
state,
[:synchronization, :timers, id],
Timer.set_interval(timer, interval)
)
else
:error -> raise Membrane.TimerError, "Timer #{inspect(id)} doesn't exist"
end
end
@spec stop_all_timers(Component.state()) :: Component.state()
def stop_all_timers(state) do
for {_id, timer} <- state.synchronization.timers do
stop_and_unsubscribe(timer)
end
Bunch.Access.put_in(state, [:synchronization, :timers], %{})
end
@spec stop_timer(Timer.id(), Component.state()) :: Component.state()
def stop_timer(id, state) do
{timer, state} = state |> Bunch.Access.pop_in([:synchronization, :timers, id])
if timer |> is_nil do
raise Membrane.TimerError, "Timer #{inspect(id)} doesn't exist"
else
stop_and_unsubscribe(timer)
state
end
end
@spec handle_tick(Timer.id(), Component.state()) :: Component.state()
def handle_tick(timer_id, state) when is_timer_present(timer_id, state) do
state =
CallbackHandler.exec_and_handle_callback(
:handle_tick,
Component.action_handler(state),
%{context: &Component.context_from_state/1},
[timer_id],
state
)
# in case the timer was removed in handle_tick
if is_timer_present(timer_id, state) do
update_in(state, [:synchronization, :timers, timer_id], &Timer.tick/1)
else
state
end
end
def handle_tick(_timer_id, state) do
state
end
@spec handle_clock_update(Timer.id(), Clock.ratio(), Component.state()) ::
Component.state()
def handle_clock_update(clock, ratio, state) do
update_in(
state,
[:synchronization, :timers],
&Bunch.Map.map_values(&1, fn
%Timer{clock: ^clock} = timer -> timer |> Timer.update_ratio(ratio)
timer -> timer
end)
)
end
@spec stop_and_unsubscribe(Timer.t()) :: :ok
defp stop_and_unsubscribe(timer) do
Timer.stop(timer)
Clock.unsubscribe(timer.clock)
end
end