Packages
membrane_rtc_engine
0.25.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/bitrate_estimator.ex
defmodule Membrane.RTC.Engine.BitrateEstimator do
@moduledoc false
alias Membrane.RTC.Engine.Track.BitrateEstimation
alias Membrane.{Buffer, Time}
@enforce_keys [:last_estimation_time]
defstruct @enforce_keys ++
[
sizes: []
]
@opaque t() :: %__MODULE__{
sizes: [{integer(), non_neg_integer()}],
last_estimation_time: integer()
}
@spec new() :: t()
def new() do
%__MODULE__{
last_estimation_time: get_timestamp()
}
end
@spec process(t(), Buffer.t()) :: t()
def process(state, buffer) do
entry = byte_size(buffer.payload) * 8
Map.update!(state, :sizes, &[entry | &1])
end
@spec estimate(t()) :: {:ok, BitrateEstimation.t(), t()} | {:error, :not_enough_data}
def estimate(state) do
start = state.last_estimation_time
stop = get_timestamp()
duration = Time.as_seconds(stop - start)
cond do
duration == 0 ->
{:error, :not_enough_data}
state.sizes == [] ->
estimation = %BitrateEstimation{estimation: 0, error: 0}
{:ok, estimation, %{state | last_estimation_time: stop}}
true ->
estimation = %BitrateEstimation{
estimation:
state.sizes
|> Enum.sum()
|> Ratio.new(duration)
|> Ratio.to_float(),
error:
state.sizes
|> Statistics.stdev()
|> then(&(&1 * length(state.sizes)))
|> Ratio.new(duration)
|> Ratio.to_float()
}
{:ok, estimation, %{state | last_estimation_time: stop, sizes: []}}
end
end
defp get_timestamp(), do: :millisecond |> System.monotonic_time() |> Time.milliseconds()
end