Skip to content

Composer mic-request + candidate readiness/self-preview (morph without reacquiring media) #22

Description

@DLSS5ONECLICK

Problem

Requesting the mic today is a separate, generic control, and camera/mic preview doesn't exist before promotion — a candidate has no way to see themselves or know their setup works until they're already live. Promotion itself re-acquires media from scratch via activateMedia()'s setCameraEnabled/setMicrophoneEnabled calls, which is a second getUserMedia() moment that can flicker/fail independently of the first.

Scope narrowed (2026-08-22)

The composer-integrated request design bullet below is implemented — real-device speaker-entry-friction testing made removing the standalone "Request the mic" control (and its separate justification form) urgent enough to pull forward, alongside #27. This issue now covers only what's left: candidate readiness (local media pre-acquisition), the persistent self-preview, and promotion without reacquiring media.

Scope narrowed further (2026-08-22)

Candidate readiness, the persistent self-preview, and promotion without reacquiring media are all implemented — see the comment below and DECISIONS.md for the full design and reasoning. This issue now covers only what's left: role-specific dominant video and a mic activity indicator.

Design

Composer-integrated request ✅ shipped: the chat composer has a mic-mode toggle (🎤) — submitting in mic-mode posts the request through the existing authoritative requestToSpeak path, replacing the standalone "Request the mic" control entirely. micRequestMode is a controlled prop lifted to EventRoom (not local to the composer), since tapping an empty seat that turns out to have a queue (issue #27) needs to switch this same composer into request mode from outside it.

Readiness without a second gesture ✅ shipped: submitting the mic-mode composer is itself the real user gesture that calls createLocalTracks({ audio: true, video: true }) once (useLiveRoomConnection.prepareLocalMedia), acquiring both tracks under Safari's gesture requirement — one combined permission prompt, not two.

Persistent self-preview, spatially stable ✅ shipped: a new SelfPreview component, always mounted whenever localVideoTrack is held, renders into #20's fixed corner slot, attaching the locally held track via .attach() — the same component/track instance through candidate readiness, promotion, and (per this issue's own explicit non-goal below) still just the local feed once actually speaking.

Promotion without reacquiring ✅ shipped: useLiveRoomConnection's publish path checks for already-prepared tracks first and calls publishTrack() on them directly, skipping a second getUserMedia() call entirely. Falls back to the existing gesture-gated setCameraEnabled/setMicrophoneEnabled path, unchanged, for anyone who never pre-acquired (issue #27's direct join).

Role-specific dominant video (partial, narrow) and mic activity indicator — remaining, unchanged from original design. The former is deliberately deferred rather than built now — the self-preview stays the local feed only; making the other speaker's video dominant once the local user is speaking is a larger visual redesign left to a later pass (possibly #18), not silently expanded into this one.

Explicit non-goal

No candidate snapshot/profile-preview icons for other waiting candidates. No change to #23's automatic-promotion scope — confirmed: resolveClaimDecision (the shared eligibility rule checkPromotionEligibility/claimOpenSeat both use) depends only on queue rank, never on media/readiness state, so this issue's remaining work required no changes there. No new server-side "readiness" field — local track possession is the whole signal (see DECISIONS.md).

Depends on

#20 (video-first room shell) — the self-preview slot must exist. Shipped.

Blocks

Nothing currently — #23's automatic promotion doesn't depend on any signal this issue produces (see the non-goal note above; that dependency assumed a design that changed once #23 was actually implemented).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions