defmodule ExSDP do
@moduledoc """
This module represents the SDP Session.
Its fields directly correspond to those defined in
[RFC4566](https://tools.ietf.org/html/rfc4566#section-5)
"""
use Bunch.Access
alias ExSDP.{
Address,
Attribute,
Bandwidth,
ConnectionData,
Encryption,
Media,
Origin,
Parser,
RepeatTimes,
Serializer,
Timezone,
Timing,
Utils
}
@enforce_keys [:origin]
@optional_keys [
:email,
:encryption,
:uri,
:phone_number,
:session_information,
:timing,
:time_zones_adjustments,
:connection_data,
attributes: [],
bandwidth: [],
media: [],
time_repeats: []
]
defstruct [
version: 0,
session_name: "-"
] ++ @enforce_keys ++ @optional_keys
@type t :: %__MODULE__{
version: non_neg_integer(),
origin: Origin.t(),
session_name: binary(),
session_information: binary() | nil,
uri: binary() | nil,
email: binary() | nil,
phone_number: binary() | nil,
connection_data: ConnectionData.t() | nil,
bandwidth: [Bandwidth.t()],
time_zones_adjustments: Timezone.t() | nil,
encryption: Encryption.t() | nil,
attributes: [Attribute.t()],
timing: Timing.t() | nil,
time_repeats: [RepeatTimes.t()],
media: [Media.t()]
}
defdelegate parse(text), to: Parser
defdelegate parse!(text), to: Parser
@doc """
Returns new sdp struct.
By default:
* `version` is `0`
* `username`, `session_id`, `session_version` and `address` - refer to `Origin.new/1`
* `session_name` is `-`
"""
@spec new(
version: non_neg_integer(),
username: binary(),
session_id: integer(),
session_version: integer(),
address: Address.t(),
session_name: binary()
) :: t()
def new(opts \\ []) do
{version, opts} = Keyword.pop(opts, :version, 0)
{session_name, opts} = Keyword.pop(opts, :session_name, "-")
%__MODULE__{
version: version,
origin: Origin.new(opts),
session_name: session_name
}
end
@spec add_media(t(), Media.t() | [Media.t()]) :: t() | Media.t()
def add_media(sdp, media), do: Map.update!(sdp, :media, &(&1 ++ Bunch.listify(media)))
@spec add_attribute(t() | Media.t(), Attribute.t()) :: t() | Media.t()
def add_attribute(sdp_or_media, attribute), do: add_attributes(sdp_or_media, [attribute])
@spec add_attributes(t() | Media.t(), [Attribute.t()]) :: t() | Media.t()
def add_attributes(sdp_or_media, attributes) when is_list(attributes),
do: Map.update!(sdp_or_media, :attributes, &(&1 ++ attributes))
@spec get_attribute(t() | Media.t(), Attribute.key()) :: Attribute.t() | nil
def get_attribute(sdp_or_media, key), do: Utils.get_attribute(sdp_or_media, key)
@spec get_attributes(t() | Media.t(), Attribute.key()) :: [Attribute.t()]
def get_attributes(sdp_or_media, key), do: Utils.get_attributes(sdp_or_media, key)
@spec delete_attribute(t() | Media.t(), Attribute.key()) :: t() | Media.t()
def delete_attribute(sdp_or_media, key), do: delete_attributes(sdp_or_media, [key])
@spec delete_attributes(t() | Media.t(), [Attribute.key()]) :: t() | Media.t()
def delete_attributes(sdp_or_media, keys), do: Utils.delete_attributes(sdp_or_media, keys)
end
defimpl String.Chars, for: ExSDP do
@impl true
def to_string(session) do
import ExSDP.Sigil
alias ExSDP.Serializer
~n"""
v=#{session.version}
o=#{session.origin}
s=#{session.session_name}
#{Serializer.maybe_serialize("i", session.session_information)}
#{Serializer.maybe_serialize("u", session.uri)}
#{Serializer.maybe_serialize("e", session.email)}
#{Serializer.maybe_serialize("p", session.phone_number)}
#{Serializer.maybe_serialize("c", session.connection_data)}
#{Serializer.maybe_serialize("b", session.bandwidth)}
#{Serializer.maybe_serialize("t", session.timing)}
#{Serializer.maybe_serialize("r", session.time_repeats)}
#{Serializer.maybe_serialize("z", session.time_zones_adjustments)}
#{Serializer.maybe_serialize("k", session.encryption)}
#{Serializer.maybe_serialize("a", session.attributes)}
#{Serializer.maybe_serialize("m", session.media)}
"""
end
end