Co-authored-by: Reifonas <211114984+Reifonas@users.noreply.github.com>
This commit is contained in:
gpt-engineer-app[bot]
2026-05-14 19:04:44 +00:00
parent 10a0c83584
commit 63852195fc
+15 -11
View File
@@ -1,6 +1,7 @@
import {
joinSignalingChannel,
sendSignal,
waitForSignalingReady,
ICE_SERVERS,
type SignalMessage,
} from './signaling';
@@ -17,6 +18,7 @@ export async function joinAsViewer(
code: string,
videoEl: HTMLVideoElement,
onState: (s: 'connecting' | 'waiting' | 'live' | 'error', detail?: string) => void,
onFallbackFrame?: (dataUrl: string) => void,
): Promise<ViewerHandle> {
const viewerId = crypto.randomUUID();
let pc: RTCPeerConnection | null = null;
@@ -25,18 +27,24 @@ export async function joinAsViewer(
onState('connecting');
const handleMessage = async (msg: SignalMessage) => {
if (msg.type === 'frame') {
onFallbackFrame?.(msg.dataUrl);
onState('live');
return;
}
if (msg.type === 'offer' && msg.viewerId === viewerId) {
pc = new RTCPeerConnection({ iceServers: ICE_SERVERS });
pc.ontrack = (ev) => {
videoEl.srcObject = ev.streams[0];
videoEl.srcObject = ev.streams[0] ?? new MediaStream([ev.track]);
videoEl.play().catch(() => {/* autoplay may need user gesture */});
onState('live');
};
pc.onicecandidate = (ev) => {
if (ev.candidate && channel) {
sendSignal(channel, {
void sendSignal(channel, {
type: 'ice',
viewerId,
from: 'viewer',
@@ -54,7 +62,7 @@ export async function joinAsViewer(
await pc.setRemoteDescription(msg.sdp);
const answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
if (channel) sendSignal(channel, { type: 'answer', viewerId, sdp: answer });
if (channel) await sendSignal(channel, { type: 'answer', viewerId, sdp: answer });
} else if (msg.type === 'ice' && msg.viewerId === viewerId && msg.from === 'broadcaster') {
if (pc) {
try {
@@ -67,18 +75,14 @@ export async function joinAsViewer(
};
channel = joinSignalingChannel(code, handleMessage);
await waitForSignalingReady(channel);
// Wait a tick for subscribe, then announce join
setTimeout(() => {
if (channel) {
sendSignal(channel, { type: 'viewer-join', viewerId });
onState('waiting');
}
}, 600);
await sendSignal(channel, { type: 'viewer-join', viewerId });
onState('waiting');
const stop = async () => {
if (channel) {
try { sendSignal(channel, { type: 'viewer-leave', viewerId }); } catch {}
try { await sendSignal(channel, { type: 'viewer-leave', viewerId }); } catch {}
const { supabase } = await import('@/integrations/supabase/client');
await supabase.removeChannel(channel);
}