Current section
Files
Jump to
Current section
Files
lib/metrics.ex
defmodule Membrane.RTC.Engine.Endpoint.WebRTC.Metrics do
@moduledoc """
Defines list of metrics, that Reporter instance can aggregate by listening on events emitted in RTC Engine.
Suggested Reporter implementation is `Membrane.TelemetryMetrics.Reporter` from
[`membrane_telemetry_metrics`](https://github.com/membraneframework/membrane_telemetry_metrics).
You can see usage example in [`membrane_videoroom`](https://github.com/membraneframework/membrane_videoroom).
See also `Metrics` guide for more details and example report that you can obtain with
`Membrane.TelemetryMetrics.Reporter`.
"""
require Membrane.TelemetryMetrics
alias Membrane.RTC.Engine.Endpoint.WebRTC.TrackReceiver
alias Membrane.RTC.Engine.Track
alias Membrane.RTP.PayloadFormatResolver
@rtp_packet_arrival_event [Membrane.RTC.Engine.Endpoint.WebRTC, :RTP, :packet, :arrival]
@variant_switched_event [Membrane.RTC.Engine.Endpoint.WebRTC, :RTP, :variant, :switched]
@paddings_sent_event [Membrane.RTC.Engine.Endpoint.WebRTC, :RTP, :paddings, :sent]
@bandwidth_event [Membrane.RTC.Engine.Endpoint.WebRTC, :endpoint, :bandwidth]
@spec metrics() :: [Telemetry.Metrics.t()]
def metrics() do
Enum.concat([
endpoint_metrics(),
Membrane.RTP.Metrics.metrics(),
Membrane.ICE.Metrics.metrics(),
Membrane.WebRTC.Metrics.metrics()
])
end
defp endpoint_metrics() do
[
Telemetry.Metrics.sum(
"inbound-rtp.frames",
event_name: @rtp_packet_arrival_event,
measurement: :frame_indicator
),
Telemetry.Metrics.sum(
"inbound-rtp.keyframes",
event_name: @rtp_packet_arrival_event,
measurement: :keyframe_indicator
),
Telemetry.Metrics.last_value(
"outbound-rtp.variant",
event_name: @variant_switched_event,
measurement: :variant
),
Telemetry.Metrics.last_value(
"outbound-rtp.variant-reason",
event_name: @variant_switched_event,
measurement: :reason
),
Telemetry.Metrics.sum(
"outbound-rtp.paddings_sent",
event_name: @paddings_sent_event,
measurement: :num
),
Telemetry.Metrics.sum(
"outbound-rtp.paddings_bytes_sent",
event_name: @paddings_sent_event,
measurement: :bytes
),
Telemetry.Metrics.last_value(
"endpoint.bandwidth",
event_name: @bandwidth_event,
measurement: :bandwidth
),
Telemetry.Metrics.last_value(
"endpoint.metadata",
event_name: [Membrane.RTC.Engine.Endpoint.WebRTC, :endpoint, :metadata, :event],
measurement: :metadata
),
Telemetry.Metrics.last_value(
"track.metadata",
event_name: [Membrane.RTC.Engine.Endpoint.WebRTC, :track, :metadata, :event],
measurement: :metadata
)
]
end
@doc false
@spec telemetry_register(Membrane.TelemetryMetrics.label()) :: :ok
def telemetry_register(telemetry_label) do
Membrane.TelemetryMetrics.register(@rtp_packet_arrival_event, telemetry_label)
:ok
end
@doc false
@spec register_bandwidth_event(Membrane.TelemetryMetrics.label()) :: :ok
def register_bandwidth_event(telemetry_label) do
Membrane.TelemetryMetrics.register(@bandwidth_event, telemetry_label)
:ok
end
@doc false
@spec register_variant_switched_event(Membrane.TelemetryMetrics.label()) :: :ok
def register_variant_switched_event(telemetry_label) do
Membrane.TelemetryMetrics.register(@variant_switched_event, telemetry_label)
:ok
end
@doc false
@spec register_paddings_sent_event(Membrane.TelemetryMetrics.label()) :: :ok
def register_paddings_sent_event(telemetry_label) do
Membrane.TelemetryMetrics.register(@paddings_sent_event, telemetry_label)
:ok
end
@doc false
@spec emit_packet_arrival_event(
binary(),
:VP8 | :H264 | :OPUS,
Membrane.TelemetryMetrics.label()
) :: :ok
def emit_packet_arrival_event(payload, codec, telemetry_label) do
Membrane.TelemetryMetrics.execute(
@rtp_packet_arrival_event,
packet_measurements(payload, codec),
%{},
telemetry_label
)
:ok
end
@doc false
@spec emit_bandwidth_event(float(), Membrane.TelemetryMetrics.label()) :: :ok
def emit_bandwidth_event(bandwidth, telemetry_label) do
Membrane.TelemetryMetrics.execute(
@bandwidth_event,
%{bandwidth: bandwidth},
%{},
telemetry_label
)
:ok
end
@doc false
@spec emit_variant_switched_event(
Track.variant(),
TrackReceiver.variant_switch_reason(),
Membrane.TelemetryMetrics.label()
) :: :ok
def emit_variant_switched_event(variant, reason, telemetry_label) do
Membrane.TelemetryMetrics.execute(
@variant_switched_event,
%{variant: variant, reason: reason},
%{},
telemetry_label
)
:ok
end
@doc false
@spec emit_paddings_sent_event(
non_neg_integer(),
non_neg_integer(),
Membrane.TelemetryMetrics.label()
) :: :ok
def emit_paddings_sent_event(num, bytes, telemetry_label) do
Membrane.TelemetryMetrics.execute(
@paddings_sent_event,
%{num: num, bytes: bytes},
%{},
telemetry_label
)
:ok
end
defp packet_measurements(payload, codec) do
measurements =
case PayloadFormatResolver.keyframe_detector(codec) do
{:ok, detector} -> %{keyframe_indicator: detector.(payload) |> bool_to_int()}
:error -> %{}
end
case PayloadFormatResolver.frame_detector(codec) do
{:ok, detector} ->
frame_indicator = detector.(payload) |> bool_to_int()
Map.put(measurements, :frame_indicator, frame_indicator)
:error ->
measurements
end
end
defp bool_to_int(true), do: 1
defp bool_to_int(false), do: 0
end