forked from Shiloh/remnantchat
feat: Connection status (#119)
* feat: implement ConnectionTest * feat: display connection results * feat: keep network status up to date
This commit is contained in:
parent
4cf75b15b0
commit
3977a82224
34
package-lock.json
generated
34
package-lock.json
generated
@ -41,6 +41,7 @@
|
|||||||
"readable-web-to-node-stream": "^3.0.2",
|
"readable-web-to-node-stream": "^3.0.2",
|
||||||
"remark-gfm": "^3.0.1",
|
"remark-gfm": "^3.0.1",
|
||||||
"sass": "^1.54.3",
|
"sass": "^1.54.3",
|
||||||
|
"sdp": "^3.2.0",
|
||||||
"secure-file-transfer": "^0.0.7",
|
"secure-file-transfer": "^0.0.7",
|
||||||
"streamsaver": "^2.0.6",
|
"streamsaver": "^2.0.6",
|
||||||
"trystero": "^0.12.0",
|
"trystero": "^0.12.0",
|
||||||
@ -48,7 +49,8 @@
|
|||||||
"typeface-roboto": "^1.1.13",
|
"typeface-roboto": "^1.1.13",
|
||||||
"typescript": "^4.7.4",
|
"typescript": "^4.7.4",
|
||||||
"uuid": "^8.3.2",
|
"uuid": "^8.3.2",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4",
|
||||||
|
"webrtc-adapter": "^8.2.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react-syntax-highlighter": "^15.5.5",
|
"@types/react-syntax-highlighter": "^15.5.5",
|
||||||
@ -23323,6 +23325,11 @@
|
|||||||
"url": "https://opencollective.com/webpack"
|
"url": "https://opencollective.com/webpack"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sdp": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/sdp/-/sdp-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw=="
|
||||||
|
},
|
||||||
"node_modules/secp256k1": {
|
"node_modules/secp256k1": {
|
||||||
"version": "4.0.3",
|
"version": "4.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz",
|
||||||
@ -26169,6 +26176,18 @@
|
|||||||
"node": ">=4.0"
|
"node": ">=4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/webrtc-adapter": {
|
||||||
|
"version": "8.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-8.2.2.tgz",
|
||||||
|
"integrity": "sha512-jQWwqiAEAFZamWliJo0Q+dIC6ZMJ8BgCFvW/oXWVFby1Nw14dOUfPwZ3lVe4nafDXdTyCUT7xfLt5xXiioXUCQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"sdp": "^3.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0",
|
||||||
|
"npm": ">=3.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/websocket-driver": {
|
"node_modules/websocket-driver": {
|
||||||
"version": "0.7.4",
|
"version": "0.7.4",
|
||||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
|
||||||
@ -43868,6 +43887,11 @@
|
|||||||
"ajv-keywords": "^3.5.2"
|
"ajv-keywords": "^3.5.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"sdp": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/sdp/-/sdp-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw=="
|
||||||
|
},
|
||||||
"secp256k1": {
|
"secp256k1": {
|
||||||
"version": "4.0.3",
|
"version": "4.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz",
|
||||||
@ -45955,6 +45979,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
|
||||||
"integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w=="
|
"integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w=="
|
||||||
},
|
},
|
||||||
|
"webrtc-adapter": {
|
||||||
|
"version": "8.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-8.2.2.tgz",
|
||||||
|
"integrity": "sha512-jQWwqiAEAFZamWliJo0Q+dIC6ZMJ8BgCFvW/oXWVFby1Nw14dOUfPwZ3lVe4nafDXdTyCUT7xfLt5xXiioXUCQ==",
|
||||||
|
"requires": {
|
||||||
|
"sdp": "^3.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"websocket-driver": {
|
"websocket-driver": {
|
||||||
"version": "0.7.4",
|
"version": "0.7.4",
|
||||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
"readable-web-to-node-stream": "^3.0.2",
|
"readable-web-to-node-stream": "^3.0.2",
|
||||||
"remark-gfm": "^3.0.1",
|
"remark-gfm": "^3.0.1",
|
||||||
"sass": "^1.54.3",
|
"sass": "^1.54.3",
|
||||||
|
"sdp": "^3.2.0",
|
||||||
"secure-file-transfer": "^0.0.7",
|
"secure-file-transfer": "^0.0.7",
|
||||||
"streamsaver": "^2.0.6",
|
"streamsaver": "^2.0.6",
|
||||||
"trystero": "^0.12.0",
|
"trystero": "^0.12.0",
|
||||||
@ -44,7 +45,8 @@
|
|||||||
"typeface-roboto": "^1.1.13",
|
"typeface-roboto": "^1.1.13",
|
||||||
"typescript": "^4.7.4",
|
"typescript": "^4.7.4",
|
||||||
"uuid": "^8.3.2",
|
"uuid": "^8.3.2",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4",
|
||||||
|
"webrtc-adapter": "^8.2.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
|
49
src/components/Shell/ConnectionTestResults.tsx
Normal file
49
src/components/Shell/ConnectionTestResults.tsx
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { Typography } from '@mui/material'
|
||||||
|
import Circle from '@mui/icons-material/FiberManualRecord'
|
||||||
|
|
||||||
|
import { ConnectionTestResults as IConnectionTestResults } from './useConnectionTest'
|
||||||
|
|
||||||
|
interface ConnectionTestResultsProps {
|
||||||
|
connectionTestResults: IConnectionTestResults
|
||||||
|
}
|
||||||
|
export const ConnectionTestResults = ({
|
||||||
|
connectionTestResults: { hasHost, hasRelay },
|
||||||
|
}: ConnectionTestResultsProps) => {
|
||||||
|
if (hasHost && hasRelay) {
|
||||||
|
return (
|
||||||
|
<Typography variant="subtitle2">
|
||||||
|
<Typography
|
||||||
|
component="span"
|
||||||
|
sx={theme => ({ color: theme.palette.success.main })}
|
||||||
|
>
|
||||||
|
<Circle sx={{ fontSize: 'small' }} />
|
||||||
|
</Typography>{' '}
|
||||||
|
Full network connection
|
||||||
|
</Typography>
|
||||||
|
)
|
||||||
|
} else if (hasHost) {
|
||||||
|
return (
|
||||||
|
<Typography variant="subtitle2">
|
||||||
|
<Typography
|
||||||
|
component="span"
|
||||||
|
sx={theme => ({ color: theme.palette.warning.main })}
|
||||||
|
>
|
||||||
|
<Circle sx={{ fontSize: 'small' }} />
|
||||||
|
</Typography>{' '}
|
||||||
|
Partial network connection
|
||||||
|
</Typography>
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<Typography variant="subtitle2">
|
||||||
|
<Typography
|
||||||
|
component="span"
|
||||||
|
sx={theme => ({ color: theme.palette.error.main })}
|
||||||
|
>
|
||||||
|
<Circle sx={{ fontSize: 'small' }} />
|
||||||
|
</Typography>{' '}
|
||||||
|
No network connection
|
||||||
|
</Typography>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,8 @@ import { AudioState, Peer } from 'models/chat'
|
|||||||
import { PeerConnectionType } from 'services/PeerRoom/PeerRoom'
|
import { PeerConnectionType } from 'services/PeerRoom/PeerRoom'
|
||||||
|
|
||||||
import { PeerListItem } from './PeerListItem'
|
import { PeerListItem } from './PeerListItem'
|
||||||
|
import { ConnectionTestResults as IConnectionTestResults } from './useConnectionTest'
|
||||||
|
import { ConnectionTestResults } from './ConnectionTestResults'
|
||||||
|
|
||||||
export const peerListWidth = 300
|
export const peerListWidth = 300
|
||||||
|
|
||||||
@ -26,6 +28,7 @@ export interface PeerListProps extends PropsWithChildren {
|
|||||||
peerConnectionTypes: Record<string, PeerConnectionType>
|
peerConnectionTypes: Record<string, PeerConnectionType>
|
||||||
audioState: AudioState
|
audioState: AudioState
|
||||||
peerAudios: Record<string, HTMLAudioElement>
|
peerAudios: Record<string, HTMLAudioElement>
|
||||||
|
connectionTestResults: IConnectionTestResults
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PeerList = ({
|
export const PeerList = ({
|
||||||
@ -36,6 +39,7 @@ export const PeerList = ({
|
|||||||
peerConnectionTypes,
|
peerConnectionTypes,
|
||||||
audioState,
|
audioState,
|
||||||
peerAudios,
|
peerAudios,
|
||||||
|
connectionTestResults,
|
||||||
}: PeerListProps) => {
|
}: PeerListProps) => {
|
||||||
return (
|
return (
|
||||||
<MuiDrawer
|
<MuiDrawer
|
||||||
@ -59,9 +63,15 @@ export const PeerList = ({
|
|||||||
<IconButton onClick={onPeerListClose} aria-label="Close peer list">
|
<IconButton onClick={onPeerListClose} aria-label="Close peer list">
|
||||||
<ChevronRightIcon />
|
<ChevronRightIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
<ListItem>
|
||||||
|
<ConnectionTestResults
|
||||||
|
connectionTestResults={connectionTestResults}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
</PeerListHeader>
|
</PeerListHeader>
|
||||||
<Divider />
|
<Divider />
|
||||||
<List>
|
<List>
|
||||||
|
<Divider />
|
||||||
<ListItem divider={true}>
|
<ListItem divider={true}>
|
||||||
{audioState === AudioState.PLAYING && (
|
{audioState === AudioState.PLAYING && (
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
|
@ -29,6 +29,7 @@ import { RouteContent } from './RouteContent'
|
|||||||
import { PeerList } from './PeerList'
|
import { PeerList } from './PeerList'
|
||||||
import { QRCodeDialog } from './QRCodeDialog'
|
import { QRCodeDialog } from './QRCodeDialog'
|
||||||
import { RoomShareDialog } from './RoomShareDialog'
|
import { RoomShareDialog } from './RoomShareDialog'
|
||||||
|
import { useConnectionTest } from './useConnectionTest'
|
||||||
|
|
||||||
export interface ShellProps extends PropsWithChildren {
|
export interface ShellProps extends PropsWithChildren {
|
||||||
userPeerId: string
|
userPeerId: string
|
||||||
@ -90,6 +91,8 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
|
|||||||
setIsAlertShowing(true)
|
setIsAlertShowing(true)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const { connectionTestResults } = useConnectionTest()
|
||||||
|
|
||||||
const shellContextValue = useMemo(
|
const shellContextValue = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
tabHasFocus,
|
tabHasFocus,
|
||||||
@ -118,6 +121,7 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
|
|||||||
setPeerAudios,
|
setPeerAudios,
|
||||||
customUsername,
|
customUsername,
|
||||||
setCustomUsername,
|
setCustomUsername,
|
||||||
|
connectionTestResults,
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
isPeerListOpen,
|
isPeerListOpen,
|
||||||
@ -143,6 +147,7 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
|
|||||||
setPeerAudios,
|
setPeerAudios,
|
||||||
customUsername,
|
customUsername,
|
||||||
setCustomUsername,
|
setCustomUsername,
|
||||||
|
connectionTestResults,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -326,6 +331,7 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
|
|||||||
peerConnectionTypes={peerConnectionTypes}
|
peerConnectionTypes={peerConnectionTypes}
|
||||||
audioState={audioState}
|
audioState={audioState}
|
||||||
peerAudios={peerAudios}
|
peerAudios={peerAudios}
|
||||||
|
connectionTestResults={connectionTestResults}
|
||||||
/>
|
/>
|
||||||
<QRCodeDialog
|
<QRCodeDialog
|
||||||
isOpen={isQRCodeDialogOpen}
|
isOpen={isQRCodeDialogOpen}
|
||||||
|
74
src/components/Shell/useConnectionTest.ts
Normal file
74
src/components/Shell/useConnectionTest.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { sleep } from 'utils'
|
||||||
|
import {
|
||||||
|
ConnectionTest,
|
||||||
|
ConnectionTestEvent,
|
||||||
|
ConnectionTestEvents,
|
||||||
|
} from 'services/ConnectionTest/ConnectionTest'
|
||||||
|
|
||||||
|
export interface ConnectionTestResults {
|
||||||
|
hasHost: boolean
|
||||||
|
hasRelay: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useConnectionTest = () => {
|
||||||
|
const [hasHost, setHasHost] = useState(false)
|
||||||
|
const [hasRelay, setHasRelay] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const checkConnection = async () => {
|
||||||
|
const connectionTest = new ConnectionTest()
|
||||||
|
|
||||||
|
const handleHasHostChanged = ((event: ConnectionTestEvent) => {
|
||||||
|
if (event.detail.hasHost) {
|
||||||
|
setHasHost(true)
|
||||||
|
|
||||||
|
connectionTest.removeEventListener(
|
||||||
|
ConnectionTestEvents.HAS_HOST_CHANGED,
|
||||||
|
handleHasHostChanged
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}) as EventListener
|
||||||
|
|
||||||
|
connectionTest.addEventListener(
|
||||||
|
ConnectionTestEvents.HAS_HOST_CHANGED,
|
||||||
|
handleHasHostChanged
|
||||||
|
)
|
||||||
|
|
||||||
|
const handleHasRelayChanged = ((event: ConnectionTestEvent) => {
|
||||||
|
if (event.detail.hasRelay) {
|
||||||
|
setHasRelay(true)
|
||||||
|
|
||||||
|
connectionTest.removeEventListener(
|
||||||
|
ConnectionTestEvents.HAS_RELAY_CHANGED,
|
||||||
|
handleHasRelayChanged
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}) as EventListener
|
||||||
|
|
||||||
|
connectionTest.addEventListener(
|
||||||
|
ConnectionTestEvents.HAS_RELAY_CHANGED,
|
||||||
|
handleHasRelayChanged
|
||||||
|
)
|
||||||
|
|
||||||
|
try {
|
||||||
|
await connectionTest.runRtcPeerConnectionTest()
|
||||||
|
} catch (e) {
|
||||||
|
setHasHost(false)
|
||||||
|
setHasRelay(false)
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
;(async () => {
|
||||||
|
while (true) {
|
||||||
|
await checkConnection()
|
||||||
|
await sleep(20 * 1000)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return {
|
||||||
|
connectionTestResults: { hasHost, hasRelay },
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ import { createContext, Dispatch, SetStateAction } from 'react'
|
|||||||
import { AlertOptions } from 'models/shell'
|
import { AlertOptions } from 'models/shell'
|
||||||
import { AudioState, ScreenShareState, VideoState, Peer } from 'models/chat'
|
import { AudioState, ScreenShareState, VideoState, Peer } from 'models/chat'
|
||||||
import { PeerConnectionType } from 'services/PeerRoom/PeerRoom'
|
import { PeerConnectionType } from 'services/PeerRoom/PeerRoom'
|
||||||
|
import { ConnectionTestResults } from 'components/Shell/useConnectionTest'
|
||||||
|
|
||||||
interface ShellContextProps {
|
interface ShellContextProps {
|
||||||
tabHasFocus: boolean
|
tabHasFocus: boolean
|
||||||
@ -32,6 +33,7 @@ interface ShellContextProps {
|
|||||||
setPeerAudios: Dispatch<SetStateAction<Record<string, HTMLAudioElement>>>
|
setPeerAudios: Dispatch<SetStateAction<Record<string, HTMLAudioElement>>>
|
||||||
customUsername: string
|
customUsername: string
|
||||||
setCustomUsername: Dispatch<SetStateAction<string>>
|
setCustomUsername: Dispatch<SetStateAction<string>>
|
||||||
|
connectionTestResults: ConnectionTestResults
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ShellContext = createContext<ShellContextProps>({
|
export const ShellContext = createContext<ShellContextProps>({
|
||||||
@ -60,4 +62,5 @@ export const ShellContext = createContext<ShellContextProps>({
|
|||||||
setPeerAudios: () => {},
|
setPeerAudios: () => {},
|
||||||
customUsername: '',
|
customUsername: '',
|
||||||
setCustomUsername: () => {},
|
setCustomUsername: () => {},
|
||||||
|
connectionTestResults: { hasHost: false, hasRelay: false },
|
||||||
})
|
})
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'webrtc-adapter'
|
||||||
import { Buffer } from 'buffer'
|
import { Buffer } from 'buffer'
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
77
src/services/ConnectionTest/ConnectionTest.ts
Normal file
77
src/services/ConnectionTest/ConnectionTest.ts
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import { rtcConfig } from 'config/rtcConfig'
|
||||||
|
import { parseCandidate } from 'sdp'
|
||||||
|
|
||||||
|
export enum ConnectionTestEvents {
|
||||||
|
CONNECTION_TEST_RESULTS_UPDATED = 'CONNECTION_TEST_RESULTS_UPDATED',
|
||||||
|
HAS_HOST_CHANGED = 'HAS_HOST_CHANGED',
|
||||||
|
HAS_RELAY_CHANGED = 'HAS_RELAY_CHANGED',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ConnectionTestEvent = CustomEvent<ConnectionTest>
|
||||||
|
|
||||||
|
export class ConnectionTest extends EventTarget {
|
||||||
|
hasHost = false
|
||||||
|
hasRelay = false
|
||||||
|
hasPeerReflexive = false
|
||||||
|
hasServerReflexive = false
|
||||||
|
|
||||||
|
async runRtcPeerConnectionTest() {
|
||||||
|
if (typeof RTCPeerConnection === 'undefined') return
|
||||||
|
|
||||||
|
const { iceServers } = rtcConfig
|
||||||
|
|
||||||
|
const rtcPeerConnection = new RTCPeerConnection({
|
||||||
|
iceServers,
|
||||||
|
})
|
||||||
|
|
||||||
|
rtcPeerConnection.addEventListener('icecandidate', event => {
|
||||||
|
if (event.candidate?.candidate.length) {
|
||||||
|
const parsedCandidate = parseCandidate(event.candidate.candidate)
|
||||||
|
let eventType: ConnectionTestEvents | undefined
|
||||||
|
|
||||||
|
switch (parsedCandidate.type) {
|
||||||
|
case 'host':
|
||||||
|
this.hasHost = true
|
||||||
|
eventType = ConnectionTestEvents.HAS_HOST_CHANGED
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'relay':
|
||||||
|
this.hasRelay = true
|
||||||
|
eventType = ConnectionTestEvents.HAS_RELAY_CHANGED
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'prflx':
|
||||||
|
this.hasPeerReflexive = true
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'srflx':
|
||||||
|
this.hasServerReflexive = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof eventType !== 'undefined') {
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent(eventType, {
|
||||||
|
detail: this,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dispatchEvent(
|
||||||
|
new Event(ConnectionTestEvents.CONNECTION_TEST_RESULTS_UPDATED)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Kick off the connection test
|
||||||
|
try {
|
||||||
|
const rtcSessionDescription = await rtcPeerConnection.createOffer({
|
||||||
|
offerToReceiveAudio: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
rtcPeerConnection.setLocalDescription(rtcSessionDescription)
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const connectionTest = new ConnectionTest()
|
Loading…
x
Reference in New Issue
Block a user