XGW.Trunk.Pipe (xgw v0.1.0)

Copy Markdown View Source

Bidirectional UDP + SRTP trunk between media edges.

What problem this solves

Multi-home rooms need an SFU-to-SFU media path that is not WebRTC/ICE and not Distributed Erlang. This GenServer owns one UDP socket, encrypts RTP/RTCP with a pre-shared key, multiplexes opaque datachannel frames, and delivers inbound plaintext to a handler pid.

RFCs

  • RFC 3711 -- SRTP on RTP/RTCP frames
  • RFC 3550 -- RTP payloads after unprotect

Summary

Functions

Returns a specification to start this module under a supervisor.

Sets the remote edge UDP address for outbound frames.

Registers a label and returns a channel_ref for SendHandle / Forwarder.

SendHandle datachannel MFA sink (apply(mod, fun, [pipe, ref, data, type])).

SendHandle RTP MFA sink (apply(mod, fun, [pipe, ssrc, rtp])).

Returns the local {ip, port} of the UDP socket.

Publishes RTP + datachannel SendHandle trunk passthrough for this pipe pid.

Sends an opaque datachannel payload labeled for demux on the far edge.

Encrypts and sends one RTP packet to the connected peer.

Replaces the inbound handler pid (e.g. your edge-to-edge bridge process).

Starts a trunk pipe.

UDP in/out packet counters (lab assertion that media used UDP).

Types

stats()

@type stats() :: %{udp_in: non_neg_integer(), udp_out: non_neg_integer()}

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

connect(pipe, ip, port)

@spec connect(pid(), :inet.ip_address(), :inet.port_number()) :: :ok

Sets the remote edge UDP address for outbound frames.

ensure_label(pipe, label)

@spec ensure_label(pid(), binary()) :: {:ok, reference()} | {:error, term()}

Registers a label and returns a channel_ref for SendHandle / Forwarder.

hot_send_dc(pipe, channel_ref, data, type \\ :string)

@spec hot_send_dc(pid(), reference(), binary(), :string | :binary) ::
  :ok | {:error, term()}

SendHandle datachannel MFA sink (apply(mod, fun, [pipe, ref, data, type])).

hot_send_rtp(pipe, ssrc, rtp)

@spec hot_send_rtp(pid(), non_neg_integer(), XMediaLib.Rtp.t()) ::
  :ok | {:error, term()}

SendHandle RTP MFA sink (apply(mod, fun, [pipe, ssrc, rtp])).

local_addr(pipe)

@spec local_addr(pid()) ::
  {:ok, {:inet.ip_address(), :inet.port_number()}} | {:error, term()}

Returns the local {ip, port} of the UDP socket.

publish_send_handles(pipe)

@spec publish_send_handles(pid()) :: :ok

Publishes RTP + datachannel SendHandle trunk passthrough for this pipe pid.

send_dc(pipe, label, data)

@spec send_dc(pid(), binary(), binary()) :: :ok | {:error, term()}

Sends an opaque datachannel payload labeled for demux on the far edge.

send_rtp(pipe, ssrc, packet)

@spec send_rtp(pid(), non_neg_integer(), XMediaLib.Rtp.t() | binary()) ::
  :ok | {:error, term()}

Encrypts and sends one RTP packet to the connected peer.

set_handler(pipe, handler)

@spec set_handler(pid(), pid()) :: :ok

Replaces the inbound handler pid (e.g. your edge-to-edge bridge process).

start_link(opts)

@spec start_link(keyword()) :: GenServer.on_start()

Starts a trunk pipe.

Opts:

  • :handler - pid that receives inbound {__MODULE__, kind, pipe, ...} messages
  • :master_key / :master_salt - shared lab keys (both directions)
  • :local_write_key / :local_write_salt / :remote_write_key / :remote_write_salt - directional write keys (preferred)
  • :port - optional bind port (default 0 ephemeral)

stats(pipe)

@spec stats(pid()) :: stats()

UDP in/out packet counters (lab assertion that media used UDP).