Functions for using the DAVE Protocol

Discord Audio & Video End-to-End Encryption (DAVE) Protocol Whitepaper

The Rust crate davey

RustlerPrecompiled will fetch the required files at compile time.

The following OS's have binaries available:

  • aarch64-apple-darwin
  • aarch64-unknown-linux-gnu
  • aarch64-unknown-linux-musl
  • arm-unknown-linux-gnueabihf
  • riscv64gc-unknown-linux-gnu
  • x86_64-apple-darwin
  • x86_64-pc-windows-gnu
  • x86_64-pc-windows-msvc
  • x86_64-unknown-freebsd
  • x86_64-unknown-linux-gnu
  • x86_64-unknown-linux-musl

If you have some wackadoo OS or you prefer to build from source with your installed Rust toolchain, you can add Rustler to your project dependencies and set FORCE_DAVE_BUILD=true.

defp deps do
  [
    ...
    {:rustler, "~> 0.37", optional: true, runtime: false}
  ]
end

Minimum set of functions required to get Discord Voice working are implemented. davey has some other functionality that may be added later. Docs here are limited, so I would recommend looking at the DAVE whitepaper or nostrum source code for integration and usage details.

Summary

Types

codec()

@type codec() :: :unknown | :opus | :av1 | :vp8 | :vp9 | :h264 | :h265

commit_welcome()

@type commit_welcome() :: {binary() | nil, binary() | nil}

media_type()

@type media_type() :: :audio | :video

proposals_operation_type()

@type proposals_operation_type() :: :append | :revoke

protocol_version()

@type protocol_version() :: pos_integer()

session()

@type session() :: reference()

session_status()

@type session_status() :: :inactive | :pending | :awaiting_response | :active

Functions

can_passthrough?(session, user_id)

@spec can_passthrough?(session(), non_neg_integer()) :: boolean()

decrypt(session, user_id, media_type \\ :audio, packet)

@spec decrypt(session(), non_neg_integer(), media_type(), binary()) ::
  binary() | :error

encrypt(session, media_type \\ :audio, codec \\ :opus, packet)

@spec encrypt(session(), media_type(), codec(), binary()) :: binary() | :error

epoch(session)

@spec epoch(session()) :: non_neg_integer()

get_serialized_key_package(session)

@spec get_serialized_key_package(session()) :: binary()

max_protocol_version()

@spec max_protocol_version() :: protocol_version()

new_session(protocol_version, user_id, channel_id)

@spec new_session(protocol_version(), non_neg_integer(), non_neg_integer()) ::
  session()

process_commit(session, commit)

@spec process_commit(session(), binary()) :: :ok | :error

process_proposals(session, operation_type, proposals, user_ids \\ nil)

@spec process_proposals(
  session(),
  proposals_operation_type(),
  binary(),
  [non_neg_integer()] | nil
) :: commit_welcome() | :error

process_welcome(session, welcome)

@spec process_welcome(session(), binary()) :: :ok | :error

protocol_version(session)

@spec protocol_version(session()) :: protocol_version()

ready?(session)

@spec ready?(session()) :: boolean()

reinit(session, protocol_version, user_id, channel_id)

@spec reinit(session(), protocol_version(), non_neg_integer(), non_neg_integer()) ::
  :ok

reset(session)

@spec reset(session()) :: :ok | :error

set_external_sender(session, sender)

@spec set_external_sender(session(), binary()) :: :ok

set_passthrough_mode(session, passthrough?)

@spec set_passthrough_mode(session(), boolean()) :: :ok

status(session)

@spec status(session()) :: session_status()