sa2kit 1.6.66 → 1.6.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/festivalCard/index.d.mts +10 -0
- package/dist/festivalCard/index.d.ts +10 -0
- package/dist/festivalCard/index.js +206 -0
- package/dist/festivalCard/index.js.map +1 -0
- package/dist/festivalCard/index.mjs +181 -0
- package/dist/festivalCard/index.mjs.map +1 -0
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +210 -18
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +208 -18
- package/dist/index.mjs.map +1 -1
- package/dist/screenReceiver/core/index.d.mts +10 -2
- package/dist/screenReceiver/core/index.d.ts +10 -2
- package/dist/screenReceiver/core/index.js +15 -0
- package/dist/screenReceiver/core/index.js.map +1 -1
- package/dist/screenReceiver/core/index.mjs +15 -1
- package/dist/screenReceiver/core/index.mjs.map +1 -1
- package/dist/screenReceiver/index.d.mts +1 -1
- package/dist/screenReceiver/index.d.ts +1 -1
- package/dist/screenReceiver/index.js +21 -3
- package/dist/screenReceiver/index.js.map +1 -1
- package/dist/screenReceiver/index.mjs +21 -4
- package/dist/screenReceiver/index.mjs.map +1 -1
- package/dist/screenReceiver/server/index.js +1 -1
- package/dist/screenReceiver/server/index.js.map +1 -1
- package/dist/screenReceiver/server/index.mjs +1 -1
- package/dist/screenReceiver/server/index.mjs.map +1 -1
- package/dist/screenReceiver/server/next.d.mts +9 -0
- package/dist/screenReceiver/server/next.d.ts +9 -0
- package/dist/screenReceiver/server/next.js +178 -0
- package/dist/screenReceiver/server/next.js.map +1 -0
- package/dist/screenReceiver/server/next.mjs +176 -0
- package/dist/screenReceiver/server/next.mjs.map +1 -0
- package/dist/screenReceiver/web/index.d.mts +1 -1
- package/dist/screenReceiver/web/index.d.ts +1 -1
- package/dist/screenReceiver/web/index.js +21 -3
- package/dist/screenReceiver/web/index.js.map +1 -1
- package/dist/screenReceiver/web/index.mjs +21 -4
- package/dist/screenReceiver/web/index.mjs.map +1 -1
- package/package.json +11 -1
|
@@ -198,11 +198,28 @@ function useScreenReceiver(options) {
|
|
|
198
198
|
[clearLogs, connect, connectionState, disconnect, iceConnectionState, isConnected, logs, stream]
|
|
199
199
|
);
|
|
200
200
|
}
|
|
201
|
-
|
|
201
|
+
|
|
202
|
+
// src/screenReceiver/signalUrl.ts
|
|
203
|
+
var DEFAULT_PORT = 8787;
|
|
204
|
+
var DEFAULT_PATH = "/ws";
|
|
205
|
+
function resolveScreenReceiverSignalUrl(options = {}) {
|
|
206
|
+
const { signalUrl, path = DEFAULT_PATH, port = DEFAULT_PORT } = options;
|
|
207
|
+
if (signalUrl && signalUrl.trim()) return signalUrl.trim();
|
|
208
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
209
|
+
if (typeof window !== "undefined") {
|
|
210
|
+
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
|
211
|
+
return `${protocol}//${window.location.host}${normalizedPath}`;
|
|
212
|
+
}
|
|
213
|
+
return `ws://127.0.0.1:${port}${normalizedPath}`;
|
|
214
|
+
}
|
|
202
215
|
var DEFAULT_ROOM_ID = "screen-room-1";
|
|
203
216
|
function ScreenReceiverPanel(props) {
|
|
204
|
-
const { defaultSignalUrl
|
|
205
|
-
const
|
|
217
|
+
const { defaultSignalUrl, defaultRoomId = DEFAULT_ROOM_ID, className } = props;
|
|
218
|
+
const initialSignalUrl = React.useMemo(
|
|
219
|
+
() => resolveScreenReceiverSignalUrl({ signalUrl: defaultSignalUrl }),
|
|
220
|
+
[defaultSignalUrl]
|
|
221
|
+
);
|
|
222
|
+
const [wsUrl, setWsUrl] = React.useState(initialSignalUrl);
|
|
206
223
|
const [roomId, setRoomId] = React.useState(defaultRoomId);
|
|
207
224
|
const receiver = useScreenReceiver({ wsUrl, roomId });
|
|
208
225
|
const logs = React.useMemo(() => receiver.logs.map((entry) => entry.text).join("\n"), [receiver.logs]);
|
|
@@ -258,6 +275,7 @@ function StatusItem({ label, value }) {
|
|
|
258
275
|
}
|
|
259
276
|
|
|
260
277
|
exports.ScreenReceiverPanel = ScreenReceiverPanel;
|
|
278
|
+
exports.resolveScreenReceiverSignalUrl = resolveScreenReceiverSignalUrl;
|
|
261
279
|
exports.useScreenReceiver = useScreenReceiver;
|
|
262
280
|
//# sourceMappingURL=index.js.map
|
|
263
281
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/screenReceiver/useScreenReceiver.ts","../../../src/screenReceiver/ScreenReceiverPanel.tsx"],"names":["useState","useRef","useCallback","useEffect","useMemo","React"],"mappings":"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","file":"index.js","sourcesContent":["import type { RefObject } from 'react';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type {\n ScreenReceiverJoinedMessage,\n ScreenReceiverPeerLeftMessage,\n ScreenReceiverRoomStateMessage,\n} from './types';\n\nconst DEFAULT_STUN_SERVER: RTCIceServer = { urls: 'stun:stun.l.google.com:19302' };\n\nexport interface ScreenReceiverLogEntry {\n id: number;\n text: string;\n}\n\nexport interface UseScreenReceiverOptions {\n wsUrl: string;\n roomId: string;\n iceServers?: RTCIceServer[];\n maxLogs?: number;\n}\n\nexport interface UseScreenReceiverReturn {\n connect: () => Promise<void>;\n disconnect: () => void;\n clearLogs: () => void;\n logs: ScreenReceiverLogEntry[];\n isConnected: boolean;\n connectionState: RTCPeerConnectionState | 'idle';\n iceConnectionState: RTCIceConnectionState | 'idle';\n videoRef: RefObject<HTMLVideoElement>;\n stream: MediaStream | null;\n}\n\ntype PeerContext = {\n ws?: WebSocket;\n pc?: RTCPeerConnection;\n pendingCandidates: RTCIceCandidateInit[];\n selfPeerId?: string;\n publisherPeerId?: string;\n};\n\nfunction parseMessage(payload: MessageEvent['data']): Record<string, any> | null {\n try {\n if (typeof payload === 'string') return JSON.parse(payload);\n if (payload instanceof ArrayBuffer) return JSON.parse(new TextDecoder().decode(payload));\n return JSON.parse(String(payload));\n } catch {\n return null;\n }\n}\n\nexport function useScreenReceiver(options: UseScreenReceiverOptions): UseScreenReceiverReturn {\n const { wsUrl, roomId, iceServers = [DEFAULT_STUN_SERVER], maxLogs = 80 } = options;\n const [logs, setLogs] = useState<ScreenReceiverLogEntry[]>([]);\n const [isConnected, setIsConnected] = useState(false);\n const [connectionState, setConnectionState] = useState<RTCPeerConnectionState | 'idle'>('idle');\n const [iceConnectionState, setIceConnectionState] = useState<RTCIceConnectionState | 'idle'>('idle');\n const [stream, setStream] = useState<MediaStream | null>(null);\n const logIdRef = useRef(0);\n const peerRef = useRef<PeerContext>({ pendingCandidates: [] });\n const videoRef = useRef<HTMLVideoElement>(null);\n\n const appendLog = useCallback(\n (text: string) => {\n logIdRef.current += 1;\n setLogs((prev) => [...prev, { id: logIdRef.current, text }].slice(-maxLogs));\n },\n [maxLogs],\n );\n\n const disconnect = useCallback(() => {\n peerRef.current.ws?.close();\n peerRef.current.pc?.close();\n peerRef.current = { pendingCandidates: [] };\n setIsConnected(false);\n setConnectionState('idle');\n setIceConnectionState('idle');\n setStream(null);\n }, []);\n\n const connect = useCallback(async () => {\n disconnect();\n\n const normalizedWsUrl = wsUrl.trim();\n const normalizedRoomId = roomId.trim();\n if (!normalizedWsUrl) {\n appendLog('ws url is empty');\n return;\n }\n if (!normalizedRoomId) {\n appendLog('room id is empty');\n return;\n }\n\n appendLog(`connecting: ${normalizedWsUrl}`);\n\n let ws: WebSocket;\n try {\n ws = new WebSocket(normalizedWsUrl);\n } catch (error) {\n appendLog(`ws create error: ${String(error)}`);\n return;\n }\n\n const pc = new RTCPeerConnection({ iceServers });\n pc.addTransceiver('video', { direction: 'recvonly' });\n\n peerRef.current.ws = ws;\n peerRef.current.pc = pc;\n peerRef.current.pendingCandidates = [];\n\n ws.onopen = () => {\n appendLog('ws connected');\n setIsConnected(true);\n ws.send(JSON.stringify({ type: 'join', roomId: normalizedRoomId, role: 'viewer' }));\n };\n\n ws.onclose = () => {\n appendLog('ws closed');\n setIsConnected(false);\n };\n\n ws.onerror = (event) => {\n appendLog(`ws error: ${event.type}`);\n };\n\n ws.onmessage = async (event) => {\n const message = parseMessage(event.data);\n if (!message) {\n appendLog('ws message parse error');\n return;\n }\n\n if (message.type === 'joined') {\n const joined = message as ScreenReceiverJoinedMessage;\n peerRef.current.selfPeerId = joined.peerId;\n appendLog(`joined room ${joined.roomId} as ${joined.peerId}`);\n return;\n }\n\n if (message.type === 'room_state') {\n const roomState = message as ScreenReceiverRoomStateMessage;\n const broadcaster = roomState.peers.find((peer) => peer.role === 'broadcaster');\n if (broadcaster) {\n peerRef.current.publisherPeerId = broadcaster.peerId;\n appendLog(`broadcaster online: ${broadcaster.peerId}`);\n }\n return;\n }\n\n if (message.type === 'offer' && typeof message.sdp === 'string') {\n appendLog('offer received');\n peerRef.current.publisherPeerId = typeof message.fromPeerId === 'string' ? message.fromPeerId : undefined;\n await pc.setRemoteDescription({ type: 'offer', sdp: message.sdp });\n for (const candidate of peerRef.current.pendingCandidates) {\n try {\n await pc.addIceCandidate(candidate);\n } catch (error) {\n appendLog(`ice err: ${String(error)}`);\n }\n }\n peerRef.current.pendingCandidates = [];\n\n const answer = await pc.createAnswer();\n await pc.setLocalDescription(answer);\n ws.send(\n JSON.stringify({\n type: 'answer',\n sdp: answer.sdp,\n targetPeerId: peerRef.current.publisherPeerId,\n }),\n );\n appendLog('answer sent');\n return;\n }\n\n if (message.type === 'ice' && message.candidate) {\n if (!pc.remoteDescription) {\n peerRef.current.pendingCandidates.push(message.candidate as RTCIceCandidateInit);\n return;\n }\n try {\n await pc.addIceCandidate(message.candidate as RTCIceCandidateInit);\n } catch (error) {\n appendLog(`ice err: ${String(error)}`);\n }\n return;\n }\n\n if (message.type === 'peer_left') {\n const peerLeft = message as ScreenReceiverPeerLeftMessage;\n if (peerLeft.peerId === peerRef.current.publisherPeerId) {\n peerRef.current.publisherPeerId = undefined;\n appendLog(`publisher left: ${peerLeft.peerId}`);\n }\n return;\n }\n\n if (message.type === 'error') {\n appendLog(`server error: ${String(message.reason ?? 'unknown')}`);\n }\n };\n\n pc.ontrack = (event) => {\n const receivedStream = event.streams[0];\n if (receivedStream) {\n setStream(receivedStream);\n appendLog('track received');\n }\n };\n\n pc.onicecandidate = (event) => {\n if (!event.candidate) return;\n ws.send(\n JSON.stringify({\n type: 'ice',\n candidate: event.candidate,\n targetPeerId: peerRef.current.publisherPeerId,\n }),\n );\n };\n\n pc.onconnectionstatechange = () => {\n const state = pc.connectionState || 'new';\n setConnectionState(state);\n appendLog(`pc state: ${state}`);\n };\n\n pc.oniceconnectionstatechange = () => {\n const state = pc.iceConnectionState || 'new';\n setIceConnectionState(state);\n appendLog(`ice state: ${state}`);\n };\n }, [appendLog, disconnect, iceServers, roomId, wsUrl]);\n\n useEffect(() => () => disconnect(), [disconnect]);\n\n useEffect(() => {\n if (!videoRef.current) return;\n videoRef.current.srcObject = stream;\n }, [stream]);\n\n const clearLogs = useCallback(() => setLogs([]), []);\n\n return useMemo(\n () => ({\n connect,\n disconnect,\n clearLogs,\n logs,\n isConnected,\n connectionState,\n iceConnectionState,\n videoRef,\n stream,\n }),\n [clearLogs, connect, connectionState, disconnect, iceConnectionState, isConnected, logs, stream],\n );\n}\n","import React, { useMemo, useState } from 'react';\nimport { useScreenReceiver } from './useScreenReceiver';\n\nexport interface ScreenReceiverPanelProps {\n defaultSignalUrl?: string;\n defaultRoomId?: string;\n className?: string;\n}\n\nconst DEFAULT_SIGNAL_URL = 'ws://127.0.0.1:8787/ws';\nconst DEFAULT_ROOM_ID = 'screen-room-1';\n\nexport function ScreenReceiverPanel(props: ScreenReceiverPanelProps) {\n const { defaultSignalUrl = DEFAULT_SIGNAL_URL, defaultRoomId = DEFAULT_ROOM_ID, className } = props;\n const [wsUrl, setWsUrl] = useState(defaultSignalUrl);\n const [roomId, setRoomId] = useState(defaultRoomId);\n const receiver = useScreenReceiver({ wsUrl, roomId });\n const logs = useMemo(() => receiver.logs.map((entry) => entry.text).join('\\n'), [receiver.logs]);\n\n return (\n <div className={className}>\n <div className=\"flex flex-col gap-4\">\n <div className=\"grid gap-3 md:grid-cols-[2fr,1fr,auto]\">\n <label className=\"flex flex-col gap-1 text-sm\">\n <span>Signaling WS</span>\n <input\n className=\"rounded-md border px-3 py-2\"\n value={wsUrl}\n onChange={(event) => setWsUrl(event.target.value)}\n />\n </label>\n <label className=\"flex flex-col gap-1 text-sm\">\n <span>Room</span>\n <input\n className=\"rounded-md border px-3 py-2\"\n value={roomId}\n onChange={(event) => setRoomId(event.target.value)}\n />\n </label>\n <div className=\"flex items-end gap-2\">\n <button\n onClick={() => void receiver.connect()}\n className=\"rounded-md border bg-black px-4 py-2 text-sm text-white\"\n >\n {receiver.isConnected ? 'Reconnect' : 'Connect'}\n </button>\n <button\n onClick={receiver.disconnect}\n className=\"rounded-md border px-4 py-2 text-sm\"\n >\n Disconnect\n </button>\n </div>\n </div>\n\n <div className=\"grid gap-3 md:grid-cols-3\">\n <StatusItem label=\"WebSocket\" value={receiver.isConnected ? 'connected' : 'idle'} />\n <StatusItem label=\"PeerConnection\" value={receiver.connectionState} />\n <StatusItem label=\"ICE State\" value={receiver.iceConnectionState} />\n </div>\n\n <div className=\"grid gap-4 lg:grid-cols-[3fr,2fr]\">\n <div className=\"rounded-xl border bg-black p-3\">\n <video\n ref={receiver.videoRef}\n autoPlay\n playsInline\n controls\n muted\n className=\"h-[360px] w-full rounded-lg bg-black\"\n />\n </div>\n <div className=\"rounded-xl border p-3\">\n <div className=\"flex items-center justify-between\">\n <p className=\"text-sm font-semibold\">Session Log</p>\n <button\n onClick={receiver.clearLogs}\n className=\"text-xs underline-offset-2 hover:underline\"\n >\n Clear\n </button>\n </div>\n <pre className=\"mt-3 h-[320px] overflow-auto rounded-lg border bg-slate-50 p-3 text-xs\">\n {logs || 'No logs yet.'}\n </pre>\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nfunction StatusItem({ label, value }: { label: string; value: string }) {\n return (\n <div className=\"rounded-md border px-3 py-2\">\n <p className=\"text-xs text-slate-500\">{label}</p>\n <p className=\"text-sm font-medium\">{value}</p>\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/screenReceiver/useScreenReceiver.ts","../../../src/screenReceiver/signalUrl.ts","../../../src/screenReceiver/ScreenReceiverPanel.tsx"],"names":["useState","useRef","useCallback","useEffect","useMemo","React"],"mappings":"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","file":"index.js","sourcesContent":["import type { RefObject } from 'react';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type {\n ScreenReceiverJoinedMessage,\n ScreenReceiverPeerLeftMessage,\n ScreenReceiverRoomStateMessage,\n} from './types';\n\nconst DEFAULT_STUN_SERVER: RTCIceServer = { urls: 'stun:stun.l.google.com:19302' };\n\nexport interface ScreenReceiverLogEntry {\n id: number;\n text: string;\n}\n\nexport interface UseScreenReceiverOptions {\n wsUrl: string;\n roomId: string;\n iceServers?: RTCIceServer[];\n maxLogs?: number;\n}\n\nexport interface UseScreenReceiverReturn {\n connect: () => Promise<void>;\n disconnect: () => void;\n clearLogs: () => void;\n logs: ScreenReceiverLogEntry[];\n isConnected: boolean;\n connectionState: RTCPeerConnectionState | 'idle';\n iceConnectionState: RTCIceConnectionState | 'idle';\n videoRef: RefObject<HTMLVideoElement>;\n stream: MediaStream | null;\n}\n\ntype PeerContext = {\n ws?: WebSocket;\n pc?: RTCPeerConnection;\n pendingCandidates: RTCIceCandidateInit[];\n selfPeerId?: string;\n publisherPeerId?: string;\n};\n\nfunction parseMessage(payload: MessageEvent['data']): Record<string, any> | null {\n try {\n if (typeof payload === 'string') return JSON.parse(payload);\n if (payload instanceof ArrayBuffer) return JSON.parse(new TextDecoder().decode(payload));\n return JSON.parse(String(payload));\n } catch {\n return null;\n }\n}\n\nexport function useScreenReceiver(options: UseScreenReceiverOptions): UseScreenReceiverReturn {\n const { wsUrl, roomId, iceServers = [DEFAULT_STUN_SERVER], maxLogs = 80 } = options;\n const [logs, setLogs] = useState<ScreenReceiverLogEntry[]>([]);\n const [isConnected, setIsConnected] = useState(false);\n const [connectionState, setConnectionState] = useState<RTCPeerConnectionState | 'idle'>('idle');\n const [iceConnectionState, setIceConnectionState] = useState<RTCIceConnectionState | 'idle'>('idle');\n const [stream, setStream] = useState<MediaStream | null>(null);\n const logIdRef = useRef(0);\n const peerRef = useRef<PeerContext>({ pendingCandidates: [] });\n const videoRef = useRef<HTMLVideoElement>(null);\n\n const appendLog = useCallback(\n (text: string) => {\n logIdRef.current += 1;\n setLogs((prev) => [...prev, { id: logIdRef.current, text }].slice(-maxLogs));\n },\n [maxLogs],\n );\n\n const disconnect = useCallback(() => {\n peerRef.current.ws?.close();\n peerRef.current.pc?.close();\n peerRef.current = { pendingCandidates: [] };\n setIsConnected(false);\n setConnectionState('idle');\n setIceConnectionState('idle');\n setStream(null);\n }, []);\n\n const connect = useCallback(async () => {\n disconnect();\n\n const normalizedWsUrl = wsUrl.trim();\n const normalizedRoomId = roomId.trim();\n if (!normalizedWsUrl) {\n appendLog('ws url is empty');\n return;\n }\n if (!normalizedRoomId) {\n appendLog('room id is empty');\n return;\n }\n\n appendLog(`connecting: ${normalizedWsUrl}`);\n\n let ws: WebSocket;\n try {\n ws = new WebSocket(normalizedWsUrl);\n } catch (error) {\n appendLog(`ws create error: ${String(error)}`);\n return;\n }\n\n const pc = new RTCPeerConnection({ iceServers });\n pc.addTransceiver('video', { direction: 'recvonly' });\n\n peerRef.current.ws = ws;\n peerRef.current.pc = pc;\n peerRef.current.pendingCandidates = [];\n\n ws.onopen = () => {\n appendLog('ws connected');\n setIsConnected(true);\n ws.send(JSON.stringify({ type: 'join', roomId: normalizedRoomId, role: 'viewer' }));\n };\n\n ws.onclose = () => {\n appendLog('ws closed');\n setIsConnected(false);\n };\n\n ws.onerror = (event) => {\n appendLog(`ws error: ${event.type}`);\n };\n\n ws.onmessage = async (event) => {\n const message = parseMessage(event.data);\n if (!message) {\n appendLog('ws message parse error');\n return;\n }\n\n if (message.type === 'joined') {\n const joined = message as ScreenReceiverJoinedMessage;\n peerRef.current.selfPeerId = joined.peerId;\n appendLog(`joined room ${joined.roomId} as ${joined.peerId}`);\n return;\n }\n\n if (message.type === 'room_state') {\n const roomState = message as ScreenReceiverRoomStateMessage;\n const broadcaster = roomState.peers.find((peer) => peer.role === 'broadcaster');\n if (broadcaster) {\n peerRef.current.publisherPeerId = broadcaster.peerId;\n appendLog(`broadcaster online: ${broadcaster.peerId}`);\n }\n return;\n }\n\n if (message.type === 'offer' && typeof message.sdp === 'string') {\n appendLog('offer received');\n peerRef.current.publisherPeerId = typeof message.fromPeerId === 'string' ? message.fromPeerId : undefined;\n await pc.setRemoteDescription({ type: 'offer', sdp: message.sdp });\n for (const candidate of peerRef.current.pendingCandidates) {\n try {\n await pc.addIceCandidate(candidate);\n } catch (error) {\n appendLog(`ice err: ${String(error)}`);\n }\n }\n peerRef.current.pendingCandidates = [];\n\n const answer = await pc.createAnswer();\n await pc.setLocalDescription(answer);\n ws.send(\n JSON.stringify({\n type: 'answer',\n sdp: answer.sdp,\n targetPeerId: peerRef.current.publisherPeerId,\n }),\n );\n appendLog('answer sent');\n return;\n }\n\n if (message.type === 'ice' && message.candidate) {\n if (!pc.remoteDescription) {\n peerRef.current.pendingCandidates.push(message.candidate as RTCIceCandidateInit);\n return;\n }\n try {\n await pc.addIceCandidate(message.candidate as RTCIceCandidateInit);\n } catch (error) {\n appendLog(`ice err: ${String(error)}`);\n }\n return;\n }\n\n if (message.type === 'peer_left') {\n const peerLeft = message as ScreenReceiverPeerLeftMessage;\n if (peerLeft.peerId === peerRef.current.publisherPeerId) {\n peerRef.current.publisherPeerId = undefined;\n appendLog(`publisher left: ${peerLeft.peerId}`);\n }\n return;\n }\n\n if (message.type === 'error') {\n appendLog(`server error: ${String(message.reason ?? 'unknown')}`);\n }\n };\n\n pc.ontrack = (event) => {\n const receivedStream = event.streams[0];\n if (receivedStream) {\n setStream(receivedStream);\n appendLog('track received');\n }\n };\n\n pc.onicecandidate = (event) => {\n if (!event.candidate) return;\n ws.send(\n JSON.stringify({\n type: 'ice',\n candidate: event.candidate,\n targetPeerId: peerRef.current.publisherPeerId,\n }),\n );\n };\n\n pc.onconnectionstatechange = () => {\n const state = pc.connectionState || 'new';\n setConnectionState(state);\n appendLog(`pc state: ${state}`);\n };\n\n pc.oniceconnectionstatechange = () => {\n const state = pc.iceConnectionState || 'new';\n setIceConnectionState(state);\n appendLog(`ice state: ${state}`);\n };\n }, [appendLog, disconnect, iceServers, roomId, wsUrl]);\n\n useEffect(() => () => disconnect(), [disconnect]);\n\n useEffect(() => {\n if (!videoRef.current) return;\n videoRef.current.srcObject = stream;\n }, [stream]);\n\n const clearLogs = useCallback(() => setLogs([]), []);\n\n return useMemo(\n () => ({\n connect,\n disconnect,\n clearLogs,\n logs,\n isConnected,\n connectionState,\n iceConnectionState,\n videoRef,\n stream,\n }),\n [clearLogs, connect, connectionState, disconnect, iceConnectionState, isConnected, logs, stream],\n );\n}\n","const DEFAULT_PORT = 8787;\nconst DEFAULT_PATH = '/ws';\n\nexport interface ResolveScreenReceiverSignalUrlOptions {\n signalUrl?: string;\n path?: string;\n port?: number;\n}\n\nexport function resolveScreenReceiverSignalUrl(\n options: ResolveScreenReceiverSignalUrlOptions = {},\n): string {\n const { signalUrl, path = DEFAULT_PATH, port = DEFAULT_PORT } = options;\n if (signalUrl && signalUrl.trim()) return signalUrl.trim();\n\n const normalizedPath = path.startsWith('/') ? path : `/${path}`;\n if (typeof window !== 'undefined') {\n const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';\n return `${protocol}//${window.location.host}${normalizedPath}`;\n }\n\n return `ws://127.0.0.1:${port}${normalizedPath}`;\n}\n","import React, { useMemo, useState } from 'react';\nimport { resolveScreenReceiverSignalUrl } from './signalUrl';\nimport { useScreenReceiver } from './useScreenReceiver';\n\nexport interface ScreenReceiverPanelProps {\n defaultSignalUrl?: string;\n defaultRoomId?: string;\n className?: string;\n}\n\nconst DEFAULT_ROOM_ID = 'screen-room-1';\n\nexport function ScreenReceiverPanel(props: ScreenReceiverPanelProps) {\n const { defaultSignalUrl, defaultRoomId = DEFAULT_ROOM_ID, className } = props;\n const initialSignalUrl = useMemo(\n () => resolveScreenReceiverSignalUrl({ signalUrl: defaultSignalUrl }),\n [defaultSignalUrl],\n );\n const [wsUrl, setWsUrl] = useState(initialSignalUrl);\n const [roomId, setRoomId] = useState(defaultRoomId);\n const receiver = useScreenReceiver({ wsUrl, roomId });\n const logs = useMemo(() => receiver.logs.map((entry) => entry.text).join('\\n'), [receiver.logs]);\n\n return (\n <div className={className}>\n <div className=\"flex flex-col gap-4\">\n <div className=\"grid gap-3 md:grid-cols-[2fr,1fr,auto]\">\n <label className=\"flex flex-col gap-1 text-sm\">\n <span>Signaling WS</span>\n <input\n className=\"rounded-md border px-3 py-2\"\n value={wsUrl}\n onChange={(event) => setWsUrl(event.target.value)}\n />\n </label>\n <label className=\"flex flex-col gap-1 text-sm\">\n <span>Room</span>\n <input\n className=\"rounded-md border px-3 py-2\"\n value={roomId}\n onChange={(event) => setRoomId(event.target.value)}\n />\n </label>\n <div className=\"flex items-end gap-2\">\n <button\n onClick={() => void receiver.connect()}\n className=\"rounded-md border bg-black px-4 py-2 text-sm text-white\"\n >\n {receiver.isConnected ? 'Reconnect' : 'Connect'}\n </button>\n <button\n onClick={receiver.disconnect}\n className=\"rounded-md border px-4 py-2 text-sm\"\n >\n Disconnect\n </button>\n </div>\n </div>\n\n <div className=\"grid gap-3 md:grid-cols-3\">\n <StatusItem label=\"WebSocket\" value={receiver.isConnected ? 'connected' : 'idle'} />\n <StatusItem label=\"PeerConnection\" value={receiver.connectionState} />\n <StatusItem label=\"ICE State\" value={receiver.iceConnectionState} />\n </div>\n\n <div className=\"grid gap-4 lg:grid-cols-[3fr,2fr]\">\n <div className=\"rounded-xl border bg-black p-3\">\n <video\n ref={receiver.videoRef}\n autoPlay\n playsInline\n controls\n muted\n className=\"h-[360px] w-full rounded-lg bg-black\"\n />\n </div>\n <div className=\"rounded-xl border p-3\">\n <div className=\"flex items-center justify-between\">\n <p className=\"text-sm font-semibold\">Session Log</p>\n <button\n onClick={receiver.clearLogs}\n className=\"text-xs underline-offset-2 hover:underline\"\n >\n Clear\n </button>\n </div>\n <pre className=\"mt-3 h-[320px] overflow-auto rounded-lg border bg-slate-50 p-3 text-xs\">\n {logs || 'No logs yet.'}\n </pre>\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nfunction StatusItem({ label, value }: { label: string; value: string }) {\n return (\n <div className=\"rounded-md border px-3 py-2\">\n <p className=\"text-xs text-slate-500\">{label}</p>\n <p className=\"text-sm font-medium\">{value}</p>\n </div>\n );\n}\n"]}
|
|
@@ -192,11 +192,28 @@ function useScreenReceiver(options) {
|
|
|
192
192
|
[clearLogs, connect, connectionState, disconnect, iceConnectionState, isConnected, logs, stream]
|
|
193
193
|
);
|
|
194
194
|
}
|
|
195
|
-
|
|
195
|
+
|
|
196
|
+
// src/screenReceiver/signalUrl.ts
|
|
197
|
+
var DEFAULT_PORT = 8787;
|
|
198
|
+
var DEFAULT_PATH = "/ws";
|
|
199
|
+
function resolveScreenReceiverSignalUrl(options = {}) {
|
|
200
|
+
const { signalUrl, path = DEFAULT_PATH, port = DEFAULT_PORT } = options;
|
|
201
|
+
if (signalUrl && signalUrl.trim()) return signalUrl.trim();
|
|
202
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
203
|
+
if (typeof window !== "undefined") {
|
|
204
|
+
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
|
205
|
+
return `${protocol}//${window.location.host}${normalizedPath}`;
|
|
206
|
+
}
|
|
207
|
+
return `ws://127.0.0.1:${port}${normalizedPath}`;
|
|
208
|
+
}
|
|
196
209
|
var DEFAULT_ROOM_ID = "screen-room-1";
|
|
197
210
|
function ScreenReceiverPanel(props) {
|
|
198
|
-
const { defaultSignalUrl
|
|
199
|
-
const
|
|
211
|
+
const { defaultSignalUrl, defaultRoomId = DEFAULT_ROOM_ID, className } = props;
|
|
212
|
+
const initialSignalUrl = useMemo(
|
|
213
|
+
() => resolveScreenReceiverSignalUrl({ signalUrl: defaultSignalUrl }),
|
|
214
|
+
[defaultSignalUrl]
|
|
215
|
+
);
|
|
216
|
+
const [wsUrl, setWsUrl] = useState(initialSignalUrl);
|
|
200
217
|
const [roomId, setRoomId] = useState(defaultRoomId);
|
|
201
218
|
const receiver = useScreenReceiver({ wsUrl, roomId });
|
|
202
219
|
const logs = useMemo(() => receiver.logs.map((entry) => entry.text).join("\n"), [receiver.logs]);
|
|
@@ -251,6 +268,6 @@ function StatusItem({ label, value }) {
|
|
|
251
268
|
return /* @__PURE__ */ React.createElement("div", { className: "rounded-md border px-3 py-2" }, /* @__PURE__ */ React.createElement("p", { className: "text-xs text-slate-500" }, label), /* @__PURE__ */ React.createElement("p", { className: "text-sm font-medium" }, value));
|
|
252
269
|
}
|
|
253
270
|
|
|
254
|
-
export { ScreenReceiverPanel, useScreenReceiver };
|
|
271
|
+
export { ScreenReceiverPanel, resolveScreenReceiverSignalUrl, useScreenReceiver };
|
|
255
272
|
//# sourceMappingURL=index.mjs.map
|
|
256
273
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/screenReceiver/useScreenReceiver.ts","../../../src/screenReceiver/ScreenReceiverPanel.tsx"],"names":["useState","useMemo"],"mappings":";;;AAQA,IAAM,mBAAA,GAAoC,EAAE,IAAA,EAAM,8BAAA,EAA+B;AAkCjF,SAAS,aAAa,OAAA,EAA2D;AAC/E,EAAA,IAAI;AACF,IAAA,IAAI,OAAO,OAAA,KAAY,QAAA,EAAU,OAAO,IAAA,CAAK,MAAM,OAAO,CAAA;AAC1D,IAAA,IAAI,OAAA,YAAmB,WAAA,EAAa,OAAO,IAAA,CAAK,KAAA,CAAM,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO,OAAO,CAAC,CAAA;AACvF,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,OAAO,CAAC,CAAA;AAAA,EACnC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEO,SAAS,kBAAkB,OAAA,EAA4D;AAC5F,EAAA,MAAM,EAAE,OAAO,MAAA,EAAQ,UAAA,GAAa,CAAC,mBAAmB,CAAA,EAAG,OAAA,GAAU,EAAA,EAAG,GAAI,OAAA;AAC5E,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,QAAA,CAAmC,EAAE,CAAA;AAC7D,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAAS,KAAK,CAAA;AACpD,EAAA,MAAM,CAAC,eAAA,EAAiB,kBAAkB,CAAA,GAAI,SAA0C,MAAM,CAAA;AAC9F,EAAA,MAAM,CAAC,kBAAA,EAAoB,qBAAqB,CAAA,GAAI,SAAyC,MAAM,CAAA;AACnG,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAA6B,IAAI,CAAA;AAC7D,EAAA,MAAM,QAAA,GAAW,OAAO,CAAC,CAAA;AACzB,EAAA,MAAM,UAAU,MAAA,CAAoB,EAAE,iBAAA,EAAmB,IAAI,CAAA;AAC7D,EAAA,MAAM,QAAA,GAAW,OAAyB,IAAI,CAAA;AAE9C,EAAA,MAAM,SAAA,GAAY,WAAA;AAAA,IAChB,CAAC,IAAA,KAAiB;AAChB,MAAA,QAAA,CAAS,OAAA,IAAW,CAAA;AACpB,MAAA,OAAA,CAAQ,CAAC,IAAA,KAAS,CAAC,GAAG,MAAM,EAAE,EAAA,EAAI,QAAA,CAAS,OAAA,EAAS,MAAM,CAAA,CAAE,KAAA,CAAM,CAAC,OAAO,CAAC,CAAA;AAAA,IAC7E,CAAA;AAAA,IACA,CAAC,OAAO;AAAA,GACV;AAEA,EAAA,MAAM,UAAA,GAAa,YAAY,MAAM;AACnC,IAAA,OAAA,CAAQ,OAAA,CAAQ,IAAI,KAAA,EAAM;AAC1B,IAAA,OAAA,CAAQ,OAAA,CAAQ,IAAI,KAAA,EAAM;AAC1B,IAAA,OAAA,CAAQ,OAAA,GAAU,EAAE,iBAAA,EAAmB,EAAC,EAAE;AAC1C,IAAA,cAAA,CAAe,KAAK,CAAA;AACpB,IAAA,kBAAA,CAAmB,MAAM,CAAA;AACzB,IAAA,qBAAA,CAAsB,MAAM,CAAA;AAC5B,IAAA,SAAA,CAAU,IAAI,CAAA;AAAA,EAChB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,OAAA,GAAU,YAAY,YAAY;AACtC,IAAA,UAAA,EAAW;AAEX,IAAA,MAAM,eAAA,GAAkB,MAAM,IAAA,EAAK;AACnC,IAAA,MAAM,gBAAA,GAAmB,OAAO,IAAA,EAAK;AACrC,IAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,MAAA,SAAA,CAAU,iBAAiB,CAAA;AAC3B,MAAA;AAAA,IACF;AACA,IAAA,IAAI,CAAC,gBAAA,EAAkB;AACrB,MAAA,SAAA,CAAU,kBAAkB,CAAA;AAC5B,MAAA;AAAA,IACF;AAEA,IAAA,SAAA,CAAU,CAAA,YAAA,EAAe,eAAe,CAAA,CAAE,CAAA;AAE1C,IAAA,IAAI,EAAA;AACJ,IAAA,IAAI;AACF,MAAA,EAAA,GAAK,IAAI,UAAU,eAAe,CAAA;AAAA,IACpC,SAAS,KAAA,EAAO;AACd,MAAA,SAAA,CAAU,CAAA,iBAAA,EAAoB,MAAA,CAAO,KAAK,CAAC,CAAA,CAAE,CAAA;AAC7C,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,EAAA,GAAK,IAAI,iBAAA,CAAkB,EAAE,YAAY,CAAA;AAC/C,IAAA,EAAA,CAAG,cAAA,CAAe,OAAA,EAAS,EAAE,SAAA,EAAW,YAAY,CAAA;AAEpD,IAAA,OAAA,CAAQ,QAAQ,EAAA,GAAK,EAAA;AACrB,IAAA,OAAA,CAAQ,QAAQ,EAAA,GAAK,EAAA;AACrB,IAAA,OAAA,CAAQ,OAAA,CAAQ,oBAAoB,EAAC;AAErC,IAAA,EAAA,CAAG,SAAS,MAAM;AAChB,MAAA,SAAA,CAAU,cAAc,CAAA;AACxB,MAAA,cAAA,CAAe,IAAI,CAAA;AACnB,MAAA,EAAA,CAAG,IAAA,CAAK,IAAA,CAAK,SAAA,CAAU,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,gBAAA,EAAkB,IAAA,EAAM,QAAA,EAAU,CAAC,CAAA;AAAA,IACpF,CAAA;AAEA,IAAA,EAAA,CAAG,UAAU,MAAM;AACjB,MAAA,SAAA,CAAU,WAAW,CAAA;AACrB,MAAA,cAAA,CAAe,KAAK,CAAA;AAAA,IACtB,CAAA;AAEA,IAAA,EAAA,CAAG,OAAA,GAAU,CAAC,KAAA,KAAU;AACtB,MAAA,SAAA,CAAU,CAAA,UAAA,EAAa,KAAA,CAAM,IAAI,CAAA,CAAE,CAAA;AAAA,IACrC,CAAA;AAEA,IAAA,EAAA,CAAG,SAAA,GAAY,OAAO,KAAA,KAAU;AAC9B,MAAA,MAAM,OAAA,GAAU,YAAA,CAAa,KAAA,CAAM,IAAI,CAAA;AACvC,MAAA,IAAI,CAAC,OAAA,EAAS;AACZ,QAAA,SAAA,CAAU,wBAAwB,CAAA;AAClC,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,OAAA,CAAQ,SAAS,QAAA,EAAU;AAC7B,QAAA,MAAM,MAAA,GAAS,OAAA;AACf,QAAA,OAAA,CAAQ,OAAA,CAAQ,aAAa,MAAA,CAAO,MAAA;AACpC,QAAA,SAAA,CAAU,eAAe,MAAA,CAAO,MAAM,CAAA,IAAA,EAAO,MAAA,CAAO,MAAM,CAAA,CAAE,CAAA;AAC5D,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,OAAA,CAAQ,SAAS,YAAA,EAAc;AACjC,QAAA,MAAM,SAAA,GAAY,OAAA;AAClB,QAAA,MAAM,WAAA,GAAc,UAAU,KAAA,CAAM,IAAA,CAAK,CAAC,IAAA,KAAS,IAAA,CAAK,SAAS,aAAa,CAAA;AAC9E,QAAA,IAAI,WAAA,EAAa;AACf,UAAA,OAAA,CAAQ,OAAA,CAAQ,kBAAkB,WAAA,CAAY,MAAA;AAC9C,UAAA,SAAA,CAAU,CAAA,oBAAA,EAAuB,WAAA,CAAY,MAAM,CAAA,CAAE,CAAA;AAAA,QACvD;AACA,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,QAAQ,IAAA,KAAS,OAAA,IAAW,OAAO,OAAA,CAAQ,QAAQ,QAAA,EAAU;AAC/D,QAAA,SAAA,CAAU,gBAAgB,CAAA;AAC1B,QAAA,OAAA,CAAQ,QAAQ,eAAA,GAAkB,OAAO,QAAQ,UAAA,KAAe,QAAA,GAAW,QAAQ,UAAA,GAAa,MAAA;AAChG,QAAA,MAAM,EAAA,CAAG,qBAAqB,EAAE,IAAA,EAAM,SAAS,GAAA,EAAK,OAAA,CAAQ,KAAK,CAAA;AACjE,QAAA,KAAA,MAAW,SAAA,IAAa,OAAA,CAAQ,OAAA,CAAQ,iBAAA,EAAmB;AACzD,UAAA,IAAI;AACF,YAAA,MAAM,EAAA,CAAG,gBAAgB,SAAS,CAAA;AAAA,UACpC,SAAS,KAAA,EAAO;AACd,YAAA,SAAA,CAAU,CAAA,SAAA,EAAY,MAAA,CAAO,KAAK,CAAC,CAAA,CAAE,CAAA;AAAA,UACvC;AAAA,QACF;AACA,QAAA,OAAA,CAAQ,OAAA,CAAQ,oBAAoB,EAAC;AAErC,QAAA,MAAM,MAAA,GAAS,MAAM,EAAA,CAAG,YAAA,EAAa;AACrC,QAAA,MAAM,EAAA,CAAG,oBAAoB,MAAM,CAAA;AACnC,QAAA,EAAA,CAAG,IAAA;AAAA,UACD,KAAK,SAAA,CAAU;AAAA,YACb,IAAA,EAAM,QAAA;AAAA,YACN,KAAK,MAAA,CAAO,GAAA;AAAA,YACZ,YAAA,EAAc,QAAQ,OAAA,CAAQ;AAAA,WAC/B;AAAA,SACH;AACA,QAAA,SAAA,CAAU,aAAa,CAAA;AACvB,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,OAAA,CAAQ,IAAA,KAAS,KAAA,IAAS,OAAA,CAAQ,SAAA,EAAW;AAC/C,QAAA,IAAI,CAAC,GAAG,iBAAA,EAAmB;AACzB,UAAA,OAAA,CAAQ,OAAA,CAAQ,iBAAA,CAAkB,IAAA,CAAK,OAAA,CAAQ,SAAgC,CAAA;AAC/E,UAAA;AAAA,QACF;AACA,QAAA,IAAI;AACF,UAAA,MAAM,EAAA,CAAG,eAAA,CAAgB,OAAA,CAAQ,SAAgC,CAAA;AAAA,QACnE,SAAS,KAAA,EAAO;AACd,UAAA,SAAA,CAAU,CAAA,SAAA,EAAY,MAAA,CAAO,KAAK,CAAC,CAAA,CAAE,CAAA;AAAA,QACvC;AACA,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,OAAA,CAAQ,SAAS,WAAA,EAAa;AAChC,QAAA,MAAM,QAAA,GAAW,OAAA;AACjB,QAAA,IAAI,QAAA,CAAS,MAAA,KAAW,OAAA,CAAQ,OAAA,CAAQ,eAAA,EAAiB;AACvD,UAAA,OAAA,CAAQ,QAAQ,eAAA,GAAkB,MAAA;AAClC,UAAA,SAAA,CAAU,CAAA,gBAAA,EAAmB,QAAA,CAAS,MAAM,CAAA,CAAE,CAAA;AAAA,QAChD;AACA,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,OAAA,CAAQ,SAAS,OAAA,EAAS;AAC5B,QAAA,SAAA,CAAU,iBAAiB,MAAA,CAAO,OAAA,CAAQ,MAAA,IAAU,SAAS,CAAC,CAAA,CAAE,CAAA;AAAA,MAClE;AAAA,IACF,CAAA;AAEA,IAAA,EAAA,CAAG,OAAA,GAAU,CAAC,KAAA,KAAU;AACtB,MAAA,MAAM,cAAA,GAAiB,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA;AACtC,MAAA,IAAI,cAAA,EAAgB;AAClB,QAAA,SAAA,CAAU,cAAc,CAAA;AACxB,QAAA,SAAA,CAAU,gBAAgB,CAAA;AAAA,MAC5B;AAAA,IACF,CAAA;AAEA,IAAA,EAAA,CAAG,cAAA,GAAiB,CAAC,KAAA,KAAU;AAC7B,MAAA,IAAI,CAAC,MAAM,SAAA,EAAW;AACtB,MAAA,EAAA,CAAG,IAAA;AAAA,QACD,KAAK,SAAA,CAAU;AAAA,UACb,IAAA,EAAM,KAAA;AAAA,UACN,WAAW,KAAA,CAAM,SAAA;AAAA,UACjB,YAAA,EAAc,QAAQ,OAAA,CAAQ;AAAA,SAC/B;AAAA,OACH;AAAA,IACF,CAAA;AAEA,IAAA,EAAA,CAAG,0BAA0B,MAAM;AACjC,MAAA,MAAM,KAAA,GAAQ,GAAG,eAAA,IAAmB,KAAA;AACpC,MAAA,kBAAA,CAAmB,KAAK,CAAA;AACxB,MAAA,SAAA,CAAU,CAAA,UAAA,EAAa,KAAK,CAAA,CAAE,CAAA;AAAA,IAChC,CAAA;AAEA,IAAA,EAAA,CAAG,6BAA6B,MAAM;AACpC,MAAA,MAAM,KAAA,GAAQ,GAAG,kBAAA,IAAsB,KAAA;AACvC,MAAA,qBAAA,CAAsB,KAAK,CAAA;AAC3B,MAAA,SAAA,CAAU,CAAA,WAAA,EAAc,KAAK,CAAA,CAAE,CAAA;AAAA,IACjC,CAAA;AAAA,EACF,GAAG,CAAC,SAAA,EAAW,YAAY,UAAA,EAAY,MAAA,EAAQ,KAAK,CAAC,CAAA;AAErD,EAAA,SAAA,CAAU,MAAM,MAAM,UAAA,EAAW,EAAG,CAAC,UAAU,CAAC,CAAA;AAEhD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,SAAS,OAAA,EAAS;AACvB,IAAA,QAAA,CAAS,QAAQ,SAAA,GAAY,MAAA;AAAA,EAC/B,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAEX,EAAA,MAAM,SAAA,GAAY,YAAY,MAAM,OAAA,CAAQ,EAAE,CAAA,EAAG,EAAE,CAAA;AAEnD,EAAA,OAAO,OAAA;AAAA,IACL,OAAO;AAAA,MACL,OAAA;AAAA,MACA,UAAA;AAAA,MACA,SAAA;AAAA,MACA,IAAA;AAAA,MACA,WAAA;AAAA,MACA,eAAA;AAAA,MACA,kBAAA;AAAA,MACA,QAAA;AAAA,MACA;AAAA,KACF,CAAA;AAAA,IACA,CAAC,WAAW,OAAA,EAAS,eAAA,EAAiB,YAAY,kBAAA,EAAoB,WAAA,EAAa,MAAM,MAAM;AAAA,GACjG;AACF;AC1PA,IAAM,kBAAA,GAAqB,wBAAA;AAC3B,IAAM,eAAA,GAAkB,eAAA;AAEjB,SAAS,oBAAoB,KAAA,EAAiC;AACnE,EAAA,MAAM,EAAE,gBAAA,GAAmB,kBAAA,EAAoB,aAAA,GAAgB,eAAA,EAAiB,WAAU,GAAI,KAAA;AAC9F,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,SAAS,gBAAgB,CAAA;AACnD,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIA,SAAS,aAAa,CAAA;AAClD,EAAA,MAAM,QAAA,GAAW,iBAAA,CAAkB,EAAE,KAAA,EAAO,QAAQ,CAAA;AACpD,EAAA,MAAM,OAAOC,OAAAA,CAAQ,MAAM,QAAA,CAAS,IAAA,CAAK,IAAI,CAAC,KAAA,KAAU,KAAA,CAAM,IAAI,EAAE,IAAA,CAAK,IAAI,GAAG,CAAC,QAAA,CAAS,IAAI,CAAC,CAAA;AAE/F,EAAA,2CACG,KAAA,EAAA,EAAI,SAAA,EAAA,sCACF,KAAA,EAAA,EAAI,SAAA,EAAU,yCACb,KAAA,CAAA,aAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,wCAAA,EAAA,sCACZ,OAAA,EAAA,EAAM,SAAA,EAAU,iDACf,KAAA,CAAA,aAAA,CAAC,MAAA,EAAA,IAAA,EAAK,cAAY,CAAA,kBAClB,KAAA,CAAA,aAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAU,6BAAA;AAAA,MACV,KAAA,EAAO,KAAA;AAAA,MACP,UAAU,CAAC,KAAA,KAAU,QAAA,CAAS,KAAA,CAAM,OAAO,KAAK;AAAA;AAAA,GAEpD,mBACA,KAAA,CAAA,aAAA,CAAC,OAAA,EAAA,EAAM,WAAU,6BAAA,EAAA,kBACf,KAAA,CAAA,aAAA,CAAC,MAAA,EAAA,IAAA,EAAK,MAAI,CAAA,kBACV,KAAA,CAAA,aAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAU,6BAAA;AAAA,MACV,KAAA,EAAO,MAAA;AAAA,MACP,UAAU,CAAC,KAAA,KAAU,SAAA,CAAU,KAAA,CAAM,OAAO,KAAK;AAAA;AAAA,GAErD,CAAA,kBACA,KAAA,CAAA,aAAA,CAAC,KAAA,EAAA,EAAI,WAAU,sBAAA,EAAA,kBACb,KAAA,CAAA,aAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,OAAA,EAAS,MAAM,KAAK,QAAA,CAAS,OAAA,EAAQ;AAAA,MACrC,SAAA,EAAU;AAAA,KAAA;AAAA,IAET,QAAA,CAAS,cAAc,WAAA,GAAc;AAAA,GACxC,kBACA,KAAA,CAAA,aAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,SAAS,QAAA,CAAS,UAAA;AAAA,MAClB,SAAA,EAAU;AAAA,KAAA;AAAA,IACX;AAAA,GAGH,CACF,CAAA,sCAEC,KAAA,EAAA,EAAI,SAAA,EAAU,+CACb,KAAA,CAAA,aAAA,CAAC,UAAA,EAAA,EAAW,KAAA,EAAM,WAAA,EAAY,OAAO,QAAA,CAAS,WAAA,GAAc,cAAc,MAAA,EAAQ,CAAA,sCACjF,UAAA,EAAA,EAAW,KAAA,EAAM,gBAAA,EAAiB,KAAA,EAAO,SAAS,eAAA,EAAiB,CAAA,sCACnE,UAAA,EAAA,EAAW,KAAA,EAAM,aAAY,KAAA,EAAO,QAAA,CAAS,oBAAoB,CACpE,CAAA,sCAEC,KAAA,EAAA,EAAI,SAAA,EAAU,uDACb,KAAA,CAAA,aAAA,CAAC,KAAA,EAAA,EAAI,WAAU,gCAAA,EAAA,kBACb,KAAA,CAAA,aAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,KAAK,QAAA,CAAS,QAAA;AAAA,MACd,QAAA,EAAQ,IAAA;AAAA,MACR,WAAA,EAAW,IAAA;AAAA,MACX,QAAA,EAAQ,IAAA;AAAA,MACR,KAAA,EAAK,IAAA;AAAA,MACL,SAAA,EAAU;AAAA;AAAA,GAEd,CAAA,kBACA,KAAA,CAAA,aAAA,CAAC,KAAA,EAAA,EAAI,WAAU,uBAAA,EAAA,kBACb,KAAA,CAAA,aAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,uDACb,KAAA,CAAA,aAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,uBAAA,EAAA,EAAwB,aAAW,CAAA,kBAChD,KAAA,CAAA,aAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,SAAS,QAAA,CAAS,SAAA;AAAA,MAClB,SAAA,EAAU;AAAA,KAAA;AAAA,IACX;AAAA,GAGH,CAAA,kBACA,KAAA,CAAA,aAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,wEAAA,EAAA,EACZ,IAAA,IAAQ,cACX,CACF,CACF,CACF,CACF,CAAA;AAEJ;AAEA,SAAS,UAAA,CAAW,EAAE,KAAA,EAAO,KAAA,EAAM,EAAqC;AACtE,EAAA,uBACE,KAAA,CAAA,aAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,6BAAA,EAAA,sCACZ,GAAA,EAAA,EAAE,SAAA,EAAU,wBAAA,EAAA,EAA0B,KAAM,mBAC7C,KAAA,CAAA,aAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,qBAAA,EAAA,EAAuB,KAAM,CAC5C,CAAA;AAEJ","file":"index.mjs","sourcesContent":["import type { RefObject } from 'react';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type {\n ScreenReceiverJoinedMessage,\n ScreenReceiverPeerLeftMessage,\n ScreenReceiverRoomStateMessage,\n} from './types';\n\nconst DEFAULT_STUN_SERVER: RTCIceServer = { urls: 'stun:stun.l.google.com:19302' };\n\nexport interface ScreenReceiverLogEntry {\n id: number;\n text: string;\n}\n\nexport interface UseScreenReceiverOptions {\n wsUrl: string;\n roomId: string;\n iceServers?: RTCIceServer[];\n maxLogs?: number;\n}\n\nexport interface UseScreenReceiverReturn {\n connect: () => Promise<void>;\n disconnect: () => void;\n clearLogs: () => void;\n logs: ScreenReceiverLogEntry[];\n isConnected: boolean;\n connectionState: RTCPeerConnectionState | 'idle';\n iceConnectionState: RTCIceConnectionState | 'idle';\n videoRef: RefObject<HTMLVideoElement>;\n stream: MediaStream | null;\n}\n\ntype PeerContext = {\n ws?: WebSocket;\n pc?: RTCPeerConnection;\n pendingCandidates: RTCIceCandidateInit[];\n selfPeerId?: string;\n publisherPeerId?: string;\n};\n\nfunction parseMessage(payload: MessageEvent['data']): Record<string, any> | null {\n try {\n if (typeof payload === 'string') return JSON.parse(payload);\n if (payload instanceof ArrayBuffer) return JSON.parse(new TextDecoder().decode(payload));\n return JSON.parse(String(payload));\n } catch {\n return null;\n }\n}\n\nexport function useScreenReceiver(options: UseScreenReceiverOptions): UseScreenReceiverReturn {\n const { wsUrl, roomId, iceServers = [DEFAULT_STUN_SERVER], maxLogs = 80 } = options;\n const [logs, setLogs] = useState<ScreenReceiverLogEntry[]>([]);\n const [isConnected, setIsConnected] = useState(false);\n const [connectionState, setConnectionState] = useState<RTCPeerConnectionState | 'idle'>('idle');\n const [iceConnectionState, setIceConnectionState] = useState<RTCIceConnectionState | 'idle'>('idle');\n const [stream, setStream] = useState<MediaStream | null>(null);\n const logIdRef = useRef(0);\n const peerRef = useRef<PeerContext>({ pendingCandidates: [] });\n const videoRef = useRef<HTMLVideoElement>(null);\n\n const appendLog = useCallback(\n (text: string) => {\n logIdRef.current += 1;\n setLogs((prev) => [...prev, { id: logIdRef.current, text }].slice(-maxLogs));\n },\n [maxLogs],\n );\n\n const disconnect = useCallback(() => {\n peerRef.current.ws?.close();\n peerRef.current.pc?.close();\n peerRef.current = { pendingCandidates: [] };\n setIsConnected(false);\n setConnectionState('idle');\n setIceConnectionState('idle');\n setStream(null);\n }, []);\n\n const connect = useCallback(async () => {\n disconnect();\n\n const normalizedWsUrl = wsUrl.trim();\n const normalizedRoomId = roomId.trim();\n if (!normalizedWsUrl) {\n appendLog('ws url is empty');\n return;\n }\n if (!normalizedRoomId) {\n appendLog('room id is empty');\n return;\n }\n\n appendLog(`connecting: ${normalizedWsUrl}`);\n\n let ws: WebSocket;\n try {\n ws = new WebSocket(normalizedWsUrl);\n } catch (error) {\n appendLog(`ws create error: ${String(error)}`);\n return;\n }\n\n const pc = new RTCPeerConnection({ iceServers });\n pc.addTransceiver('video', { direction: 'recvonly' });\n\n peerRef.current.ws = ws;\n peerRef.current.pc = pc;\n peerRef.current.pendingCandidates = [];\n\n ws.onopen = () => {\n appendLog('ws connected');\n setIsConnected(true);\n ws.send(JSON.stringify({ type: 'join', roomId: normalizedRoomId, role: 'viewer' }));\n };\n\n ws.onclose = () => {\n appendLog('ws closed');\n setIsConnected(false);\n };\n\n ws.onerror = (event) => {\n appendLog(`ws error: ${event.type}`);\n };\n\n ws.onmessage = async (event) => {\n const message = parseMessage(event.data);\n if (!message) {\n appendLog('ws message parse error');\n return;\n }\n\n if (message.type === 'joined') {\n const joined = message as ScreenReceiverJoinedMessage;\n peerRef.current.selfPeerId = joined.peerId;\n appendLog(`joined room ${joined.roomId} as ${joined.peerId}`);\n return;\n }\n\n if (message.type === 'room_state') {\n const roomState = message as ScreenReceiverRoomStateMessage;\n const broadcaster = roomState.peers.find((peer) => peer.role === 'broadcaster');\n if (broadcaster) {\n peerRef.current.publisherPeerId = broadcaster.peerId;\n appendLog(`broadcaster online: ${broadcaster.peerId}`);\n }\n return;\n }\n\n if (message.type === 'offer' && typeof message.sdp === 'string') {\n appendLog('offer received');\n peerRef.current.publisherPeerId = typeof message.fromPeerId === 'string' ? message.fromPeerId : undefined;\n await pc.setRemoteDescription({ type: 'offer', sdp: message.sdp });\n for (const candidate of peerRef.current.pendingCandidates) {\n try {\n await pc.addIceCandidate(candidate);\n } catch (error) {\n appendLog(`ice err: ${String(error)}`);\n }\n }\n peerRef.current.pendingCandidates = [];\n\n const answer = await pc.createAnswer();\n await pc.setLocalDescription(answer);\n ws.send(\n JSON.stringify({\n type: 'answer',\n sdp: answer.sdp,\n targetPeerId: peerRef.current.publisherPeerId,\n }),\n );\n appendLog('answer sent');\n return;\n }\n\n if (message.type === 'ice' && message.candidate) {\n if (!pc.remoteDescription) {\n peerRef.current.pendingCandidates.push(message.candidate as RTCIceCandidateInit);\n return;\n }\n try {\n await pc.addIceCandidate(message.candidate as RTCIceCandidateInit);\n } catch (error) {\n appendLog(`ice err: ${String(error)}`);\n }\n return;\n }\n\n if (message.type === 'peer_left') {\n const peerLeft = message as ScreenReceiverPeerLeftMessage;\n if (peerLeft.peerId === peerRef.current.publisherPeerId) {\n peerRef.current.publisherPeerId = undefined;\n appendLog(`publisher left: ${peerLeft.peerId}`);\n }\n return;\n }\n\n if (message.type === 'error') {\n appendLog(`server error: ${String(message.reason ?? 'unknown')}`);\n }\n };\n\n pc.ontrack = (event) => {\n const receivedStream = event.streams[0];\n if (receivedStream) {\n setStream(receivedStream);\n appendLog('track received');\n }\n };\n\n pc.onicecandidate = (event) => {\n if (!event.candidate) return;\n ws.send(\n JSON.stringify({\n type: 'ice',\n candidate: event.candidate,\n targetPeerId: peerRef.current.publisherPeerId,\n }),\n );\n };\n\n pc.onconnectionstatechange = () => {\n const state = pc.connectionState || 'new';\n setConnectionState(state);\n appendLog(`pc state: ${state}`);\n };\n\n pc.oniceconnectionstatechange = () => {\n const state = pc.iceConnectionState || 'new';\n setIceConnectionState(state);\n appendLog(`ice state: ${state}`);\n };\n }, [appendLog, disconnect, iceServers, roomId, wsUrl]);\n\n useEffect(() => () => disconnect(), [disconnect]);\n\n useEffect(() => {\n if (!videoRef.current) return;\n videoRef.current.srcObject = stream;\n }, [stream]);\n\n const clearLogs = useCallback(() => setLogs([]), []);\n\n return useMemo(\n () => ({\n connect,\n disconnect,\n clearLogs,\n logs,\n isConnected,\n connectionState,\n iceConnectionState,\n videoRef,\n stream,\n }),\n [clearLogs, connect, connectionState, disconnect, iceConnectionState, isConnected, logs, stream],\n );\n}\n","import React, { useMemo, useState } from 'react';\nimport { useScreenReceiver } from './useScreenReceiver';\n\nexport interface ScreenReceiverPanelProps {\n defaultSignalUrl?: string;\n defaultRoomId?: string;\n className?: string;\n}\n\nconst DEFAULT_SIGNAL_URL = 'ws://127.0.0.1:8787/ws';\nconst DEFAULT_ROOM_ID = 'screen-room-1';\n\nexport function ScreenReceiverPanel(props: ScreenReceiverPanelProps) {\n const { defaultSignalUrl = DEFAULT_SIGNAL_URL, defaultRoomId = DEFAULT_ROOM_ID, className } = props;\n const [wsUrl, setWsUrl] = useState(defaultSignalUrl);\n const [roomId, setRoomId] = useState(defaultRoomId);\n const receiver = useScreenReceiver({ wsUrl, roomId });\n const logs = useMemo(() => receiver.logs.map((entry) => entry.text).join('\\n'), [receiver.logs]);\n\n return (\n <div className={className}>\n <div className=\"flex flex-col gap-4\">\n <div className=\"grid gap-3 md:grid-cols-[2fr,1fr,auto]\">\n <label className=\"flex flex-col gap-1 text-sm\">\n <span>Signaling WS</span>\n <input\n className=\"rounded-md border px-3 py-2\"\n value={wsUrl}\n onChange={(event) => setWsUrl(event.target.value)}\n />\n </label>\n <label className=\"flex flex-col gap-1 text-sm\">\n <span>Room</span>\n <input\n className=\"rounded-md border px-3 py-2\"\n value={roomId}\n onChange={(event) => setRoomId(event.target.value)}\n />\n </label>\n <div className=\"flex items-end gap-2\">\n <button\n onClick={() => void receiver.connect()}\n className=\"rounded-md border bg-black px-4 py-2 text-sm text-white\"\n >\n {receiver.isConnected ? 'Reconnect' : 'Connect'}\n </button>\n <button\n onClick={receiver.disconnect}\n className=\"rounded-md border px-4 py-2 text-sm\"\n >\n Disconnect\n </button>\n </div>\n </div>\n\n <div className=\"grid gap-3 md:grid-cols-3\">\n <StatusItem label=\"WebSocket\" value={receiver.isConnected ? 'connected' : 'idle'} />\n <StatusItem label=\"PeerConnection\" value={receiver.connectionState} />\n <StatusItem label=\"ICE State\" value={receiver.iceConnectionState} />\n </div>\n\n <div className=\"grid gap-4 lg:grid-cols-[3fr,2fr]\">\n <div className=\"rounded-xl border bg-black p-3\">\n <video\n ref={receiver.videoRef}\n autoPlay\n playsInline\n controls\n muted\n className=\"h-[360px] w-full rounded-lg bg-black\"\n />\n </div>\n <div className=\"rounded-xl border p-3\">\n <div className=\"flex items-center justify-between\">\n <p className=\"text-sm font-semibold\">Session Log</p>\n <button\n onClick={receiver.clearLogs}\n className=\"text-xs underline-offset-2 hover:underline\"\n >\n Clear\n </button>\n </div>\n <pre className=\"mt-3 h-[320px] overflow-auto rounded-lg border bg-slate-50 p-3 text-xs\">\n {logs || 'No logs yet.'}\n </pre>\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nfunction StatusItem({ label, value }: { label: string; value: string }) {\n return (\n <div className=\"rounded-md border px-3 py-2\">\n <p className=\"text-xs text-slate-500\">{label}</p>\n <p className=\"text-sm font-medium\">{value}</p>\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/screenReceiver/useScreenReceiver.ts","../../../src/screenReceiver/signalUrl.ts","../../../src/screenReceiver/ScreenReceiverPanel.tsx"],"names":["useMemo","useState"],"mappings":"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","file":"index.mjs","sourcesContent":["import type { RefObject } from 'react';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type {\n ScreenReceiverJoinedMessage,\n ScreenReceiverPeerLeftMessage,\n ScreenReceiverRoomStateMessage,\n} from './types';\n\nconst DEFAULT_STUN_SERVER: RTCIceServer = { urls: 'stun:stun.l.google.com:19302' };\n\nexport interface ScreenReceiverLogEntry {\n id: number;\n text: string;\n}\n\nexport interface UseScreenReceiverOptions {\n wsUrl: string;\n roomId: string;\n iceServers?: RTCIceServer[];\n maxLogs?: number;\n}\n\nexport interface UseScreenReceiverReturn {\n connect: () => Promise<void>;\n disconnect: () => void;\n clearLogs: () => void;\n logs: ScreenReceiverLogEntry[];\n isConnected: boolean;\n connectionState: RTCPeerConnectionState | 'idle';\n iceConnectionState: RTCIceConnectionState | 'idle';\n videoRef: RefObject<HTMLVideoElement>;\n stream: MediaStream | null;\n}\n\ntype PeerContext = {\n ws?: WebSocket;\n pc?: RTCPeerConnection;\n pendingCandidates: RTCIceCandidateInit[];\n selfPeerId?: string;\n publisherPeerId?: string;\n};\n\nfunction parseMessage(payload: MessageEvent['data']): Record<string, any> | null {\n try {\n if (typeof payload === 'string') return JSON.parse(payload);\n if (payload instanceof ArrayBuffer) return JSON.parse(new TextDecoder().decode(payload));\n return JSON.parse(String(payload));\n } catch {\n return null;\n }\n}\n\nexport function useScreenReceiver(options: UseScreenReceiverOptions): UseScreenReceiverReturn {\n const { wsUrl, roomId, iceServers = [DEFAULT_STUN_SERVER], maxLogs = 80 } = options;\n const [logs, setLogs] = useState<ScreenReceiverLogEntry[]>([]);\n const [isConnected, setIsConnected] = useState(false);\n const [connectionState, setConnectionState] = useState<RTCPeerConnectionState | 'idle'>('idle');\n const [iceConnectionState, setIceConnectionState] = useState<RTCIceConnectionState | 'idle'>('idle');\n const [stream, setStream] = useState<MediaStream | null>(null);\n const logIdRef = useRef(0);\n const peerRef = useRef<PeerContext>({ pendingCandidates: [] });\n const videoRef = useRef<HTMLVideoElement>(null);\n\n const appendLog = useCallback(\n (text: string) => {\n logIdRef.current += 1;\n setLogs((prev) => [...prev, { id: logIdRef.current, text }].slice(-maxLogs));\n },\n [maxLogs],\n );\n\n const disconnect = useCallback(() => {\n peerRef.current.ws?.close();\n peerRef.current.pc?.close();\n peerRef.current = { pendingCandidates: [] };\n setIsConnected(false);\n setConnectionState('idle');\n setIceConnectionState('idle');\n setStream(null);\n }, []);\n\n const connect = useCallback(async () => {\n disconnect();\n\n const normalizedWsUrl = wsUrl.trim();\n const normalizedRoomId = roomId.trim();\n if (!normalizedWsUrl) {\n appendLog('ws url is empty');\n return;\n }\n if (!normalizedRoomId) {\n appendLog('room id is empty');\n return;\n }\n\n appendLog(`connecting: ${normalizedWsUrl}`);\n\n let ws: WebSocket;\n try {\n ws = new WebSocket(normalizedWsUrl);\n } catch (error) {\n appendLog(`ws create error: ${String(error)}`);\n return;\n }\n\n const pc = new RTCPeerConnection({ iceServers });\n pc.addTransceiver('video', { direction: 'recvonly' });\n\n peerRef.current.ws = ws;\n peerRef.current.pc = pc;\n peerRef.current.pendingCandidates = [];\n\n ws.onopen = () => {\n appendLog('ws connected');\n setIsConnected(true);\n ws.send(JSON.stringify({ type: 'join', roomId: normalizedRoomId, role: 'viewer' }));\n };\n\n ws.onclose = () => {\n appendLog('ws closed');\n setIsConnected(false);\n };\n\n ws.onerror = (event) => {\n appendLog(`ws error: ${event.type}`);\n };\n\n ws.onmessage = async (event) => {\n const message = parseMessage(event.data);\n if (!message) {\n appendLog('ws message parse error');\n return;\n }\n\n if (message.type === 'joined') {\n const joined = message as ScreenReceiverJoinedMessage;\n peerRef.current.selfPeerId = joined.peerId;\n appendLog(`joined room ${joined.roomId} as ${joined.peerId}`);\n return;\n }\n\n if (message.type === 'room_state') {\n const roomState = message as ScreenReceiverRoomStateMessage;\n const broadcaster = roomState.peers.find((peer) => peer.role === 'broadcaster');\n if (broadcaster) {\n peerRef.current.publisherPeerId = broadcaster.peerId;\n appendLog(`broadcaster online: ${broadcaster.peerId}`);\n }\n return;\n }\n\n if (message.type === 'offer' && typeof message.sdp === 'string') {\n appendLog('offer received');\n peerRef.current.publisherPeerId = typeof message.fromPeerId === 'string' ? message.fromPeerId : undefined;\n await pc.setRemoteDescription({ type: 'offer', sdp: message.sdp });\n for (const candidate of peerRef.current.pendingCandidates) {\n try {\n await pc.addIceCandidate(candidate);\n } catch (error) {\n appendLog(`ice err: ${String(error)}`);\n }\n }\n peerRef.current.pendingCandidates = [];\n\n const answer = await pc.createAnswer();\n await pc.setLocalDescription(answer);\n ws.send(\n JSON.stringify({\n type: 'answer',\n sdp: answer.sdp,\n targetPeerId: peerRef.current.publisherPeerId,\n }),\n );\n appendLog('answer sent');\n return;\n }\n\n if (message.type === 'ice' && message.candidate) {\n if (!pc.remoteDescription) {\n peerRef.current.pendingCandidates.push(message.candidate as RTCIceCandidateInit);\n return;\n }\n try {\n await pc.addIceCandidate(message.candidate as RTCIceCandidateInit);\n } catch (error) {\n appendLog(`ice err: ${String(error)}`);\n }\n return;\n }\n\n if (message.type === 'peer_left') {\n const peerLeft = message as ScreenReceiverPeerLeftMessage;\n if (peerLeft.peerId === peerRef.current.publisherPeerId) {\n peerRef.current.publisherPeerId = undefined;\n appendLog(`publisher left: ${peerLeft.peerId}`);\n }\n return;\n }\n\n if (message.type === 'error') {\n appendLog(`server error: ${String(message.reason ?? 'unknown')}`);\n }\n };\n\n pc.ontrack = (event) => {\n const receivedStream = event.streams[0];\n if (receivedStream) {\n setStream(receivedStream);\n appendLog('track received');\n }\n };\n\n pc.onicecandidate = (event) => {\n if (!event.candidate) return;\n ws.send(\n JSON.stringify({\n type: 'ice',\n candidate: event.candidate,\n targetPeerId: peerRef.current.publisherPeerId,\n }),\n );\n };\n\n pc.onconnectionstatechange = () => {\n const state = pc.connectionState || 'new';\n setConnectionState(state);\n appendLog(`pc state: ${state}`);\n };\n\n pc.oniceconnectionstatechange = () => {\n const state = pc.iceConnectionState || 'new';\n setIceConnectionState(state);\n appendLog(`ice state: ${state}`);\n };\n }, [appendLog, disconnect, iceServers, roomId, wsUrl]);\n\n useEffect(() => () => disconnect(), [disconnect]);\n\n useEffect(() => {\n if (!videoRef.current) return;\n videoRef.current.srcObject = stream;\n }, [stream]);\n\n const clearLogs = useCallback(() => setLogs([]), []);\n\n return useMemo(\n () => ({\n connect,\n disconnect,\n clearLogs,\n logs,\n isConnected,\n connectionState,\n iceConnectionState,\n videoRef,\n stream,\n }),\n [clearLogs, connect, connectionState, disconnect, iceConnectionState, isConnected, logs, stream],\n );\n}\n","const DEFAULT_PORT = 8787;\nconst DEFAULT_PATH = '/ws';\n\nexport interface ResolveScreenReceiverSignalUrlOptions {\n signalUrl?: string;\n path?: string;\n port?: number;\n}\n\nexport function resolveScreenReceiverSignalUrl(\n options: ResolveScreenReceiverSignalUrlOptions = {},\n): string {\n const { signalUrl, path = DEFAULT_PATH, port = DEFAULT_PORT } = options;\n if (signalUrl && signalUrl.trim()) return signalUrl.trim();\n\n const normalizedPath = path.startsWith('/') ? path : `/${path}`;\n if (typeof window !== 'undefined') {\n const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';\n return `${protocol}//${window.location.host}${normalizedPath}`;\n }\n\n return `ws://127.0.0.1:${port}${normalizedPath}`;\n}\n","import React, { useMemo, useState } from 'react';\nimport { resolveScreenReceiverSignalUrl } from './signalUrl';\nimport { useScreenReceiver } from './useScreenReceiver';\n\nexport interface ScreenReceiverPanelProps {\n defaultSignalUrl?: string;\n defaultRoomId?: string;\n className?: string;\n}\n\nconst DEFAULT_ROOM_ID = 'screen-room-1';\n\nexport function ScreenReceiverPanel(props: ScreenReceiverPanelProps) {\n const { defaultSignalUrl, defaultRoomId = DEFAULT_ROOM_ID, className } = props;\n const initialSignalUrl = useMemo(\n () => resolveScreenReceiverSignalUrl({ signalUrl: defaultSignalUrl }),\n [defaultSignalUrl],\n );\n const [wsUrl, setWsUrl] = useState(initialSignalUrl);\n const [roomId, setRoomId] = useState(defaultRoomId);\n const receiver = useScreenReceiver({ wsUrl, roomId });\n const logs = useMemo(() => receiver.logs.map((entry) => entry.text).join('\\n'), [receiver.logs]);\n\n return (\n <div className={className}>\n <div className=\"flex flex-col gap-4\">\n <div className=\"grid gap-3 md:grid-cols-[2fr,1fr,auto]\">\n <label className=\"flex flex-col gap-1 text-sm\">\n <span>Signaling WS</span>\n <input\n className=\"rounded-md border px-3 py-2\"\n value={wsUrl}\n onChange={(event) => setWsUrl(event.target.value)}\n />\n </label>\n <label className=\"flex flex-col gap-1 text-sm\">\n <span>Room</span>\n <input\n className=\"rounded-md border px-3 py-2\"\n value={roomId}\n onChange={(event) => setRoomId(event.target.value)}\n />\n </label>\n <div className=\"flex items-end gap-2\">\n <button\n onClick={() => void receiver.connect()}\n className=\"rounded-md border bg-black px-4 py-2 text-sm text-white\"\n >\n {receiver.isConnected ? 'Reconnect' : 'Connect'}\n </button>\n <button\n onClick={receiver.disconnect}\n className=\"rounded-md border px-4 py-2 text-sm\"\n >\n Disconnect\n </button>\n </div>\n </div>\n\n <div className=\"grid gap-3 md:grid-cols-3\">\n <StatusItem label=\"WebSocket\" value={receiver.isConnected ? 'connected' : 'idle'} />\n <StatusItem label=\"PeerConnection\" value={receiver.connectionState} />\n <StatusItem label=\"ICE State\" value={receiver.iceConnectionState} />\n </div>\n\n <div className=\"grid gap-4 lg:grid-cols-[3fr,2fr]\">\n <div className=\"rounded-xl border bg-black p-3\">\n <video\n ref={receiver.videoRef}\n autoPlay\n playsInline\n controls\n muted\n className=\"h-[360px] w-full rounded-lg bg-black\"\n />\n </div>\n <div className=\"rounded-xl border p-3\">\n <div className=\"flex items-center justify-between\">\n <p className=\"text-sm font-semibold\">Session Log</p>\n <button\n onClick={receiver.clearLogs}\n className=\"text-xs underline-offset-2 hover:underline\"\n >\n Clear\n </button>\n </div>\n <pre className=\"mt-3 h-[320px] overflow-auto rounded-lg border bg-slate-50 p-3 text-xs\">\n {logs || 'No logs yet.'}\n </pre>\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nfunction StatusItem({ label, value }: { label: string; value: string }) {\n return (\n <div className=\"rounded-md border px-3 py-2\">\n <p className=\"text-xs text-slate-500\">{label}</p>\n <p className=\"text-sm font-medium\">{value}</p>\n </div>\n );\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sa2kit",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.67",
|
|
4
4
|
"description": "A modern, type-safe React utility library with cross-platform support and platform adapters",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -353,6 +353,11 @@
|
|
|
353
353
|
"import": "./dist/mikuFireworks3D/server/index.mjs",
|
|
354
354
|
"require": "./dist/mikuFireworks3D/server/index.js"
|
|
355
355
|
},
|
|
356
|
+
"./festivalCard": {
|
|
357
|
+
"types": "./dist/festivalCard/index.d.ts",
|
|
358
|
+
"import": "./dist/festivalCard/index.mjs",
|
|
359
|
+
"require": "./dist/festivalCard/index.js"
|
|
360
|
+
},
|
|
356
361
|
"./components": {
|
|
357
362
|
"types": "./dist/components/index.d.ts",
|
|
358
363
|
"import": "./dist/components/index.mjs",
|
|
@@ -517,6 +522,11 @@
|
|
|
517
522
|
"types": "./dist/screenReceiver/web/index.d.ts",
|
|
518
523
|
"import": "./dist/screenReceiver/web/index.mjs",
|
|
519
524
|
"require": "./dist/screenReceiver/web/index.js"
|
|
525
|
+
},
|
|
526
|
+
"./screenReceiver/server/next": {
|
|
527
|
+
"types": "./dist/screenReceiver/server/next.d.ts",
|
|
528
|
+
"import": "./dist/screenReceiver/server/next.mjs",
|
|
529
|
+
"require": "./dist/screenReceiver/server/next.js"
|
|
520
530
|
}
|
|
521
531
|
},
|
|
522
532
|
"files": [
|