Current section
Files
Jump to
Current section
Files
lib/reporter.ex
defmodule Membrane.RTC.Engine.Endpoint.Recording.Reporter do
@moduledoc """
Module responsible for creating report with information needed to decode recorded streams.
"""
use GenServer
alias Membrane.RTC.Engine.Track
@track_reports_keys [
:type,
:encoding,
:offset,
:start_timestamp,
:end_timestamp,
:clock_rate,
:metadata,
:origin
]
@type filename :: String.t()
@type track_report :: %{
type: Track.t(),
encoding: Track.encoding(),
offset: pos_integer(),
start_timestamp: pos_integer(),
end_timestamp: pos_integer(),
clock_rate: Membrane.RTP.clock_rate_t(),
metadata: any(),
origin: String.t()
}
@type report :: %{
recording_id: String.t(),
tracks: %{filename() => track_report()}
}
@opaque state :: %{tracks: [], recording_id: String.t()}
@spec start(String.t()) :: {:ok, pid()} | {:error, term()}
def start(recording_id) do
GenServer.start(__MODULE__, recording_id)
end
@spec add_track(pid(), Track.t(), filename(), pos_integer()) :: :ok
def add_track(reporter, track, filename, timestamp) do
track = Map.put(track, :offset, timestamp)
GenServer.cast(reporter, {:add_track, track, filename})
end
@spec start_timestamp(pid(), Track.id(), pos_integer()) :: :ok
def start_timestamp(reporter, track_id, start_timestamp) do
GenServer.cast(reporter, {:start_timestamp, track_id, start_timestamp})
end
@spec end_timestamp(pid, Track.id(), pos_integer()) :: :ok
def end_timestamp(reporter, track_id, end_timestamp) do
GenServer.cast(reporter, {:end_timestamp, track_id, end_timestamp})
end
@spec get_report(pid()) :: report()
def get_report(reporter) do
GenServer.call(reporter, :get_report)
end
@spec stop(pid()) :: :ok
def stop(reporter) do
GenServer.stop(reporter)
end
@impl true
def init(recording_id) do
{:ok, %{recording_id: recording_id, tracks: %{}}}
end
@impl true
def handle_cast({:add_track, track, filename}, state) do
state = put_in(state[:tracks][track.id], {filename, track})
{:noreply, state}
end
@impl true
def handle_cast({:start_timestamp, track_id, start_timestamp}, state) do
state =
update_in(state[:tracks][track_id], fn {filename, track} ->
track =
track
|> Map.put(:start_timestamp, start_timestamp)
|> Map.put(:end_timestamp, start_timestamp)
{filename, track}
end)
{:noreply, state}
end
@impl true
def handle_cast({:end_timestamp, track_id, end_timestamp}, state) do
state =
update_in(state[:tracks][track_id], fn {filename, track} ->
{filename, Map.put(track, :end_timestamp, end_timestamp)}
end)
{:noreply, state}
end
@impl true
def handle_call(:get_report, _from, state) do
tracks_report =
state.tracks
|> Map.values()
|> Enum.reject(fn {_filename, track} ->
is_nil(track[:start_timestamp]) or is_nil(track[:end_timestamp])
end)
|> Map.new(fn {filename, track} ->
{filename, Map.take(track, @track_reports_keys)}
end)
report = %{recording_id: state.recording_id, tracks: tracks_report}
{:reply, report, state}
end
end