lib/ex_sdp/serializer.ex

defmodule ExSDP.Serializer do
  @moduledoc """
  Module providing helper functions for serialization.
  """

  @doc """
  Serializes both sdp lines (<type>=<value>) and sdp parameters (<parameter>=<value>)
  """
  @spec maybe_serialize(type :: binary(), value :: term()) :: binary()
  def maybe_serialize(_type, nil), do: ""
  def maybe_serialize(_type, []), do: ""

  def maybe_serialize(type, values) when is_list(values),
    do: Enum.map_join(values, "\n", fn value -> maybe_serialize(type, value) end)

  def maybe_serialize(type, {:framerate, {frames, sec}}),
    do: "#{type}=framerate:#{frames}/#{sec}"

  def maybe_serialize(type, {:ice_ufrag, value}), do: "#{type}=ice-ufrag:#{value}"
  def maybe_serialize(type, {:ice_pwd, value}), do: "#{type}=ice-pwd:#{value}"

  def maybe_serialize(type, :ice_lite), do: "#{type}=ice-lite"

  def maybe_serialize(type, {:ice_options, value}),
    do: "#{type}=ice-options:#{serialize_ice_options(value)}"

  def maybe_serialize(type, {:fingerprint, value}),
    do: "#{type}=fingerprint:#{serialize_fingerprint(value)}"

  def maybe_serialize(type, {:setup, value}), do: "#{type}=setup:#{serialize_setup(value)}"
  def maybe_serialize(type, {:mid, value}), do: "#{type}=mid:#{value}"
  def maybe_serialize(type, :rtcp_mux), do: "#{type}=rtcp-mux"
  def maybe_serialize(type, :rtcp_rsize), do: "#{type}=rtcp-rsize"

  def maybe_serialize(type, true), do: "#{type}=1"
  def maybe_serialize(type, false), do: "#{type}=0"
  def maybe_serialize("dtmf-tones", value), do: "#{value}"
  def maybe_serialize(type, {key, value}), do: "#{type}=#{key}:#{value}"
  def maybe_serialize(type, value), do: "#{type}=#{value}"

  @spec maybe_serialize_hex(String.t(), nil | integer) :: binary
  def maybe_serialize_hex(_type, nil), do: ""

  def maybe_serialize_hex(type, value),
    do: "#{type}=#{Integer.to_string(value, 16) |> String.downcase()}"

  @spec maybe_serialize_list([String.t()] | nil, String.t()) :: String.t()
  def maybe_serialize_list([], _sep), do: ""
  def maybe_serialize_list(nil, _sep), do: ""
  def maybe_serialize_list(list, sep), do: Enum.map_join(list, sep, &"#{&1}")

  defp serialize_ice_options(ice_options) do
    Bunch.listify(ice_options) |> Enum.join(" ")
  end

  defp serialize_fingerprint(fingerprint) do
    case fingerprint do
      {:sha1, value} -> "sha-1 #{value}"
      {:sha224, value} -> "sha-224 #{value}"
      {:sha256, value} -> "sha-256 #{value}"
      {:sha384, value} -> "sha-384 #{value}"
      {:sha512, value} -> "sha-512 #{value}"
    end
  end

  defp serialize_setup(setup) when setup in [:active, :passive, :actpass, :holdconn],
    do: Atom.to_string(setup)
end