From 2d763c669aef350b041b55ced45d9ab3e32553da 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,
- ),
},
})