Current section
Files
Jump to
Current section
Files
lib/membrane/live_compositor/context.ex
defmodule Membrane.LiveCompositor.Context do
@moduledoc """
Context of LiveCompositor. Specifies LiveCompositor inputs and outputs.
"""
require Membrane.Pad
alias Membrane.LiveCompositor
alias Membrane.Pad
defstruct video_inputs: [], audio_inputs: [], video_outputs: [], audio_outputs: []
@typedoc """
Context of LiveCompositor. Specifies LiveCompositor inputs and outputs.
"""
@type t :: %__MODULE__{
video_inputs: list(LiveCompositor.input_id()),
audio_inputs: list(LiveCompositor.input_id()),
video_outputs: list(LiveCompositor.output_id()),
audio_outputs: list(LiveCompositor.output_id())
}
@doc false
@spec add_stream(Pad.ref(), t()) :: t()
def add_stream(Pad.ref(pad_type, id), ctx = %__MODULE__{}) do
if !String.valid?(id) do
raise """
All LiveCompositor pads need to be defined as `Pad.ref(pad_name, pad_id)`
where `pad_id` is a string.
"""
end
# Don't optimize this with [%State.Input{...} | inputs]
# Adding this at the beginning is O(1) instead of O(N),
# but this way this list is always ordered by insert order.
# Since this list should be small, preserving order with O(N) is better
# (order is preserved in returned VC context, state is more consistent etc.)
case pad_type do
:video_input ->
ensure_no_inputs_with_id(id, ctx)
%__MODULE__{ctx | video_inputs: ctx.video_inputs ++ [id]}
:audio_input ->
ensure_no_inputs_with_id(id, ctx)
%__MODULE__{ctx | audio_inputs: ctx.audio_inputs ++ [id]}
:video_output ->
ensure_no_outputs_with_id(id, ctx)
%__MODULE__{ctx | video_outputs: [id | ctx.video_outputs]}
:audio_output ->
ensure_no_outputs_with_id(id, ctx)
%__MODULE__{ctx | audio_outputs: [id | ctx.audio_outputs]}
end
end
@doc false
@spec remove_input(LiveCompositor.input_id(), t()) :: t()
def remove_input(input_id, ctx = %__MODULE__{audio_inputs: audio, video_inputs: video}) do
audio = audio |> Enum.reject(fn id -> input_id == id end)
video = video |> Enum.reject(fn id -> input_id == id end)
%__MODULE__{ctx | audio_inputs: audio, video_inputs: video}
end
@doc false
@spec remove_output(LiveCompositor.output_id(), t()) :: t()
def remove_output(output_id, ctx = %__MODULE__{audio_outputs: audio, video_outputs: video}) do
audio = audio |> Enum.reject(fn id -> output_id == id end)
video = video |> Enum.reject(fn id -> output_id == id end)
%__MODULE__{ctx | audio_outputs: audio, video_outputs: video}
end
defp get_input(input_id, ctx) do
ctx.audio_inputs |> Enum.find(fn id -> input_id == id end) ||
ctx.video_inputs |> Enum.find(fn id -> input_id == id end)
end
defp ensure_no_inputs_with_id(input_id, ctx) do
input = get_input(input_id, ctx)
if input != nil do
raise """
You can only register one input at the time with a specific id. Input pad
with id "#{input_id}" was already connected.
"""
end
end
defp get_output(output_id, ctx) do
ctx.audio_outputs |> Enum.find(fn id -> output_id == id end) ||
ctx.video_outputs |> Enum.find(fn id -> output_id == id end)
end
defp ensure_no_outputs_with_id(output_id, ctx) do
output = get_output(output_id, ctx)
if output != nil do
raise """
You can only register one output at the time with a specific id. Output pad
with id "#{output_id}" was already connected.
"""
end
end
end