dave 0.2.0

Rust DAVE primitives with Discord Opus audio and video frame transform support.
Documentation
# dave

Discord DAVE media-frame transform primitives for Rust. `dave` implements the
end-to-end encryption layer used by Discord audio/video sessions: OpenMLS session
setup, gateway-facilitated proposal/commit/welcome processing, keyed media
ratchets, staged sender activation, passthrough windows, and typed frame
encryption/decryption errors.

The crate deliberately stops at the DAVE layer. It does not implement Discord
gateway IO, UDP/RTP transport, codec encode/decode, packetization,
depacketization, or runtime scheduling; those belong in a media runtime such as
`cacophony`.

## Features

- **Frame-transform API**: encrypt typed `MediaFrame<C: FrameCodec>` values and
  decrypt received protocol frames with caller-provided output buffers.
- **libdave codec set**: send-side transforms for Opus audio plus VP8, VP9,
  H264, H265, and AV1 video; receive-side parsing is codec-agnostic.
- **DAVE transition model**: prepared target protocol state is separate from
  active sender media state, matching prepare/ready/execute gateway transitions.
- **Ratchet retention**: previous receive ratchets are retained for in-flight
  media during transitions and removed after their retention window.
- **Typed errors**: malformed frames, replayed nonces, missing key generations,
  AEAD failures, passthrough rejection, unsupported codecs, and missing
  decryptors are distinguishable.
- **Secret hygiene**: ratchet key material is stored in zeroizing containers.

## Codec support

The public frame API is codec typed:

- `Opus`: fully encrypted audio frames, with the standard Discord Opus silence
  frame left unchanged.
- `Vp8`: packetizer-visible payload header bytes are authenticated but left
  unencrypted.
- `Vp9`: fully encrypted video frames.
- `H264` and `H265`: NAL start/header sections are authenticated but left
  unencrypted, with nonce retry when ciphertext would create packetizer-confusing
  start codes.
- `Av1`: packetizer-visible OBU headers are authenticated but left unencrypted,
  matching libdave's size-field rewrite behavior.

Receive-side parsing handles DAVE supplemental data, unencrypted ranges,
truncated nonces, and tags before reconstructing the decrypted encoded frame.

## Example

```rust
use dave::{MediaFrame, Opus, Session};

fn new_session(user_id: u64, channel_id: u64) -> Result<Session, dave::InitError> {
    Session::new(user_id, channel_id)
}

fn opus_frame(bytes: &[u8]) -> MediaFrame<'_, Opus> {
    MediaFrame::<Opus>::new(bytes)
}
```

A caller is expected to drive the Discord voice gateway DAVE messages and call
the corresponding session methods (`set_external_sender`, `process_proposals`,
`process_welcome`, `process_commit`, and `activate_staged_sender`) at the
transition points required by the gateway.

## Related crates

- [`cacophony`]https://crates.io/crates/cacophony: high-performance Discord
  voice runtime built on top of `dave`.

## License

AGPL-3.0-only. See `LICENSE` for details.