Current section

Files

Jump to
membrane_rtc_engine lib membrane_rtc_engine display_manager endpoint_manager.ex
Raw

lib/membrane_rtc_engine/display_manager/endpoint_manager.ex

defmodule Membrane.RTC.Engine.EndpointManager do
@moduledoc false
alias Membrane.RTC.Engine.Track
@enforce_keys [:id, :video_tracks_limit]
defstruct @enforce_keys ++
[
inbound_tracks: %{},
outbound_tracks: %{},
prioritized_tracks: [],
screens_sizes: %{
same_size?: true,
big_screens: nil,
small_screens: nil,
medium_screens: nil
}
]
@type id :: String.t()
@type t :: %__MODULE__{
id: id(),
inbound_tracks: %{Track.id() => Track.t()},
outbound_tracks: %{Track.id() => Track.t()},
video_tracks_limit: integer() | nil,
prioritized_tracks: [String.t()],
screens_sizes: %{
same_size?: boolean(),
big_screens: nil | integer(),
medium_screens: nil | integer(),
small_screens: nil | integer()
}
}
@doc """
Creates a new EndpointManager.
"""
@spec new(
endpoint_id :: id(),
video_tracks_limit :: integer() | nil
) :: t()
def new(endpoint_id, video_tracks_limit) do
%__MODULE__{
id: endpoint_id,
video_tracks_limit: video_tracks_limit
}
end
@spec add_tracks(
endpoint :: t(),
tracks :: [Track.t()],
type :: :inbound_tracks | :outbound_tracks
) :: t()
def add_tracks(endpoint, tracks, type) do
Map.update!(endpoint, type, &update_tracks(tracks, &1))
end
@spec remove_tracks(
endpoint :: t(),
tracks :: [Track.t()],
type :: :inbound_tracks | :outbound_tracks
) :: t()
def remove_tracks(endpoint, tracks, type) do
track_id_to_track = Map.fetch!(endpoint, type)
track_id_to_track =
Enum.reduce(tracks, track_id_to_track, fn track, acc -> Map.pop(acc, track.id) end)
Map.put(endpoint, type, track_id_to_track)
end
@spec map_audio_to_video(endpoint_manager :: t(), track_id :: Track.id()) :: [Track.t()]
def map_audio_to_video(endpoint_manager, track_id) do
if Map.has_key?(endpoint_manager.inbound_tracks, track_id) do
endpoint_manager.inbound_tracks
|> Map.values()
|> Enum.filter(&(&1.type == :video))
else
[]
end
end
@spec calculate_track_priorities(endpoint :: t(), ordered_tracks :: [Track.id()]) :: [
Track.id()
]
def calculate_track_priorities(endpoint, ordered_tracks) do
ordered_tracks =
Enum.reject(ordered_tracks, fn track ->
Map.has_key?(endpoint.inbound_tracks, track.id) or track.id in endpoint.prioritized_tracks
end)
video_tracks_limit =
if endpoint.video_tracks_limit == nil do
endpoint.outbound_tracks |> Map.values() |> Enum.count()
else
max(endpoint.video_tracks_limit - Enum.count(endpoint.prioritized_tracks), 0)
end
ordered_tracks = ordered_tracks |> Enum.take(video_tracks_limit) |> Enum.map(& &1.id)
endpoint.prioritized_tracks ++ ordered_tracks
end
@spec prioritize_track(endpoint :: t(), track_id :: Track.id()) :: t()
def prioritize_track(endpoint, track_id) do
%{endpoint | prioritized_tracks: [track_id | endpoint.prioritized_tracks]}
end
@spec unprioritize_track(endpoint :: t(), track_id :: Track.id()) :: t()
def unprioritize_track(endpoint, track_id) do
%{endpoint | prioritized_tracks: Enum.reject(endpoint.prioritized_tracks, &(&1 == track_id))}
end
@spec get_inbound_video_tracks(endpoint :: t()) :: [Track.t()]
def get_inbound_video_tracks(nil) do
[]
end
def get_inbound_video_tracks(endpoint) do
endpoint.inbound_tracks |> Map.values() |> Enum.filter(&(&1.type == :video))
end
defp update_tracks(tracks, track_id_to_track) do
Enum.reduce(tracks, track_id_to_track, fn track, acc ->
Map.put(acc, track.id, track)
end)
end
end