Skip to content

Commit 5afa44d

Browse files
authored
Update customize.tsx
helper for missing camera / mic
1 parent 2067798 commit 5afa44d

File tree

1 file changed

+48
-3
lines changed

1 file changed

+48
-3
lines changed

examples/nextjs/pages/customize.tsx

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ const CustomizeExample: NextPage = () => {
2626
const [connect, setConnect] = useState(false);
2727
const [isConnected, setIsConnected] = useState(false);
2828
const [error, setError] = useState<string>();
29+
const [hasAudio, setHasAudio] = useState(false);
30+
const [hasVideo, setHasVideo] = useState(false);
2931

3032
// Get room parameters once on mount
3133
const [roomParams] = useState(() => {
@@ -37,6 +39,30 @@ const CustomizeExample: NextPage = () => {
3739
};
3840
});
3941

42+
// Check available devices on mount
43+
useEffect(() => {
44+
async function checkDevices() {
45+
try {
46+
const devices = await navigator.mediaDevices.enumerateDevices();
47+
setHasAudio(devices.some(device => device.kind === 'audioinput'));
48+
setHasVideo(devices.some(device => device.kind === 'videoinput'));
49+
} catch (e) {
50+
console.warn('Unable to check media devices:', e);
51+
setHasAudio(false);
52+
setHasVideo(false);
53+
}
54+
}
55+
56+
// Only check devices if on client side and API is available
57+
if (typeof window !== 'undefined' && navigator.mediaDevices) {
58+
checkDevices();
59+
60+
// Listen for device changes
61+
navigator.mediaDevices.addEventListener('devicechange', checkDevices);
62+
return () => navigator.mediaDevices.removeEventListener('devicechange', checkDevices);
63+
}
64+
}, []);
65+
4066
// Fetch token only when connect button is clicked
4167
const fetchToken = useCallback(async () => {
4268
try {
@@ -75,6 +101,11 @@ const CustomizeExample: NextPage = () => {
75101
}, []);
76102

77103
const handleError = useCallback((err: Error) => {
104+
// Don't treat missing devices as a fatal error
105+
if (err.name === 'NotFoundError' || err.name === 'NotAllowedError') {
106+
console.warn('Media device error:', err);
107+
return;
108+
}
78109
console.error('LiveKit error:', err);
79110
setError(err.message);
80111
handleDisconnect();
@@ -87,8 +118,14 @@ const CustomizeExample: NextPage = () => {
87118
Welcome to <a href="https://livekit.io">LiveKit</a>
88119
</h1>
89120

121+
{!hasAudio && !hasVideo && (
122+
<div style={{ backgroundColor: '#fff3cd', color: '#856404', padding: '1rem', borderRadius: '4px', margin: '1rem 0' }}>
123+
No camera or microphone detected. You can still join but won't be able to share audio or video.
124+
</div>
125+
)}
126+
90127
{error && (
91-
<div style={{ color: 'red', margin: '1rem 0' }}>
128+
<div style={{ backgroundColor: '#f8d7da', color: '#721c24', padding: '1rem', borderRadius: '4px', margin: '1rem 0' }}>
92129
Error: {error}
93130
</div>
94131
)}
@@ -111,8 +148,16 @@ const CustomizeExample: NextPage = () => {
111148
onConnected={() => setIsConnected(true)}
112149
onDisconnected={handleDisconnect}
113150
onError={handleError}
114-
audio={true}
115-
video={true}
151+
// Only enable audio/video if devices are available
152+
audio={hasAudio}
153+
video={hasVideo}
154+
options={{
155+
audioCaptureDefaults: {
156+
echoCancellation: true,
157+
noiseSuppression: true,
158+
autoGainControl: true,
159+
},
160+
}}
116161
>
117162
<RoomAudioRenderer />
118163
{isConnected && <Stage />}

0 commit comments

Comments
 (0)