# `@aphrodite/live-media-adapter`

This package is Aphrodite tenant #1's inward-facing adapter to the canonical
`@oshun/live-media` substrate. It may translate Aphrodite identity and
persistence, but it does not own shared live-media contracts or create a tenant
fork.

The publisher-grant store uses PostgreSQL transactions, a per-resource advisory
lock, an active-generation partial unique index, and tenant RLS. It persists
only publisher-secret digests. The static substrate tenant ID is `aphrodite`;
product broadcaster IDs remain external references and do not replace it.

The internal transcode control fixes the same tenant and derives every output
URI from its configured operator root, stream UUID, and generated execution
UUID. Aphrodite callers cannot select another tenant's media namespace or reuse
an arbitrary output path.

Publisher connect/disconnect callbacks and reconciliation now enter the shared
`LiveMediaTenantPublisherEdgeControl`. Aphrodite's class is only a tenant-#1
constructor wrapper retaining its default SQL store, operational telemetry,
clock, and request-ID seams; edge lifecycle and emission behavior live once in
the canonical substrate.

The rendition-publication adapter preserves that boundary. Its PostgreSQL store
uses transaction-local tenant context, forced RLS, a per-publication advisory
lock, optimistic revisions, and an exact JSON object ledger for
publishing/ready/failed/revoked transitions. The shared
`LiveMediaTenantMediaPublicationControl` generates publication and request IDs
internally and owns tenant-fixed publish/get/revoke behavior. Aphrodite's class
is a tenant-#1 wrapper that maps completed Neith output into the shared packager
and retains its legacy grant method only as a deprecated compatibility shim.
Current protocol-aware viewer grants use `AphroditePlaybackGrantControl`, which
issues a path-scoped grant only from a trusted positive entitlement decision.

The canonical shared SQL media-pipeline store persists exact job inputs and
attempts in forced-RLS PostgreSQL tables. Advisory idempotency locks,
`SKIP LOCKED` claims, database-clock leases, lease-token fencing, bounded
recovery, and a composite tenant/stream/publication foreign key keep concurrent
and restarted workers on one authoritative state machine.
`SqlAphroditeMediaPipelineJobStore` is only a constructor-compatible tenant-#1
wrapper that supplies Aphrodite's default database client and exact legacy
tenant-mismatch error. The tenant-fixed control generates all job, attempt,
execution, publication, request, and lease identities server-side.

Protected playback maps an authenticated `users.id` JWT subject through
`viewers.user_id` in one repeatable-read, read-only SQL snapshot. Viewer state,
ban expiry, age verification, sensual-tier opt-in, stream state/type,
broadcaster blocks, current subscription/private-show access, and the newest
ready publication are evaluated together. Ticket streams remain explicitly
unconfigured and fail closed. Only an allowed decision can reach the narrow
playback-grant issuer; callers cannot choose a tenant, publication, decision, or
viewer row.

The durable viewer-session adapter is the sole Aphrodite playback-presence
authority. Forced-RLS tables hold digest-only rotating lease credentials, the
session row, immutable lifecycle events, and immutable QoE samples. Database
time, per-resource advisory locking, idempotency uniqueness, lazy crash expiry,
and token fencing preserve join/refresh/reconnect/heartbeat/leave semantics
across processes. Active-session and unique-viewer counts are exact SQL
aggregates; legacy stream counters are reconciled projections, not an alternate
write path. The Viewer app composes this store behind canonical leased playback,
heartbeat, leave, and presence routes, while its former direct playback-URL and
counter-mutation routes are retired.

The live-chat runtime enters the canonical service and durable store through
`LiveMediaTenantLiveChatControl`. Aphrodite's class is a tenant-#1 wrapper that
retains its constructor, exact denial error contract, SQL viewer/owner identity
and entitlement policy, durable product filters, timing/rate configuration, and
operational telemetry injection. Membership, messaging, moderation commands,
presence, system/tip publication, event polling, tenant-fixed scopes, and
body-free chat telemetry now live once in the shared control.

The first production optional-media adapter is publication-bound content
analysis. It accepts only an exact ready HLS/DASH video object already present
in the publication ledger, reads it through a checksum- and length-bounded
object-store operation, extracts a measured JPEG with FFmpeg, and invokes the
configured OpenAI-compatible vision endpoint under an Aphrodite-owned advisory
policy profile. Results are advisory only: automatic age gates and policy
actions are forcibly disabled, and durable evidence retains category/policy
signals and face/text counts without biometric identifiers, OCR bodies, or raw
sample bytes.

Probe, analyze, and teardown now enter the optional-adapter service through
`LiveMediaTenantContentAnalysisControl`. Aphrodite's class is a thin tenant-#1
wrapper that fixes `aphrodite.content-analysis.v1` while retaining the exact
constructor, input schema/type, timing/request-ID seams, provider, publication
binding verifier, advisory policy, routes, queue, and worker behavior.

