Wait for ICE gathering completion before requesting video track + create file e2e test fix (#5193)

* Test main e2e

* Create projects separately in home page tests

I think creating them in Promise.all was introducing nondeterminism and
making tests flaky.

* Query the homepage projects in an order-insensitive way

* Wait for ICE candidate gathering to complete before requesting video track

* Update src/lang/std/engineConnection.ts

Co-authored-by: Jonathan Tran <jonnytran@gmail.com>

* Fix create file e2e failure

* Yarn fmt

* Fix typo: s/that/this

yarn tsc was failing with this error:

```
src/lang/std/engineConnection.ts:1285:7 - error TS2304: Cannot find name 'that'.

1285       that.triggeredStart = false
           ~~~~
```

* Fix up revolve tests

* Turn off 3 flaky Windows tests

* Fix tags

---------

Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
This commit is contained in:
49fl
2025-02-03 13:41:23 -05:00
committed by GitHub
parent 3e8ee3ffc4
commit 56d861f2cc
10 changed files with 281 additions and 237 deletions

View File

@ -127,54 +127,54 @@ test.describe('Command bar tests', () => {
await expect(commandLevelArgButton).toHaveText('level: project') await expect(commandLevelArgButton).toHaveText('level: project')
}) })
test('Command bar keybinding works from code editor and can change a setting', async ({ test(
page, 'Command bar keybinding works from code editor and can change a setting',
homePage, { tag: ['@skipWin'] },
}) => { async ({ page, homePage }) => {
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await expect( await expect(
page.getByRole('button', { name: 'Start Sketch' }) page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled() ).not.toBeDisabled()
// Put the cursor in the code editor // Put the cursor in the code editor
await page.locator('.cm-content').click() await page.locator('.cm-content').click()
// Now try the same, but with the keyboard shortcut, check focus // Now try the same, but with the keyboard shortcut, check focus
await page.keyboard.press('ControlOrMeta+K') await page.keyboard.press('ControlOrMeta+K')
let cmdSearchBar = page.getByPlaceholder('Search commands') let cmdSearchBar = page.getByPlaceholder('Search commands')
await expect(cmdSearchBar).toBeVisible() await expect(cmdSearchBar).toBeVisible()
await expect(cmdSearchBar).toBeFocused() await expect(cmdSearchBar).toBeFocused()
// Try typing in the command bar // Try typing in the command bar
await cmdSearchBar.fill('theme') await cmdSearchBar.fill('theme')
const themeOption = page.getByRole('option', { const themeOption = page.getByRole('option', {
name: 'Settings · app · theme', name: 'Settings · app · theme',
}) })
await expect(themeOption).toBeVisible() await expect(themeOption).toBeVisible()
await themeOption.click() await themeOption.click()
const themeInput = page.getByPlaceholder('dark') const themeInput = page.getByPlaceholder('dark')
await expect(themeInput).toBeVisible() await expect(themeInput).toBeVisible()
await expect(themeInput).toBeFocused() await expect(themeInput).toBeFocused()
// Select dark theme // Select dark theme
await page.keyboard.press('ArrowDown') await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown') await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown') await page.keyboard.press('ArrowDown')
await expect(page.getByRole('option', { name: 'system' })).toHaveAttribute( await expect(
'data-headlessui-state', page.getByRole('option', { name: 'system' })
'active' ).toHaveAttribute('data-headlessui-state', 'active')
) await page.keyboard.press('Enter')
await page.keyboard.press('Enter')
// Check the toast appeared // Check the toast appeared
await expect( await expect(
page.getByText(`Set theme to "system" as a user default`) page.getByText(`Set theme to "system" as a user default`)
).toBeVisible() ).toBeVisible()
// Check that the theme changed // Check that the theme changed
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`) await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
}) }
)
test('Can extrude from the command bar', async ({ page, homePage }) => { test('Can extrude from the command bar', async ({ page, homePage }) => {
await page.addInitScript(async () => { await page.addInitScript(async () => {

View File

@ -966,106 +966,106 @@ test.describe('Editor tests', () => {
|> close(%)`) |> close(%)`)
}) })
test('Can undo a sketch modification with ctrl+z', async ({ test(
page, 'Can undo a sketch modification with ctrl+z',
homePage, { tag: ['@skipWin'] },
}) => { async ({ page, homePage }) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',
`sketch001 = startSketchOn('XZ') `sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -10.01], %) |> startProfileAt([4.61, -10.01], %)
|> line([12.73, -0.09], %) |> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -0.38], %) |> tangentialArcTo([24.95, -0.38], %)
|> close(%) |> close(%)
|> extrude(5, %)` |> extrude(5, %)`
) )
}) })
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await expect( await expect(
page.getByRole('button', { name: 'Start Sketch' }) page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled() ).not.toBeDisabled()
await page.waitForTimeout(100) await page.waitForTimeout(100)
await u.openAndClearDebugPanel() await u.openAndClearDebugPanel()
await u.sendCustomCmd({ await u.sendCustomCmd({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { cmd: {
type: 'default_camera_look_at', type: 'default_camera_look_at',
vantage: { x: 0, y: -1250, z: 580 }, vantage: { x: 0, y: -1250, z: 580 },
center: { x: 0, y: 0, z: 0 }, center: { x: 0, y: 0, z: 0 },
up: { x: 0, y: 0, z: 1 }, up: { x: 0, y: 0, z: 1 },
}, },
}) })
await page.waitForTimeout(100) await page.waitForTimeout(100)
await u.sendCustomCmd({ await u.sendCustomCmd({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { cmd: {
type: 'default_camera_get_settings', type: 'default_camera_get_settings',
}, },
}) })
await page.waitForTimeout(100) await page.waitForTimeout(100)
const startPX = [1200 / 2, 500 / 2] const startPX = [1200 / 2, 500 / 2]
const dragPX = 40 const dragPX = 40
await page.getByText('startProfileAt([4.61, -10.01], %)').click() await page.getByText('startProfileAt([4.61, -10.01], %)').click()
await expect( await expect(
page.getByRole('button', { name: 'Edit Sketch' }) page.getByRole('button', { name: 'Edit Sketch' })
).toBeVisible() ).toBeVisible()
await page.getByRole('button', { name: 'Edit Sketch' }).click() await page.getByRole('button', { name: 'Edit Sketch' }).click()
await page.waitForTimeout(400) await page.waitForTimeout(400)
let prevContent = await page.locator('.cm-content').innerText() let prevContent = await page.locator('.cm-content').innerText()
await expect(page.getByTestId('segment-overlay')).toHaveCount(2) await expect(page.getByTestId('segment-overlay')).toHaveCount(2)
// drag startProfileAt handle // drag startProfileAt handle
await page.dragAndDrop('#stream', '#stream', { await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: startPX[0] + 68, y: startPX[1] + 147 }, sourcePosition: { x: startPX[0] + 68, y: startPX[1] + 147 },
targetPosition: { x: startPX[0] + dragPX, y: startPX[1] + dragPX }, targetPosition: { x: startPX[0] + dragPX, y: startPX[1] + dragPX },
}) })
await page.waitForTimeout(100) await page.waitForTimeout(100)
await expect(page.locator('.cm-content')).not.toHaveText(prevContent) await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
prevContent = await page.locator('.cm-content').innerText() prevContent = await page.locator('.cm-content').innerText()
// drag line handle // drag line handle
// we wait so it saves the code // we wait so it saves the code
await page.waitForTimeout(800) await page.waitForTimeout(800)
const lineEnd = await u.getBoundingBox('[data-overlay-index="0"]') const lineEnd = await u.getBoundingBox('[data-overlay-index="0"]')
await page.waitForTimeout(100) await page.waitForTimeout(100)
await page.dragAndDrop('#stream', '#stream', { await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: lineEnd.x - 5, y: lineEnd.y }, sourcePosition: { x: lineEnd.x - 5, y: lineEnd.y },
targetPosition: { x: lineEnd.x + dragPX, y: lineEnd.y + dragPX }, targetPosition: { x: lineEnd.x + dragPX, y: lineEnd.y + dragPX },
}) })
await expect(page.locator('.cm-content')).not.toHaveText(prevContent) await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
prevContent = await page.locator('.cm-content').innerText() prevContent = await page.locator('.cm-content').innerText()
// we wait so it saves the code // we wait so it saves the code
await page.waitForTimeout(800) await page.waitForTimeout(800)
// drag tangentialArcTo handle // drag tangentialArcTo handle
const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]') const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]')
await page.dragAndDrop('#stream', '#stream', { await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: tangentEnd.x + 10, y: tangentEnd.y - 5 }, sourcePosition: { x: tangentEnd.x + 10, y: tangentEnd.y - 5 },
targetPosition: { targetPosition: {
x: tangentEnd.x + dragPX, x: tangentEnd.x + dragPX,
y: tangentEnd.y + dragPX, y: tangentEnd.y + dragPX,
}, },
}) })
await page.waitForTimeout(100) await page.waitForTimeout(100)
await expect(page.locator('.cm-content')).not.toHaveText(prevContent) await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
// expect the code to have changed // expect the code to have changed
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn('XZ') .toHaveText(`sketch001 = startSketchOn('XZ')
|> startProfileAt([2.71, -2.71], %) |> startProfileAt([2.71, -2.71], %)
|> line([15.4, -2.78], %) |> line([15.4, -2.78], %)
|> tangentialArcTo([27.6, -3.05], %) |> tangentialArcTo([27.6, -3.05], %)
@ -1073,26 +1073,26 @@ test.describe('Editor tests', () => {
|> extrude(5, %) |> extrude(5, %)
`) `)
// Hit undo // Hit undo
await page.keyboard.down('Control') await page.keyboard.down('Control')
await page.keyboard.press('KeyZ') await page.keyboard.press('KeyZ')
await page.keyboard.up('Control') await page.keyboard.up('Control')
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn('XZ') .toHaveText(`sketch001 = startSketchOn('XZ')
|> startProfileAt([2.71, -2.71], %) |> startProfileAt([2.71, -2.71], %)
|> line([15.4, -2.78], %) |> line([15.4, -2.78], %)
|> tangentialArcTo([24.95, -0.38], %) |> tangentialArcTo([24.95, -0.38], %)
|> close(%) |> close(%)
|> extrude(5, %)`) |> extrude(5, %)`)
// Hit undo again. // Hit undo again.
await page.keyboard.down('Control') await page.keyboard.down('Control')
await page.keyboard.press('KeyZ') await page.keyboard.press('KeyZ')
await page.keyboard.up('Control') await page.keyboard.up('Control')
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn('XZ') .toHaveText(`sketch001 = startSketchOn('XZ')
|> startProfileAt([2.71, -2.71], %) |> startProfileAt([2.71, -2.71], %)
|> line([12.73, -0.09], %) |> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -0.38], %) |> tangentialArcTo([24.95, -0.38], %)
@ -1100,20 +1100,21 @@ test.describe('Editor tests', () => {
|> extrude(5, %) |> extrude(5, %)
`) `)
// Hit undo again. // Hit undo again.
await page.keyboard.down('Control') await page.keyboard.down('Control')
await page.keyboard.press('KeyZ') await page.keyboard.press('KeyZ')
await page.keyboard.up('Control') await page.keyboard.up('Control')
await page.waitForTimeout(100) await page.waitForTimeout(100)
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn('XZ') .toHaveText(`sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -10.01], %) |> startProfileAt([4.61, -10.01], %)
|> line([12.73, -0.09], %) |> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -0.38], %) |> tangentialArcTo([24.95, -0.38], %)
|> close(%) |> close(%)
|> extrude(5, %)`) |> extrude(5, %)`)
}) }
)
test.fixme( test.fixme(
`Can use the import stdlib function on a local OBJ file`, `Can use the import stdlib function on a local OBJ file`,

View File

@ -19,7 +19,7 @@ test.describe('integrations tests', () => {
) )
}) })
const [clickObj] = await scene.makeMouseHelpers(600, 300) const [clickObj] = await scene.makeMouseHelpers(726, 272)
await test.step('setup test', async () => { await test.step('setup test', async () => {
await homePage.expectState({ await homePage.expectState({
@ -61,6 +61,7 @@ test.describe('integrations tests', () => {
}) })
await test.step('setup for next assertion', async () => { await test.step('setup for next assertion', async () => {
await toolbar.openFile('main.kcl') await toolbar.openFile('main.kcl')
await scene.waitForExecutionDone()
await clickObj() await clickObj()
await scene.moveNoWhere() await scene.moveNoWhere()
await editor.expectState({ await editor.expectState({

View File

@ -89,18 +89,11 @@ export class HomePageFixture {
* Maybe there a good sanity check we can do each time? * Maybe there a good sanity check we can do each time?
*/ */
expectState = async (expectedState: HomePageState) => { expectState = async (expectedState: HomePageState) => {
await expect await expect.poll(this._serialiseSortBy).toEqual(expectedState.sortBy)
.poll(async () => {
const [projectCards, sortBy] = await Promise.all([ for (const projectCard of expectedState.projectCards) {
this._serialiseProjectCards(), await expect.poll(this._serialiseProjectCards).toContainEqual(projectCard)
this._serialiseSortBy(), }
])
return {
projectCards,
sortBy,
}
})
.toEqual(expectedState)
} }
createAndGoToProject = async (projectTitle = 'project-$nnn') => { createAndGoToProject = async (projectTitle = 'project-$nnn') => {

View File

@ -62,7 +62,9 @@ export class ToolbarFixture {
this.filePane = page.locator('#files-pane') this.filePane = page.locator('#files-pane')
this.featureTreePane = page.locator('#feature-tree-pane') this.featureTreePane = page.locator('#feature-tree-pane')
this.fileCreateToast = page.getByText('Successfully created') this.fileCreateToast = page.getByText('Successfully created')
this.exeIndicator = page.getByTestId('model-state-indicator-execution-done') this.exeIndicator = page.getByTestId(
'model-state-indicator-receive-reliable'
)
} }
get logoLink() { get logoLink() {

View File

@ -2273,10 +2273,6 @@ radius = 8.69
const lineCodeToSelection = `|> angledLine([0, 202.6], %, $rectangleSegmentA001)` const lineCodeToSelection = `|> angledLine([0, 202.6], %, $rectangleSegmentA001)`
await page.getByText(lineCodeToSelection).click() await page.getByText(lineCodeToSelection).click()
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
const newCodeToFind = `revolve001 = revolve({angle = 360, axis = getOppositeEdge(rectangleSegmentA001)}, sketch002) ` const newCodeToFind = `revolve001 = revolve({angle = 360, axis = getOppositeEdge(rectangleSegmentA001)}, sketch002) `
expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy() expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy()
@ -2328,10 +2324,6 @@ radius = 8.69
const lineCodeToSelection = `|> xLine(2.6, %)` const lineCodeToSelection = `|> xLine(2.6, %)`
await page.getByText(lineCodeToSelection).click() await page.getByText(lineCodeToSelection).click()
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
const newCodeToFind = `revolve001 = revolve({ angle = 360, axis = seg01 }, sketch003)` const newCodeToFind = `revolve001 = revolve({ angle = 360, axis = seg01 }, sketch003)`
expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy() expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy()

View File

@ -1527,34 +1527,32 @@ test(
{ tag: '@electron' }, { tag: '@electron' },
async ({ context, page, cmdBar, homePage }, testInfo) => { async ({ context, page, cmdBar, homePage }, testInfo) => {
await context.folderSetupFn(async (dir) => { await context.folderSetupFn(async (dir) => {
await Promise.all([ await fsp.mkdir(path.join(dir, 'router-template-slate'), {
fsp.mkdir(path.join(dir, 'router-template-slate'), { recursive: true }), recursive: true,
fsp.mkdir(path.join(dir, 'bracket'), { recursive: true }), })
]) await fsp.copyFile(
await Promise.all([ path.join(
fsp.copyFile( 'src',
path.join( 'wasm-lib',
'src', 'tests',
'wasm-lib', 'executor',
'tests', 'inputs',
'executor', 'router-template-slate.kcl'
'inputs',
'router-template-slate.kcl'
),
path.join(dir, 'router-template-slate', 'main.kcl')
), ),
fsp.copyFile( path.join(dir, 'router-template-slate', 'main.kcl')
path.join( )
'src', await fsp.mkdir(path.join(dir, 'bracket'), { recursive: true })
'wasm-lib', await fsp.copyFile(
'tests', path.join(
'executor', 'src',
'inputs', 'wasm-lib',
'focusrite_scarlett_mounting_braket.kcl' 'tests',
), 'executor',
path.join(dir, 'bracket', 'main.kcl') 'inputs',
'focusrite_scarlett_mounting_braket.kcl'
), ),
]) path.join(dir, 'bracket', 'main.kcl')
)
}) })
const u = await getUtils(page) const u = await getUtils(page)
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })

View File

@ -312,32 +312,40 @@ test.describe('Sketch tests', () => {
|> line([1.97, 2.06], %) |> line([1.97, 2.06], %)
|> close(%)`) |> close(%)`)
} }
test('code pane open at start-handles', async ({ page, homePage }) => { test(
// Load the app with the code panes 'code pane open at start-handles',
await page.addInitScript(async () => { { tag: ['@skipWin'] },
localStorage.setItem( async ({ page, homePage }) => {
'store', // Load the app with the code panes
JSON.stringify({ await page.addInitScript(async () => {
state: { localStorage.setItem(
openPanes: ['code'], 'store',
}, JSON.stringify({
version: 0, state: {
}) openPanes: ['code'],
) },
}) version: 0,
await doEditSegmentsByDraggingHandle(page, homePage, ['code']) })
}) )
})
await doEditSegmentsByDraggingHandle(page, homePage, ['code'])
}
)
test('code pane closed at start-handles', async ({ page, homePage }) => { test(
// Load the app with the code panes 'code pane closed at start-handles',
await page.addInitScript(async (persistModelingContext) => { { tag: ['@skipWin'] },
localStorage.setItem( async ({ page, homePage }) => {
persistModelingContext, // Load the app with the code panes
JSON.stringify({ openPanes: [] }) await page.addInitScript(async (persistModelingContext) => {
) localStorage.setItem(
}, PERSIST_MODELING_CONTEXT) persistModelingContext,
await doEditSegmentsByDraggingHandle(page, homePage, []) JSON.stringify({ openPanes: [] })
}) )
}, PERSIST_MODELING_CONTEXT)
await doEditSegmentsByDraggingHandle(page, homePage, [])
}
)
}) })
test('Can edit a circle center and radius by dragging its handles', async ({ test('Can edit a circle center and radius by dragging its handles', async ({

View File

@ -209,5 +209,6 @@
"wasm-pack": "^0.13.1", "wasm-pack": "^0.13.1",
"ws": "^8.17.0", "ws": "^8.17.0",
"yarn": "^1.22.22" "yarn": "^1.22.22"
} },
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
} }

View File

@ -248,6 +248,8 @@ class EngineConnection extends EventTarget {
mediaStream?: MediaStream mediaStream?: MediaStream
idleMode: boolean = false idleMode: boolean = false
promise?: Promise<void> promise?: Promise<void>
sdpAnswer?: Models['RtcSessionDescription_type']
triggeredStart = false
onIceCandidate = function ( onIceCandidate = function (
this: RTCPeerConnection, this: RTCPeerConnection,
@ -553,6 +555,7 @@ class EngineConnection extends EventTarget {
* did not establish. * did not establish.
*/ */
connect(reconnecting?: boolean): Promise<void> { connect(reconnecting?: boolean): Promise<void> {
const that = this
return new Promise((resolve) => { return new Promise((resolve) => {
if (this.isConnecting() || this.isReady()) { if (this.isConnecting() || this.isReady()) {
return return
@ -583,8 +586,38 @@ class EngineConnection extends EventTarget {
}, },
} }
const initiateConnectingExclusive = () => {
if (that.triggeredStart) return
that.triggeredStart = true
// Start connecting.
that.state = {
type: EngineConnectionStateType.Connecting,
value: {
type: ConnectingType.WebRTCConnecting,
},
}
// As soon as this is set, RTCPeerConnection tries to
// establish a connection.
// @ts-expect-error: Have to ignore because dom.ts doesn't have the right type
void that.pc?.setRemoteDescription(that.sdpAnswer)
that.state = {
type: EngineConnectionStateType.Connecting,
value: {
type: ConnectingType.SetRemoteDescription,
},
}
}
this.onIceCandidate = (event: RTCPeerConnectionIceEvent) => { this.onIceCandidate = (event: RTCPeerConnectionIceEvent) => {
console.log('icecandidate', event.candidate)
// This is null when the ICE gathering state is done.
// Windows ONLY uses this to signal it's done!
if (event.candidate === null) { if (event.candidate === null) {
initiateConnectingExclusive()
return return
} }
@ -595,7 +628,6 @@ class EngineConnection extends EventTarget {
}, },
} }
// Request a candidate to use
this.send({ this.send({
type: 'trickle_ice', type: 'trickle_ice',
candidate: { candidate: {
@ -605,8 +637,38 @@ class EngineConnection extends EventTarget {
usernameFragment: event.candidate.usernameFragment || undefined, usernameFragment: event.candidate.usernameFragment || undefined,
}, },
}) })
// Sometimes the remote end doesn't report the end of candidates.
// They have 3 seconds to.
setTimeout(() => {
initiateConnectingExclusive()
}, 3000)
} }
this.pc?.addEventListener?.('icecandidate', this.onIceCandidate) this.pc?.addEventListener?.('icecandidate', this.onIceCandidate)
this.pc?.addEventListener?.(
'icegatheringstatechange',
function (_event) {
console.log('icegatheringstatechange', this.iceGatheringState)
if (this.iceGatheringState !== 'complete') return
initiateConnectingExclusive()
}
)
this.pc?.addEventListener?.(
'iceconnectionstatechange',
function (_event) {
console.log('iceconnectionstatechange', this.iceConnectionState)
console.log('iceconnectionstatechange', this.iceGatheringState)
}
)
this.pc?.addEventListener?.('negotiationneeded', function (_event) {
console.log('negotiationneeded', this.iceConnectionState)
console.log('negotiationneeded', this.iceGatheringState)
})
this.pc?.addEventListener?.('signalingstatechange', function (event) {
console.log('signalingstatechange', this.signalingState)
})
this.onIceCandidateError = (_event: Event) => { this.onIceCandidateError = (_event: Event) => {
const event = _event as RTCPeerConnectionIceErrorEvent const event = _event as RTCPeerConnectionIceErrorEvent
@ -634,6 +696,8 @@ class EngineConnection extends EventTarget {
}) })
) )
break break
case 'connecting':
break
case 'disconnected': case 'disconnected':
case 'failed': case 'failed':
this.pc?.removeEventListener('icecandidate', this.onIceCandidate) this.pc?.removeEventListener('icecandidate', this.onIceCandidate)
@ -1126,25 +1190,8 @@ class EngineConnection extends EventTarget {
}, },
} }
// As soon as this is set, RTCPeerConnection tries to this.sdpAnswer = answer
// establish a connection.
// @ts-ignore
// Have to ignore because dom.ts doesn't have the right type
void this.pc?.setRemoteDescription(answer)
this.state = {
type: EngineConnectionStateType.Connecting,
value: {
type: ConnectingType.SetRemoteDescription,
},
}
this.state = {
type: EngineConnectionStateType.Connecting,
value: {
type: ConnectingType.WebRTCConnecting,
},
}
break break
case 'trickle_ice': case 'trickle_ice':
@ -1235,6 +1282,7 @@ class EngineConnection extends EventTarget {
if (closedPc && closedUDC && closedWS) { if (closedPc && closedUDC && closedWS) {
// Do not notify the rest of the program that we have cut off anything. // Do not notify the rest of the program that we have cut off anything.
this.state = { type: EngineConnectionStateType.Disconnected } this.state = { type: EngineConnectionStateType.Disconnected }
this.triggeredStart = false
} }
} }
} }