# `VideoInterop.Lease`
[🔗](https://github.com/emerge-elixir/video_interop/blob/v0.1.2/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 cancel the child
registration. Releases are idempotent per `{token, holder}` pair.

Use `VideoInterop.LeaseOwner` for managed leases. Its isolated mailbox prevents
media traffic in the producing element from delaying retirement. Use `new/2`
only in implementations that provide equivalent registration, isolation,
idempotency, and draining.

The opaque backend token must provide an owner-crash destructor fallback. For
holder-specific abandonment fallback, attach one unique
`VideoInterop.AbandonmentGuard` producer authority envelope to each holder.
The guard's verified native resource destructor provides 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.

Use `VideoInterop.LeaseOwner.issue/3` for managed leases. 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*
