# `VideoInterop.Lease`
[🔗](https://github.com/emerge-elixir/video_interop/blob/v0.1.0/lib/video_interop/lease.ex#L1)

Per-consumer producer lifetime token for a borrowed video interop frame.

A lease holder is unique. Before fan-out, a splitter must synchronously call
`retain/2` for every additional branch and give each branch a different
returned lease. The producer registers the new holder as pending before acknowledging
the retain request. The caller then confirms receipt. It must process retain/confirm/cancel
messages in mailbox order; a timeout sends
`{:video_interop_cancel_retain, token, child_holder}` to remove a possibly late
registration. Releases are idempotent per
`{token, holder}` pair.

Producers should issue managed leases through `VideoInterop.LeaseOwner`, whose isolated
mailbox prevents media traffic in the producing element from delaying retirement. `new/2` is a
low-level unmanaged constructor for implementations that provide equivalent registration,
isolation, idempotency, and draining themselves.

The opaque backend token should provide an owner-crash destructor fallback. A producer may also
attach a unique `VideoInterop.AbandonmentGuard` authority envelope to each holder. Its verified
native resource destructor is an eventual fallback for a holder-bearing BEAM term that disappears
without an explicit release. Normal release remains the primary path.

# `t`

```elixir
@type t() :: %VideoInterop.Lease{
  abandonment_guard: VideoInterop.AbandonmentGuard.t() | nil,
  holder: reference(),
  owner: pid(),
  token: term()
}
```

# `cancel_retain_tag`

```elixir
@spec cancel_retain_tag() :: :video_interop_cancel_retain
```

# `confirm_retain_tag`

```elixir
@spec confirm_retain_tag() :: :video_interop_confirm_retain
```

# `new`

```elixir
@spec new(pid(), term()) :: t()
```

Creates an unmanaged root lease.

Prefer `VideoInterop.LeaseOwner.issue/3`. This constructor does not register the holder or
provide mailbox isolation, fan-out accounting, release callbacks, or shutdown draining.

# `release`

```elixir
@spec release(t()) :: :ok
```

# `release_tag`

```elixir
@spec release_tag() :: :video_interop_release
```

# `retain`

```elixir
@spec retain(t(), timeout()) ::
  {:ok, t()} | {:error, :timeout | {:owner_down, term()} | term()}
```

Synchronously obtains a unique child holder for an additional consumer.

The owner receives:

    {:video_interop_retain, token, parent_holder, child_holder, reply_to, request_ref}

`request_ref` is a process alias. The owner must register `child_holder` as pending, monitor
`reply_to`, construct a fresh child guard, and send
`{:video_interop_retained, request_ref, {:ok, child_guard}}` to the alias. Receipt is committed
by `{:video_interop_confirm_retain, token, child_holder, request_ref}`; caller death or
cancellation before that confirmation must remove the pending holder. The child lease replaces
both the holder and guard; it never copies the parent's guard.

# `retain_tag`

```elixir
@spec retain_tag() :: :video_interop_retain
```

# `retained_tag`

```elixir
@spec retained_tag() :: :video_interop_retained
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
