Packages
membrane_rtc_engine
0.3.0
0.25.0
0.24.0
0.23.0
0.22.0
0.21.0
0.20.0
0.19.0
0.18.0
0.17.1
0.17.0
0.16.0
0.15.1
0.15.0
0.14.2
0.14.1
0.14.0
0.13.0
0.12.1
0.12.0
0.11.0
0.10.3
0.10.2
0.10.1
0.10.0
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.0
0.6.0
0.5.1
0.5.0
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.0
0.1.0
0.1.0-alpha.2
0.1.0-alpha.1
0.1.0-alpha
Membrane RTC Engine and its client library
Current section
Files
Jump to
Current section
Files
lib/membrane_rtc_engine/tees/tee.ex
defmodule Membrane.RTC.Engine.Tee do
@moduledoc false
# Element for forwarding buffers to multiple output pads. If no output
# pad is linked, buffers are dropped.
# It has got built-in mechanism for limiting forwarding video buffers.
# It reads from ETS table on which pads it should forward buffers.
# Counter is used for passing a single packets once in a while.
# It is necessary for SRTP as they can update their ROCs
# based on sequence numbers and when we drop to many packets we may roll it over.
use Membrane.Filter
def_options track_id: [
spec: String.t(),
description: "Id of track for which tee was created"
],
ets_name: [
spec: String.t(),
description:
"Name of ETS table from which Tee will read to which pads it should send buffers",
default: "table"
],
type: [
spec: :audio | :video,
description: "Type of track which buffers tee is forwarding"
]
def_input_pad :input,
availability: :always,
mode: :pull,
demand_mode: :auto,
caps: :any
def_output_pad :output,
availability: :on_request,
mode: :push,
caps: :any
@impl true
def handle_init(opts) do
{:ok,
%{
ets_name: :"#{opts.ets_name}",
track_id: opts.track_id,
counter: 0,
type: opts.type,
forward_to: MapSet.new()
}}
end
@impl true
def handle_process(:input, %Membrane.Buffer{} = buffer, _ctx, %{type: :audio} = state) do
{{:ok, forward: buffer}, state}
end
@impl true
def handle_process(
:input,
%Membrane.Buffer{} = buffer,
_ctx,
%{type: :video, counter: 1000} = state
) do
{{:ok, forward: buffer}, %{state | counter: 0}}
end
@impl true
def handle_process(:input, %Membrane.Buffer{} = buffer, ctx, %{type: :video} = state) do
pads =
ctx.pads
|> Map.keys()
|> Enum.filter(fn
{Membrane.Pad, :output, {:endpoint, _endpoint_id} = endpoint_name} ->
MapSet.member?(state.forward_to, endpoint_name)
{Membrane.Pad, :output, _ref} ->
true
_other ->
false
end)
actions = Enum.map(pads, &{:buffer, {&1, buffer}})
{{:ok, actions}, %{state | counter: state.counter + 1}}
end
@impl true
def handle_other(:track_priorities_updated, _ctx, state) do
forward_to =
case :ets.lookup(state.ets_name, state.track_id) do
[{_track_id, endpoint_names} | _] ->
MapSet.new(endpoint_names)
[] ->
MapSet.new()
end
{:ok, %{state | forward_to: forward_to}}
end
end