Migration `00013_live_media_content_analysis` supplies the forced-RLS operation
ledger. Semantic idempotency, database-clock leases, periodic renewal,
lease-token fencing, bounded attempts, immutable checksummed result artifacts,
and exact replay make execution restart-safe. The streaming app exposes the
adapter only through its internal service-key boundary; tenant, adapter,
capability, and policy ownership remain fixed inside the control. The supervised
MediaMTX gate applies the real PostgreSQL migration, samples an actual published
transport segment, reconstructs the database and provider, proves no second
vendor call on replay, fences concurrent/stale workers, denies another tenant,
and tears every test service down.

The recording optional-media adapter is likewise real and tenant-fixed. It
requires the requested publisher connection to agree between the durable edge
ledger and a fresh MediaMTX Control API observation, then derives the RTSP input
from operator configuration rather than caller input. A shell-free FFmpeg
stream-copy capture is duration-bounded, cancellation-aware, and accepted only
after FFprobe verifies its container, video stream, dimensions, duration, and
optional audio stream. The measured file is hashed through an open descriptor,
staged in the durable operation ledger, uploaded create-only through the shared
object store, verified by exact checksum and length, and removed from its
private attempt directory before terminal success.

Its public control and worker are now exact tenant-#1 wrappers over the shared
`LiveMediaTenantRecordingControl` and `LiveMediaTenantRecordingWorker`.
Aphrodite retains the forced-RLS queue, record validator, MediaMTX source
authority, retention policy, FFmpeg executor, object store, scheduler, routes,
and shutdown cancellation. The shared boundary fixes `aphrodite` plus
`aphrodite.recording.v1`, creates request scopes and semantic fingerprints, and
rejects mismatched durable work before it can reach the provider.

Migration `00014_live_media_recording` owns the database-clock queue, semantic
idempotency, retry schedule, bounded attempts, expiring renewable leases,
lease-token fencing, and staged artifact descriptor under forced tenant RLS. A
restarted worker settles an already-uploaded staged object without capturing the
stream again; expired final attempts become explicit failures instead of stuck
processing rows. The supervised MediaMTX/PostgreSQL gate records the live SRT
publisher through RTSP into a probed MP4 object, reconstructs the database and
provider, proves no second FFmpeg call on replay, recovers and fences an
abandoned lease, denies another tenant, and tears down the publisher and both
containers.

The segment-encryption optional-media adapter protects one exact ready HLS VOD
publication with AES-128-CBC. It validates the publication ledger's complete
canonical master/media/MPEG-TS graph, rejects existing encryption and unsafe or
unreferenced objects, derives each IV from the media sequence, encrypts every
segment create-only, and independently decrypts persisted bytes back to the
source before success. Protected media manifests, the master manifest, and a
checksummed key-free descriptor are committed in dependency order; exact
existing objects are accepted on restart only when media type, length, and
checksum all match.

Migration `00015_live_media_segment_encryption` owns the forced-RLS,
publication-bound queue, database-clock retry schedule, renewable fenced leases,
semantic idempotency, wrapped-key custody, staged publication evidence, and
terminal replay. The provider creates a random data key and uses the Neith
PKCS#11 KMS backend to wrap it under an existing nonextractable RSA-3072 KEK.
Only wrapped bytes and context/recovery digests are durable; plaintext data and
content-key buffers are zeroed, never enter PostgreSQL or object descriptors,
and are recovered only for an exact succeeded operation. CENC, CBCS, vendor DRM
licenses, viewer wiring, and protected-object/key cleanup remain explicit later
work rather than simulated support.

The watermark optional-media adapter is a real, deliberately visible transform.
`aphrodite.watermark.v1` accepts one exact ready `video/mp2t` H.264/AAC object
from the publication ledger and always applies the tenant-fixed
`aphrodite.visible-grid.v1` profile. The caller cannot choose the profile, key,
payload, output namespace, or worker. The control derives an opaque payload
reference from either the exact publication or an exact active, entitled viewer
session; the binding verifier rechecks that authority with database time before
queue mutation and execution.

A shell-free, time- and byte-bounded FFmpeg executor encodes a keyed 8x8
black/white grid into real H.264/AAC MPEG-TS output. It decodes the persisted
result, extracts all 64 cells from exact pixels, and measures luma PSNR outside
the grid bounding box before success. The create-only media object is committed
before a checksummed evidence descriptor. Existing exact objects are verified on
restart rather than re-encoded. The evidence explicitly describes a visible grid
and makes no invisible-watermark or forensic-robustness claim.

