defmodule ExLibSRTP do
@moduledoc """
[libsrtp](https://github.com/cisco/libsrtp) bindings for Elixir.
The workflow goes as follows:
- create ExLibSRTP instance with `new/0`
- add streams with `add_stream/2`
- protect or unprotect packets with `protect/3`, `unprotect/3`, `protect_rtcp/3`, `unprotect_rtcp/3`
- remove streams with `remove_stream/2`
"""
alias ExLibSRTP.{Native, Policy}
require Record
@opaque t :: {__MODULE__, native :: reference}
@type ssrc_t :: 0..4_294_967_295
defguard is_ssrc(ssrc) when ssrc in 0..4_294_967_295
defmacrop ref(native) do
quote do
{unquote(__MODULE__), unquote(native)}
end
end
@spec new() :: t()
def new() do
ref(Native.create())
end
@spec add_stream(t(), policy :: Policy.t()) :: :ok
def add_stream(ref(native) = _srtp, %Policy{} = policy) do
{ssrc_type, ssrc} = Native.marshal_ssrc(policy.ssrc)
{keys, keys_mkis} = Native.marshal_master_keys(policy.key)
Native.add_stream(
native,
ssrc_type,
ssrc,
keys,
keys_mkis,
policy.rtp,
policy.rtcp,
policy.window_size,
policy.allow_repeat_tx
)
end
@spec remove_stream(t(), ssrc :: ssrc_t()) :: :ok
def remove_stream(ref(native) = _srtp, ssrc) when is_ssrc(ssrc) do
Native.remove_stream(native, ssrc)
end
@spec update(t(), policy :: Policy.t()) :: :ok
def update(ref(native), %Policy{} = policy) do
{ssrc_type, ssrc} = Native.marshal_ssrc(policy.ssrc)
{keys, keys_mkis} = Native.marshal_master_keys(policy.key)
Native.update(
native,
ssrc_type,
ssrc,
keys,
keys_mkis,
policy.rtp,
policy.rtcp,
policy.window_size,
policy.allow_repeat_tx
)
end
@spec protect(t(), unprotected :: binary(), mki_index :: pos_integer() | nil) ::
{:ok, protected :: binary()}
def protect(srtp, unprotected, mki_index \\ nil)
def protect(ref(native), unprotected, nil) do
Native.protect(native, :rtp, unprotected, false, 0)
end
def protect(ref(native), unprotected, mki_index) when is_integer(mki_index) do
Native.protect(native, :rtp, unprotected, true, mki_index)
end
@spec protect_rtcp(t(), unprotected :: binary(), mki_index :: pos_integer() | nil) ::
{:ok, protected :: binary()}
def protect_rtcp(srtp, unprotected, mki_index \\ nil)
def protect_rtcp(ref(native), unprotected, nil) do
Native.protect(native, :rtcp, unprotected, false, 0)
end
def protect_rtcp(ref(native), unprotected, mki_index) when is_integer(mki_index) do
Native.protect(native, :rtcp, unprotected, true, mki_index)
end
@spec unprotect(t(), protected :: binary(), use_mki :: boolean()) ::
{:ok, unprotected :: binary()} | {:error, :auth_fail | :reply_fail | :bad_mki}
def unprotect(ref(native) = _srtp, protected, use_mki \\ false) do
Native.unprotect(native, :rtp, protected, use_mki)
end
@spec unprotect_rtcp(t(), protected :: binary(), use_mki :: boolean()) ::
{:ok, unprotected :: binary()} | {:error, :auth_fail | :reply_fail | :bad_mki}
def unprotect_rtcp(ref(native) = _srtp, protected, use_mki \\ false) do
Native.unprotect(native, :rtcp, protected, use_mki)
end
end