🐛(frontend) add LiveKit connection warmup for Firefox+proxy fixes
Implement HTTPS prefetch before joining rooms to resolve WebSocket handshake failures where Firefox+proxy returns HTTP 200 instead of 101. Reproduced locally with Squid container. No proxy configuration fixes found - HTTPS warmup is only working workaround. Issue doesn't occur when signaling server shares webapp domain, making warmup unnecessary. Use HEAD request to minimize bandwidth.
This commit is contained in:
@@ -50,6 +50,7 @@ def get_frontend_configuration(request):
|
|||||||
else None,
|
else None,
|
||||||
"default_country": settings.ROOM_TELEPHONY_DEFAULT_COUNTRY,
|
"default_country": settings.ROOM_TELEPHONY_DEFAULT_COUNTRY,
|
||||||
},
|
},
|
||||||
|
"livekit": {"url": settings.LIVEKIT_CONFIGURATION["url"]},
|
||||||
}
|
}
|
||||||
frontend_configuration.update(settings.FRONTEND_CONFIGURATION)
|
frontend_configuration.update(settings.FRONTEND_CONFIGURATION)
|
||||||
return Response(frontend_configuration)
|
return Response(frontend_configuration)
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ export interface ApiConfig {
|
|||||||
default_country?: string
|
default_country?: string
|
||||||
}
|
}
|
||||||
manifest_link?: string
|
manifest_link?: string
|
||||||
|
livekit: {
|
||||||
|
url: string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchConfig = (): Promise<ApiConfig> => {
|
const fetchConfig = (): Promise<ApiConfig> => {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import { LocalUserChoices } from '@/stores/userChoices'
|
|||||||
import { navigateTo } from '@/navigation/navigateTo'
|
import { navigateTo } from '@/navigation/navigateTo'
|
||||||
import { MediaDeviceErrorAlert } from './MediaDeviceErrorAlert'
|
import { MediaDeviceErrorAlert } from './MediaDeviceErrorAlert'
|
||||||
import { usePostHog } from 'posthog-js/react'
|
import { usePostHog } from 'posthog-js/react'
|
||||||
|
import { useConfig } from '@/api/useConfig'
|
||||||
|
|
||||||
export const Conference = ({
|
export const Conference = ({
|
||||||
roomId,
|
roomId,
|
||||||
@@ -37,12 +38,15 @@ export const Conference = ({
|
|||||||
initialRoomData?: ApiRoom
|
initialRoomData?: ApiRoom
|
||||||
}) => {
|
}) => {
|
||||||
const posthog = usePostHog()
|
const posthog = usePostHog()
|
||||||
|
const { data: apiConfig } = useConfig()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
posthog.capture('visit-room', { slug: roomId })
|
posthog.capture('visit-room', { slug: roomId })
|
||||||
}, [roomId, posthog])
|
}, [roomId, posthog])
|
||||||
const fetchKey = [keys.room, roomId]
|
const fetchKey = [keys.room, roomId]
|
||||||
|
|
||||||
|
const [isConnectionWarmedUp, setIsConnectionWarmedUp] = useState(false)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
mutateAsync: createRoom,
|
mutateAsync: createRoom,
|
||||||
status: createStatus,
|
status: createStatus,
|
||||||
@@ -53,6 +57,36 @@ export const Conference = ({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Warm up connection to LiveKit server before joining room
|
||||||
|
* This prefetch helps reduce initial connection latency by establishing
|
||||||
|
* an early HTTP connection to the WebRTC signaling server
|
||||||
|
*
|
||||||
|
* FIREFOX + PROXY WORKAROUND:
|
||||||
|
* On Firefox behind proxy configurations, WebSocket signaling fails to establish.
|
||||||
|
* Client receives HTTP 200 instead of expected 101 (Switching Protocols).
|
||||||
|
* This appears to be a certificate/security issue where the initial request
|
||||||
|
* is considered unsecure. By first calling the signaling server via HTTPS,
|
||||||
|
* subsequent WebSocket establishment works correctly in these setups.
|
||||||
|
* This is a temporary workaround - issue is reproducible on LiveKit's demo app.
|
||||||
|
*/
|
||||||
|
useEffect(() => {
|
||||||
|
const warmUpLivekitConnection = async () => {
|
||||||
|
if (isConnectionWarmedUp || !apiConfig) return
|
||||||
|
try {
|
||||||
|
// Make HTTPS request to establish secure connection
|
||||||
|
// This resolves Firefox+proxy WebSocket handshake issues
|
||||||
|
await fetch(apiConfig.livekit.url)
|
||||||
|
setIsConnectionWarmedUp(true)
|
||||||
|
} catch (error) {
|
||||||
|
// Don't block room connection if warmup fails
|
||||||
|
console.warn('LiveKit connection warmup failed:', error)
|
||||||
|
setIsConnectionWarmedUp(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
warmUpLivekitConnection()
|
||||||
|
}, [isConnectionWarmedUp, apiConfig])
|
||||||
|
|
||||||
const {
|
const {
|
||||||
status: fetchStatus,
|
status: fetchStatus,
|
||||||
isError: isFetchError,
|
isError: isFetchError,
|
||||||
@@ -125,9 +159,9 @@ export const Conference = ({
|
|||||||
<Screen header={false} footer={false}>
|
<Screen header={false} footer={false}>
|
||||||
<LiveKitRoom
|
<LiveKitRoom
|
||||||
room={room}
|
room={room}
|
||||||
serverUrl={data?.livekit?.url}
|
serverUrl={apiConfig?.livekit.url}
|
||||||
token={data?.livekit?.token}
|
token={data?.livekit?.token}
|
||||||
connect={true}
|
connect={isConnectionWarmedUp}
|
||||||
audio={userConfig.audioEnabled}
|
audio={userConfig.audioEnabled}
|
||||||
video={
|
video={
|
||||||
userConfig.videoEnabled && {
|
userConfig.videoEnabled && {
|
||||||
|
|||||||
Reference in New Issue
Block a user