Migration `00016_live_media_watermark` supplies the publication-bound,
forced-RLS queue with semantic idempotency, database-clock retry scheduling,
renewable fenced leases, staged custody/artifact recovery, exact terminal
replay, and durable release. Each operation creates a random 256-bit data key,
wraps it under an existing nonextractable RSA-3072 PKCS#11 KEK, and derives the
64-bit grid token with a domain-separated HMAC over the exact operation context.
Only wrapped bytes and verification digests are durable. Release deletes both
fixed output objects before recording the durable release fence, and repeated
release is safe; a released operation identity cannot recreate its media.

The player-client optional adapter is a real HLS/DASH browser proof boundary
rather than a simulated player manager. Protected playback reserves one
operation for the exact publication, viewer session, playback grant, client
instance, and protocol without ever passing the Bearer credential to the
adapter. A positive result can be created only after the viewer-session store
has committed a `playing` QoE event whose `playbackGrantId` matches and whose
measured decoded frame count is positive. The first event remains the immutable
proof while later heartbeats renew the session and replay the succeeded
descriptor.

Migration `00017_live_media_player_client` owns the forced-RLS operation ledger,
composite publication/session/QoE foreign keys, one-active-operation session
fence, semantic idempotency, database-clock lifecycle, reclaimable execution
lease, and durable release. Refresh supersedes the prior operation; leave,
startup failure, and authorization failure release it. Result and evidence
constraints exclude bearer, credential, lease-token, and token fields. The real
MediaMTX/PostgreSQL gate applies the migration, binds the operation to protected
playback, accepts only persisted decoded-frame evidence, proves restart-safe
claiming, browser-device enforcement, exact protocol-specific runtime proof, and
cross-tenant denial, and releases the operation. Native player adapters remain
explicit later work.

The publisher-client optional adapter is a credential-free proof boundary for
browser WHIP publishing. Provisioning makes the publisher grant ID the operation
ID and reserves it for one tenant stream, client instance, and WebRTC protocol.
MediaMTX external authentication binds the exact grant to the source connection
ID; the browser heartbeat contributes only monotonic outbound RTP counters, and
success additionally requires positive inbound bytes from that same connected
edge session. Provider results carry separate `client-runtime` and
`edge-observation` proofs plus a client-session artifact, never the Bearer, SDP,
ICE data, or device details.

Migration `00018_live_media_publisher_client` owns the forced-RLS operation
ledger, exact composite grant/resource foreign key, one-active-publisher stream
fence, semantic idempotency, database-clock lifecycle, reclaimable execution
lease, immutable success, and repeat-safe release. The application revokes only
after locating the exact operation and uses that operation's grant ID as an
atomic revocation condition, so an unknown or superseded operation cannot
invalidate a newer live publisher grant. The real MediaMTX/PostgreSQL gate
proves durable edge/client evidence over the existing real SRT publisher, secret
non-disclosure, tenant isolation, restart replay, and cleanup. The separate real
MediaMTX/Chromium gate proves WebRTC OPTIONS capability authentication without a
fabricated connection and subsequent WHIP source-ID binding. Only the browser
WHIP runtime is claimed; native publisher adapters remain later work.

The remote-guest optional adapter binds one exact active publisher grant to one
host browser and one invited guest browser. The tenant-fixed control generates
the operation, guest session, invitation, guest lease, and signaling tickets;
callers cannot choose another tenant or an arbitrary media authority. Raw
capabilities are returned once and only SHA-256 digests are durable. Invitation
exchange and signaling-ticket consumption are transactionally one-use, while
idempotent replay rotates only still-unused secrets and refuses to recover a
consumed provision.

Migration `00021_live_media_remote_guests` supplies the forced-RLS PostgreSQL
operation, invitation, signaling-event, and bounded evidence state. It uses
database-clock lifecycle and execution leases, one-active-session fencing per
stream, semantic idempotency, restart recovery, stale-worker rejection, and
repeat-safe release. SDP, ICE candidates, raw invitation/ticket/guest-lease
values, local/remote addresses, codec strings, device labels, and captured media
are excluded from durable rows. Success requires connected/offer/answer
signaling state and reciprocal RTP evidence whose guest outbound and host
inbound video SSRC hashes agree.

The supervised PostgreSQL/MediaMTX gate applies the real migration, proves
host/guest secret rotation and one-use consumption, durable secret and SDP/ICE
absence, restart replay, RLS tenant denial, database-clock invitation and
lifecycle expiry, abandoned-lease recovery, stale-writer fencing, idempotent
release, and teardown. The browser Playwright gate independently proves actual
two-browser WebRTC media, the reciprocal SSRC link, third-participant rejection,
credential containment, accessibility, mobile/reduced-motion behavior, and
ordered release.
