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