fix(rc+guest): coordinate/keyboard/UI for remote control; guest media + panel fixes (batch71)
Remote control (connect.html viewer): - Coordinate offset fixed: map clicks to the actual video CONTENT rect (object-fit letterbox-aware), not the element rect — cursor now lands where you click. - Keyboard: capture at document level while a session is live (the <video> lost focus on bar clicks → keys did nothing). Skips the chat input. - Control bar moved to bottom-right with tiny modern icons; video fills the viewport. - Smoother cursor (mousemove ~60/s). Guest meetings: - Guest mic inaudible + guest invisible in the participant list + outsider screen share not showing (#1/#8/#11): root cause was the SFU media→tile map keyed on identity==uid, but guests had a random LiveKit identity and a null signaling uid. Guests now carry ONE stable id across signaling (meeting-join guestId) and the LiveKit token identity, so their media attaches and they appear to everyone. - Guests can't add participants (#9) and don't see the transcript button (#12). - Search box in the schedule participant list (#10). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+4
-2
@@ -937,13 +937,15 @@ route('POST', '/api/meetings/token', async (req, res) => {
|
||||
// meeting, so a token can't be created for an arbitrary/expired code. Identity is a throwaway guest id.
|
||||
route('POST', '/api/meetings/guest-token', async (req, res) => {
|
||||
if (!LIVEKIT_ENABLED) return json(res, 501, { error: 'sfu not configured' });
|
||||
const { room, name } = await readBody(req);
|
||||
const { room, name, identity } = await readBody(req);
|
||||
const rm = String(room || '').trim();
|
||||
if (!/^\d{6}$/.test(rm)) return json(res, 400, { error: 'invalid room' });
|
||||
const live = (() => { try { return require('./presence').meetingRooms.has(rm); } catch (_) { return false; } })();
|
||||
const sched = (() => { try { const s = R.scheduledMeetings.byCode(rm); return !!(s && !s.ended_at); } catch (_) { return false; } })();
|
||||
if (!live && !sched) return json(res, 404, { error: 'meeting not found or not active' });
|
||||
const gid = 'guest-' + crypto.randomBytes(8).toString('hex');
|
||||
// Reuse the guest's client id as the LiveKit identity so it matches the id they announced over
|
||||
// signaling (meeting-join guestId) — that mapping is how their media attaches to their tile.
|
||||
const gid = (typeof identity === 'string' && /^guest-[a-z0-9]+$/i.test(identity)) ? identity.slice(0, 64) : ('guest-' + crypto.randomBytes(8).toString('hex'));
|
||||
const gname = String(name || 'Guest').slice(0, 60);
|
||||
const token = livekitToken(gid, gname, rm, JSON.stringify({ guest: true }));
|
||||
json(res, 200, { token, url: LIVEKIT_URL, identity: gid, name: gname });
|
||||
|
||||
Reference in New Issue
Block a user