From 84e737216d7d04fb1631d81abc12f154082568da Mon Sep 17 00:00:00 2001 From: Jeff Emmett <46964190+Jeff-Emmett@users.noreply.github.com> Date: Mon, 9 Dec 2024 03:42:44 -0500 Subject: [PATCH] videochat working --- .env.example | 4 +- .gitignore | 2 - src/App.tsx | 22 ++- src/shapes/VideoChatShapeUtil.tsx | 265 +++++++++--------------------- vite.config.ts | 6 - 5 files changed, 96 insertions(+), 203 deletions(-) diff --git a/.env.example b/.env.example index 343532a..dcfe279 100644 --- a/.env.example +++ b/.env.example @@ -15,5 +15,5 @@ R2_BUCKET_NAME='your_bucket_name' R2_PREVIEW_BUCKET_NAME='your_preview_bucket_name' # Daily.co Configuration -DAILY_API_KEY='your_daily_api_key' -DAILY_DOMAIN='your_daily_domain' \ No newline at end of file +VITE_DAILY_API_KEY=your_daily_api_key_here +VITE_DAILY_DOMAIN='your_daily_domain' \ No newline at end of file diff --git a/.gitignore b/.gitignore index f6d9952..7e702d5 100644 --- a/.gitignore +++ b/.gitignore @@ -175,7 +175,5 @@ dist .env.*.local .dev.vars -# Keep example file -!.env.example package-lock.json \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index beaea4f..f083919 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -19,6 +19,8 @@ import { MarkdownShape } from "./shapes/MarkdownShapeUtil" import { MarkdownTool } from "./tools/MarkdownTool" import { createRoot } from "react-dom/client" import { handleInitialPageLoad } from "./utils/handleInitialPageLoad" +import { DailyProvider } from "@daily-co/daily-react" +import Daily from "@daily-co/daily-js" inject() @@ -30,6 +32,8 @@ const customShapeUtils = [ ] const customTools = [ChatBoxTool, VideoChatTool, EmbedTool, MarkdownTool] +const callObject = Daily.createCallObject() + export default function InteractiveShapeExample() { return (
@@ -64,14 +68,16 @@ function App() { console.log("App initialized, NODE_ENV:", process.env.NODE_ENV) return ( - - - } /> - } /> - } /> - } /> - - + + + + } /> + } /> + } /> + } /> + + + ) } diff --git a/src/shapes/VideoChatShapeUtil.tsx b/src/shapes/VideoChatShapeUtil.tsx index 55bbde9..ad087fb 100644 --- a/src/shapes/VideoChatShapeUtil.tsx +++ b/src/shapes/VideoChatShapeUtil.tsx @@ -1,13 +1,5 @@ import { BaseBoxShapeUtil, TLBaseShape } from "tldraw" -import { useEffect, useState, useRef } from "react" -import { WORKER_URL } from "../routes/Board" -import DailyIframe from "@daily-co/daily-js" - -interface Window { - DailyIframe: { - setLogLevel(level: "error" | "warn" | "info" | "debug"): void - } -} +import { useEffect, useState } from "react" export type IVideoChatShape = TLBaseShape< "VideoChat", @@ -15,63 +7,11 @@ export type IVideoChatShape = TLBaseShape< w: number h: number roomUrl: string | null - userName: string + allowCamera: boolean + allowMicrophone: boolean } > -interface DailyApiError { - error: string - info?: string - message?: string -} - -// Simplified component using Daily Prebuilt -const VideoChatComponent = ({ roomUrl }: { roomUrl: string }) => { - const wrapperRef = useRef(null) - const callFrameRef = useRef | null>(null) - - useEffect(() => { - if (!wrapperRef.current || !roomUrl) return - - // Create and configure the Daily call frame - callFrameRef.current = DailyIframe.createFrame(wrapperRef.current, { - iframeStyle: { - width: "100%", - height: "100%", - border: "0", - borderRadius: "4px", - }, - showLeaveButton: true, - showFullscreenButton: true, - }) - - // Join the room - callFrameRef.current.join({ url: roomUrl }) - - // Cleanup - return () => { - if (callFrameRef.current) { - callFrameRef.current.destroy() - } - } - }, [roomUrl]) - - return ( -
- ) -} - export class VideoChatShape extends BaseBoxShapeUtil { static override type = "VideoChat" @@ -84,86 +24,45 @@ export class VideoChatShape extends BaseBoxShapeUtil { roomUrl: null, w: 640, h: 480, - userName: "", + allowCamera: false, + allowMicrophone: false, } } async ensureRoomExists(shape: IVideoChatShape) { - console.log("Environment variables:", { - NODE_ENV: process.env.NODE_ENV, - allEnvVars: import.meta.env, - dailyApiKey: import.meta.env.VITE_DAILY_API_KEY, - }) - - if (shape.props.roomUrl !== null) { - return - } + if (shape.props.roomUrl !== null) return try { - // Ensure API key exists and is properly formatted - const apiKey = import.meta.env.VITE_DAILY_API_KEY?.trim() - console.log("API Key exists:", !!apiKey) - console.log( - "API Key format:", - apiKey?.substring(0, 4) === "key_" ? "correct" : "incorrect", - ) - console.log("Available env vars:", import.meta.env) + const apiKey = import.meta.env["VITE_DAILY_API_KEY"] + if (!apiKey) throw new Error("Daily API key is missing") - if (!apiKey) { - throw new Error("Daily API key is missing") - } - - // Create room using Daily.co API directly - const response = await fetch(`https://api.daily.co/v1/rooms`, { + const response = await fetch("https://api.daily.co/v1/rooms", { method: "POST", headers: { "Content-Type": "application/json", - // Ensure no extra spaces in the Authorization header - Authorization: `Bearer ${apiKey}`.trim(), + Authorization: `Bearer ${apiKey.trim()}`, }, body: JSON.stringify({ properties: { enable_chat: true, start_audio_off: true, start_video_off: true, - enable_screenshare: true, - enable_recording: true, - max_participants: 8, - enable_network_ui: true, - enable_prejoin_ui: true, - enable_people_ui: true, - enable_pip_ui: true, - enable_emoji_reactions: true, - enable_hand_raising: true, - enable_noise_cancellation_ui: true, }, }), }) - if (!response.ok) { - const errorData = (await response.json()) as DailyApiError - console.error("Daily API Error:", { - status: response.status, - statusText: response.statusText, - errorData, - authHeader: `Bearer ${apiKey.substring(0, 5)}...`, // Log first 5 chars for debugging - }) - throw new Error( - errorData.message || - errorData.info || - `Failed to create room (${response.status})`, - ) - } + if (!response.ok) + throw new Error(`Failed to create room (${response.status})`) - const { url } = (await response.json()) as { url: string } + const responseData = (await response.json()) as { url: string } + const url = responseData.url + + if (!url) throw new Error("Room URL is missing") this.editor.updateShape({ id: shape.id, type: "VideoChat", - props: { - ...shape.props, - roomUrl: url, - }, + props: { ...shape.props, roomUrl: url }, }) } catch (error) { console.error("Failed to create Daily room:", error) @@ -172,48 +71,39 @@ export class VideoChatShape extends BaseBoxShapeUtil { } component(shape: IVideoChatShape) { - const [isInRoom, setIsInRoom] = useState(false) - const [error, setError] = useState("") - const [isLoading, setIsLoading] = useState(false) + const [hasPermissions, setHasPermissions] = useState(false) useEffect(() => { - setIsLoading(true) - this.ensureRoomExists(shape) - .catch((err) => setError(err.message)) - .finally(() => setIsLoading(false)) + this.ensureRoomExists(shape).catch(console.error) }, []) - // useEffect(() => { - // // Disable Daily.co debug logs - // if (window.DailyIframe) { - // window.DailyIframe.setLogLevel("error") - // } - // }, []) + useEffect(() => { + // Request permissions when needed + const requestPermissions = async () => { + try { + if (shape.props.allowCamera || shape.props.allowMicrophone) { + const constraints = { + video: shape.props.allowCamera, + audio: shape.props.allowMicrophone, + } + await navigator.mediaDevices.getUserMedia(constraints) + setHasPermissions(true) + } + } catch (error) { + console.error("Permission request failed:", error) + setHasPermissions(false) + } + } - if (isLoading) { - return ( -
-
Initializing video chat...
-
- ) - } + requestPermissions() + }, [shape.props.allowCamera, shape.props.allowMicrophone]) if (!shape.props.roomUrl) { return (
{ ) } + // Construct URL with permission parameters + const roomUrlWithParams = new URL(shape.props.roomUrl) + roomUrlWithParams.searchParams.set( + "allow_camera", + String(shape.props.allowCamera), + ) + roomUrlWithParams.searchParams.set( + "allow_mic", + String(shape.props.allowMicrophone), + ) + + console.log(shape.props.roomUrl) + return (
- {!isInRoom ? ( - - ) : ( - - )} - {error && ( -
- {error} -
- )} + +

+ url: {shape.props.roomUrl} +

) } diff --git a/vite.config.ts b/vite.config.ts index a7e6629..c2facbd 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -22,11 +22,5 @@ export default defineConfig({ "import.meta.env.VITE_WORKER_URL": JSON.stringify( process.env.VITE_WORKER_URL, ), - "import.meta.env.VITE_DAILY_DOMAIN": JSON.stringify( - "https://mycopunks.daily.co", - ), - "import.meta.env.VITE_DAILY_API_KEY": JSON.stringify( - process.env.VITE_DAILY_API_KEY, - ), }, })