move web components to web/
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
import { useState, useEffect, useRef, useCallback } from 'react';
|
||||
import { API } from '../api/player';
|
||||
|
||||
interface UseScreenShareResult {
|
||||
isScreenSharing: boolean;
|
||||
isScreenSharingSupported: boolean;
|
||||
toggleScreenShare: () => Promise<void>;
|
||||
stopScreenShare: () => void;
|
||||
}
|
||||
|
||||
function getBestSupportedMimeType() {
|
||||
// Ordered by preference (best first) - all of these include audio+video
|
||||
const mimeTypes = [
|
||||
'video/webm;codecs=vp9,opus', // Best quality, good compression
|
||||
'video/webm;codecs=vp8,opus', // Good fallback, well supported
|
||||
'video/webm;codecs=h264,opus', // Better compatibility with some systems
|
||||
'video/mp4;codecs=h264,aac', // Good for Safari but may not be supported for MediaRecorder
|
||||
'video/webm', // Generic fallback (browser will choose codecs)
|
||||
'video/mp4' // Last resort
|
||||
];
|
||||
|
||||
// Find the first supported mimetype
|
||||
for (const type of mimeTypes) {
|
||||
if (MediaRecorder.isTypeSupported(type)) {
|
||||
console.log(`Using mime type: ${type}`);
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
// If none are supported, return null or a basic fallback
|
||||
console.warn('No preferred mime types supported by this browser');
|
||||
return 'video/webm'; // Most basic fallback
|
||||
}
|
||||
|
||||
export const useScreenShare = (): UseScreenShareResult => {
|
||||
const [isScreenSharing, setIsScreenSharing] = useState(false);
|
||||
const [isScreenSharingSupported, setIsScreenSharingSupported] = useState(false);
|
||||
const screenShareSocketRef = useRef<WebSocket | null>(null);
|
||||
|
||||
// Check if screen sharing is supported
|
||||
useEffect(() => {
|
||||
setIsScreenSharingSupported(
|
||||
typeof navigator !== 'undefined' &&
|
||||
navigator.mediaDevices !== undefined &&
|
||||
typeof navigator.mediaDevices.getDisplayMedia === 'function'
|
||||
);
|
||||
}, []);
|
||||
|
||||
const stopScreenShare = useCallback(() => {
|
||||
if (screenShareSocketRef.current) {
|
||||
screenShareSocketRef.current.close();
|
||||
screenShareSocketRef.current = null;
|
||||
}
|
||||
setIsScreenSharing(false);
|
||||
}, []);
|
||||
|
||||
const startScreenShare = useCallback(async () => {
|
||||
try {
|
||||
const mediaStream = await navigator.mediaDevices.getDisplayMedia({
|
||||
video: true,
|
||||
audio: true,
|
||||
});
|
||||
|
||||
let mimeType = getBestSupportedMimeType();
|
||||
console.log('Using MIME type:', mimeType);
|
||||
|
||||
const mediaRecorder = new MediaRecorder(mediaStream, {
|
||||
mimeType: mimeType,
|
||||
videoBitsPerSecond: 2500000, // 2.5 Mbps
|
||||
audioBitsPerSecond: 128000, // 128 kbps
|
||||
});
|
||||
|
||||
// Connect to WebSocket
|
||||
screenShareSocketRef.current = API.startScreenShare(mimeType);
|
||||
|
||||
// Set up WebSocket event handlers
|
||||
screenShareSocketRef.current.onopen = () => {
|
||||
console.log('Screen sharing WebSocket connected');
|
||||
setIsScreenSharing(true);
|
||||
|
||||
mediaRecorder.start(100);
|
||||
};
|
||||
|
||||
screenShareSocketRef.current.onclose = () => {
|
||||
console.log('Screen sharing WebSocket closed');
|
||||
setIsScreenSharing(false);
|
||||
|
||||
// Stop all tracks when WebSocket is closed
|
||||
mediaStream.getTracks().forEach(track => track.stop());
|
||||
};
|
||||
|
||||
screenShareSocketRef.current.onerror = (error) => {
|
||||
console.error('Screen sharing WebSocket error:', error);
|
||||
setIsScreenSharing(false);
|
||||
|
||||
// Stop all tracks on error
|
||||
mediaStream.getTracks().forEach(track => track.stop());
|
||||
};
|
||||
|
||||
// Send data over WebSocket when available
|
||||
mediaRecorder.ondataavailable = (event) => {
|
||||
if (event.data && event.data.size > 0 && screenShareSocketRef.current && screenShareSocketRef.current.readyState === WebSocket.OPEN) {
|
||||
screenShareSocketRef.current.send(event.data);
|
||||
}
|
||||
};
|
||||
|
||||
// Handle stream ending (user clicks "Stop sharing")
|
||||
mediaStream.getVideoTracks()[0].onended = () => {
|
||||
if (screenShareSocketRef.current) {
|
||||
screenShareSocketRef.current.close();
|
||||
screenShareSocketRef.current = null;
|
||||
}
|
||||
setIsScreenSharing(false);
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error starting screen share:', error);
|
||||
setIsScreenSharing(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const toggleScreenShare = useCallback(async () => {
|
||||
if (screenShareSocketRef.current) {
|
||||
stopScreenShare();
|
||||
} else {
|
||||
await startScreenShare();
|
||||
}
|
||||
}, [startScreenShare, stopScreenShare]);
|
||||
|
||||
return {
|
||||
isScreenSharing,
|
||||
isScreenSharingSupported,
|
||||
toggleScreenShare,
|
||||
stopScreenShare
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user