From 6588672a3cae825439c4e9473c207fe5fd30d88a Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Tue, 26 Aug 2025 19:07:07 -0700 Subject: [PATCH] Race condition on startup of AV still... --- client/src/MediaControl.tsx | 470 ++++++++++++++++++++++++------------ server/main.py | 86 +++++-- 2 files changed, 371 insertions(+), 185 deletions(-) diff --git a/client/src/MediaControl.tsx b/client/src/MediaControl.tsx index 23f0099..b2c1edb 100644 --- a/client/src/MediaControl.tsx +++ b/client/src/MediaControl.tsx @@ -13,6 +13,113 @@ import { Session } from "./GlobalContext"; const debug = true; +const createAnimatedVideoTrack = ({ width = 320, height = 240 } = {}): MediaStreamTrack => { + const canvas = document.createElement("canvas"); + canvas.width = width; + canvas.height = height; + + const ctx = canvas.getContext("2d"); + if (!ctx) throw new Error("Could not get canvas context"); + + // Ball properties + const ball = { + x: width / 2, + y: height / 2, + radius: Math.min(width, height) * 0.06, + dx: 3, + dy: 2, + color: "#00ff88", + }; + + // Create stream BEFORE starting animation + const stream = canvas.captureStream(15); + const track = stream.getVideoTracks()[0]; + + function drawFrame() { + if (!ctx) return; + // Clear canvas + ctx.fillStyle = "#000000"; + ctx.fillRect(0, 0, width, height); + + // Update ball position + ball.x += ball.dx; + ball.y += ball.dy; + + // Bounce off walls + if (ball.x + ball.radius >= width || ball.x - ball.radius <= 0) { + ball.dx = -ball.dx; + } + if (ball.y + ball.radius >= height || ball.y - ball.radius <= 0) { + ball.dy = -ball.dy; + } + + // Keep ball in bounds + ball.x = Math.max(ball.radius, Math.min(width - ball.radius, ball.x)); + ball.y = Math.max(ball.radius, Math.min(height - ball.radius, ball.y)); + + // Draw ball + ctx.beginPath(); + ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2); + ctx.fillStyle = ball.color; + ctx.fill(); + + // Add frame number or timestamp for debugging + ctx.fillStyle = "#ffffff"; + ctx.font = "12px Arial"; + ctx.fillText(`Frame: ${Date.now() % 10000}`, 10, 20); + } + + // Draw initial frame + drawFrame(); + + // Start animation - CRITICAL: Request animation frame for better performance + function animate() { + drawFrame(); + requestAnimationFrame(animate); + } + animate(); + + track.enabled = true; + return track; +}; + +const createBlackVideoTrack = ({ width = 320, height = 240 } = {}): MediaStreamTrack => { + const canvas = document.createElement("canvas"); + canvas.width = width; + canvas.height = height; + + const ctx = canvas.getContext("2d"); + if (ctx) { + ctx.fillStyle = "black"; + ctx.fillRect(0, 0, width, height); + } + + // Use 1 FPS instead of 30 for synthetic tracks + const stream = canvas.captureStream(1); + return stream.getVideoTracks()[0]; +}; + +// Helper function to create a silent audio track +const createSilentAudioTrack = (): MediaStreamTrack => { + const audioContext = new AudioContext(); + const oscillator = audioContext.createOscillator(); + const gainNode = audioContext.createGain(); + const destination = audioContext.createMediaStreamDestination(); + + // Set gain to 0 for silence + gainNode.gain.value = 0; + + // Connect: oscillator -> gain -> destination + oscillator.connect(gainNode); + gainNode.connect(destination); + + oscillator.start(); + + const track = destination.stream.getAudioTracks()[0]; + track.enabled = true; + return track; +}; + // Types for peer and track context interface Peer { session_id: string; @@ -25,13 +132,14 @@ interface Peer { local: boolean; dead: boolean; connection?: RTCPeerConnection; + queuedCandidates?: RTCIceCandidateInit[]; } export type { Peer }; interface TrackContext { media: MediaStream | null; - audio: boolean; - video: boolean; + has_audio: boolean; + has_video: boolean; } interface AddPeerConfig { @@ -63,24 +171,42 @@ interface VideoProps extends React.VideoHTMLAttributes { const Video: React.FC = ({ srcObject, local, ...props }) => { const refVideo = useRef(null); + useEffect(() => { - if (!refVideo.current) { + if (!refVideo.current || !srcObject) { return; } + const ref = refVideo.current; - if (debug) console.log("media-control - video