From fe557a4af4cd3b15e9fbd4ba3028f45b82e50289 Mon Sep 17 00:00:00 2001 From: kwasniow Date: Fri, 7 Jun 2024 17:19:22 +0200 Subject: [PATCH 1/4] feat: spark-532493 expose separate events for connection state and ice connection state --- src/connection-state-handler.spec.ts | 26 ++++++--- src/connection-state-handler.ts | 87 ++++++++++++++++++++-------- src/peer-connection.ts | 40 ++++++++++++- 3 files changed, 117 insertions(+), 36 deletions(-) diff --git a/src/connection-state-handler.spec.ts b/src/connection-state-handler.spec.ts index b33d290..4481c76 100644 --- a/src/connection-state-handler.spec.ts +++ b/src/connection-state-handler.spec.ts @@ -1,4 +1,8 @@ -import { ConnectionState, ConnectionStateHandler } from './connection-state-handler'; +import { + ConnectionState, + ConnectionStateHandler, + IceConnectionState, +} from './connection-state-handler'; describe('ConnectionStateHandler', () => { let fakeIceState: RTCIceConnectionState; @@ -24,18 +28,25 @@ describe('ConnectionStateHandler', () => { expect(connStateHandler.getConnectionState()).toStrictEqual(ConnectionState.New); }); - it('updates connection state on ice connection state change and emits the event', () => { + it('reads initial ice connection state', () => { + expect.assertions(1); + const connStateHandler = new ConnectionStateHandler(fakeCallback); + + expect(connStateHandler.getIceConnectionState()).toStrictEqual(IceConnectionState.New); + }); + + it('updates ice connection state on ice connection state change and emits the event', () => { expect.assertions(2); const connStateHandler = new ConnectionStateHandler(fakeCallback); - connStateHandler.on(ConnectionStateHandler.Events.ConnectionStateChanged, (state) => { - expect(state).toStrictEqual(ConnectionState.Connecting); + connStateHandler.on(ConnectionStateHandler.Events.IceConnectionStateChanged, (state) => { + expect(state).toStrictEqual(IceConnectionState.Checking); }); fakeIceState = 'checking'; connStateHandler.onIceConnectionStateChange(); - expect(connStateHandler.getConnectionState()).toStrictEqual(ConnectionState.Connecting); + expect(connStateHandler.getIceConnectionState()).toStrictEqual(IceConnectionState.Checking); }); it("updates connection state on RTCPeerConnection's connection state change", () => { @@ -118,10 +129,7 @@ describe('ConnectionStateHandler', () => { fakeConnectionState = connState; fakeIceState = iceState; - // it's sufficient to trigger just one of the callbacks - connStateHandler.onConnectionStateChange(); - - expect(connStateHandler.getConnectionState()).toStrictEqual(expected); + expect(connStateHandler.getOverallConnectionState()).toStrictEqual(expected); }) ); }); diff --git a/src/connection-state-handler.ts b/src/connection-state-handler.ts index 8a5a974..7f297ac 100644 --- a/src/connection-state-handler.ts +++ b/src/connection-state-handler.ts @@ -1,7 +1,15 @@ import { EventEmitter, EventMap } from './event-emitter'; import { logger } from './util/logger'; -// Overall connection state (based on the ICE and DTLS connection states) +export enum OverallConnectionState { + New = 'New', + Connecting = 'Connecting', + Connected = 'Connected', + Disconnected = 'Disconnected', + Failed = 'Failed', + Closed = 'Closed', +} + export enum ConnectionState { New = 'New', // connection attempt has not been started Closed = 'Closed', // connection closed, there is no way to move out of this state @@ -11,12 +19,24 @@ export enum ConnectionState { Failed = 'Failed', // connection failed, an ICE restart is required } +export enum IceConnectionState { + New = 'New', + Checking = 'Checking', + Connected = 'Connected', + Completed = 'Completed', + Failed = 'Failed', + Disconnected = 'Disconnected', + Closed = 'Closed', +} + enum ConnectionStateEvents { ConnectionStateChanged = 'ConnectionStateChanged', + IceConnectionStateChanged = 'IceConnectionStateChanged', } interface ConnectionStateEventHandlers extends EventMap { [ConnectionStateEvents.ConnectionStateChanged]: (state: ConnectionState) => void; + [ConnectionStateEvents.IceConnectionStateChanged]: (state: IceConnectionState) => void; } type GetCurrentStatesCallback = () => { @@ -31,8 +51,6 @@ type GetCurrentStatesCallback = () => { export class ConnectionStateHandler extends EventEmitter { static Events = ConnectionStateEvents; - private mediaConnectionState: ConnectionState; - private getCurrentStatesCallback: GetCurrentStatesCallback; /** @@ -44,33 +62,26 @@ export class ConnectionStateHandler extends EventEmitter value === 'new')) { - mediaConnectionState = ConnectionState.New; + mediaConnectionState = OverallConnectionState.New; } else if (connectionStates.some((value) => value === 'closed')) { - mediaConnectionState = ConnectionState.Closed; + mediaConnectionState = OverallConnectionState.Closed; } else if (connectionStates.some((value) => value === 'failed')) { - mediaConnectionState = ConnectionState.Failed; + mediaConnectionState = OverallConnectionState.Failed; } else if (connectionStates.some((value) => value === 'disconnected')) { - mediaConnectionState = ConnectionState.Disconnected; + mediaConnectionState = OverallConnectionState.Disconnected; } else if (connectionStates.every((value) => value === 'connected' || value === 'completed')) { - mediaConnectionState = ConnectionState.Connected; + mediaConnectionState = OverallConnectionState.Connected; } else { - mediaConnectionState = ConnectionState.Connecting; + mediaConnectionState = OverallConnectionState.Connecting; } logger.log( @@ -113,6 +124,32 @@ export class ConnectionStateHandler extends EventEmitter void; [PeerConnectionEvents.IceCandidate]: (ev: RTCPeerConnectionIceEvent) => void; [PeerConnectionEvents.ConnectionStateChange]: (state: ConnectionState) => void; + [PeerConnectionEvents.IceConnectionStateChange]: (state: IceConnectionState) => void; [PeerConnectionEvents.CreateOfferOnSuccess]: (offer: RTCSessionDescriptionInit) => void; [PeerConnectionEvents.CreateAnswerOnSuccess]: (answer: RTCSessionDescriptionInit) => void; [PeerConnectionEvents.SetLocalDescriptionOnSuccess]: ( @@ -85,6 +92,13 @@ class PeerConnection extends EventEmitter { } ); + this.connectionStateHandler.on( + ConnectionStateHandler.Events.IceConnectionStateChanged, + (state: IceConnectionState) => { + this.emit(PeerConnection.Events.IceConnectionStateChange, state); + } + ); + // Forward the connection state related events to connection state handler // eslint-disable-next-line jsdoc/require-jsdoc this.pc.oniceconnectionstatechange = () => @@ -118,10 +132,28 @@ class PeerConnection extends EventEmitter { * * @returns The underlying connection's overall state. */ + getOverallConnectionState(): OverallConnectionState { + return this.connectionStateHandler.getOverallConnectionState(); + } + + /** + * Gets the connection state of the underlying RTCPeerConnection. + * + * @returns The underlying RTCPeerConnection connection state. + */ getConnectionState(): ConnectionState { return this.connectionStateHandler.getConnectionState(); } + /** + * Gets the ICE connection state of the underlying RTCPeerConnection. + * + * @returns The underlying RTCPeerConnection ICE connection state. + */ + getIceConnectionState(): IceConnectionState { + return this.connectionStateHandler.getIceConnectionState(); + } + /** * Adds a new media track to the set of tracks which will be transmitted to the other peer. * @@ -374,5 +406,9 @@ class PeerConnection extends EventEmitter { } } -export { ConnectionState } from './connection-state-handler'; +export { + ConnectionState, + IceConnectionState, + OverallConnectionState, +} from './connection-state-handler'; export { MediaStreamTrackKind, PeerConnection, RTCDataChannelOptions }; From 73556f1149dc83cfd7f7d7df4c59f54748bdcb2a Mon Sep 17 00:00:00 2001 From: kwasniow Date: Fri, 7 Jun 2024 17:19:22 +0200 Subject: [PATCH 2/4] feat: spark-532493 expose separate events for connection state and ice connection state --- src/connection-state-handler.spec.ts | 26 ++++++--- src/connection-state-handler.ts | 87 ++++++++++++++++++++-------- src/peer-connection.spec.ts | 23 +++++++- src/peer-connection.ts | 40 ++++++++++++- 4 files changed, 139 insertions(+), 37 deletions(-) diff --git a/src/connection-state-handler.spec.ts b/src/connection-state-handler.spec.ts index b33d290..4481c76 100644 --- a/src/connection-state-handler.spec.ts +++ b/src/connection-state-handler.spec.ts @@ -1,4 +1,8 @@ -import { ConnectionState, ConnectionStateHandler } from './connection-state-handler'; +import { + ConnectionState, + ConnectionStateHandler, + IceConnectionState, +} from './connection-state-handler'; describe('ConnectionStateHandler', () => { let fakeIceState: RTCIceConnectionState; @@ -24,18 +28,25 @@ describe('ConnectionStateHandler', () => { expect(connStateHandler.getConnectionState()).toStrictEqual(ConnectionState.New); }); - it('updates connection state on ice connection state change and emits the event', () => { + it('reads initial ice connection state', () => { + expect.assertions(1); + const connStateHandler = new ConnectionStateHandler(fakeCallback); + + expect(connStateHandler.getIceConnectionState()).toStrictEqual(IceConnectionState.New); + }); + + it('updates ice connection state on ice connection state change and emits the event', () => { expect.assertions(2); const connStateHandler = new ConnectionStateHandler(fakeCallback); - connStateHandler.on(ConnectionStateHandler.Events.ConnectionStateChanged, (state) => { - expect(state).toStrictEqual(ConnectionState.Connecting); + connStateHandler.on(ConnectionStateHandler.Events.IceConnectionStateChanged, (state) => { + expect(state).toStrictEqual(IceConnectionState.Checking); }); fakeIceState = 'checking'; connStateHandler.onIceConnectionStateChange(); - expect(connStateHandler.getConnectionState()).toStrictEqual(ConnectionState.Connecting); + expect(connStateHandler.getIceConnectionState()).toStrictEqual(IceConnectionState.Checking); }); it("updates connection state on RTCPeerConnection's connection state change", () => { @@ -118,10 +129,7 @@ describe('ConnectionStateHandler', () => { fakeConnectionState = connState; fakeIceState = iceState; - // it's sufficient to trigger just one of the callbacks - connStateHandler.onConnectionStateChange(); - - expect(connStateHandler.getConnectionState()).toStrictEqual(expected); + expect(connStateHandler.getOverallConnectionState()).toStrictEqual(expected); }) ); }); diff --git a/src/connection-state-handler.ts b/src/connection-state-handler.ts index 8a5a974..7f297ac 100644 --- a/src/connection-state-handler.ts +++ b/src/connection-state-handler.ts @@ -1,7 +1,15 @@ import { EventEmitter, EventMap } from './event-emitter'; import { logger } from './util/logger'; -// Overall connection state (based on the ICE and DTLS connection states) +export enum OverallConnectionState { + New = 'New', + Connecting = 'Connecting', + Connected = 'Connected', + Disconnected = 'Disconnected', + Failed = 'Failed', + Closed = 'Closed', +} + export enum ConnectionState { New = 'New', // connection attempt has not been started Closed = 'Closed', // connection closed, there is no way to move out of this state @@ -11,12 +19,24 @@ export enum ConnectionState { Failed = 'Failed', // connection failed, an ICE restart is required } +export enum IceConnectionState { + New = 'New', + Checking = 'Checking', + Connected = 'Connected', + Completed = 'Completed', + Failed = 'Failed', + Disconnected = 'Disconnected', + Closed = 'Closed', +} + enum ConnectionStateEvents { ConnectionStateChanged = 'ConnectionStateChanged', + IceConnectionStateChanged = 'IceConnectionStateChanged', } interface ConnectionStateEventHandlers extends EventMap { [ConnectionStateEvents.ConnectionStateChanged]: (state: ConnectionState) => void; + [ConnectionStateEvents.IceConnectionStateChanged]: (state: IceConnectionState) => void; } type GetCurrentStatesCallback = () => { @@ -31,8 +51,6 @@ type GetCurrentStatesCallback = () => { export class ConnectionStateHandler extends EventEmitter { static Events = ConnectionStateEvents; - private mediaConnectionState: ConnectionState; - private getCurrentStatesCallback: GetCurrentStatesCallback; /** @@ -44,33 +62,26 @@ export class ConnectionStateHandler extends EventEmitter value === 'new')) { - mediaConnectionState = ConnectionState.New; + mediaConnectionState = OverallConnectionState.New; } else if (connectionStates.some((value) => value === 'closed')) { - mediaConnectionState = ConnectionState.Closed; + mediaConnectionState = OverallConnectionState.Closed; } else if (connectionStates.some((value) => value === 'failed')) { - mediaConnectionState = ConnectionState.Failed; + mediaConnectionState = OverallConnectionState.Failed; } else if (connectionStates.some((value) => value === 'disconnected')) { - mediaConnectionState = ConnectionState.Disconnected; + mediaConnectionState = OverallConnectionState.Disconnected; } else if (connectionStates.every((value) => value === 'connected' || value === 'completed')) { - mediaConnectionState = ConnectionState.Connected; + mediaConnectionState = OverallConnectionState.Connected; } else { - mediaConnectionState = ConnectionState.Connecting; + mediaConnectionState = OverallConnectionState.Connecting; } logger.log( @@ -113,6 +124,32 @@ export class ConnectionStateHandler extends EventEmitter { const connectionStateHandlerListener = connectionStateHandler.on.mock.calls[0][1]; connectionStateHandlerListener(ConnectionState.Connecting); }); + it("listens on ConnectionStateHandler's IceConnectionStateChange event and emits it", () => { + expect.assertions(2); + const connectionStateHandler = getInstantiatedConnectionStateHandler(); + + pc.on(PeerConnection.Events.IceConnectionStateChange, (state) => { + expect(state).toStrictEqual(IceConnectionState.Checking); + }); + + // verify that PeerConnection listens for the right event + expect(connectionStateHandler.on.mock.calls[0][0]).toStrictEqual( + ConnectionStateHandler.Events.IceConnectionStateChanged + ); + + // trigger the fake event from ConnectionStateHandler + const connectionStateHandlerListener = connectionStateHandler.on.mock.calls[0][1]; + connectionStateHandlerListener(IceConnectionState.Checking); + }); }); describe('createAnswer', () => { let mockPc: MockedObjectDeep; diff --git a/src/peer-connection.ts b/src/peer-connection.ts index 7018b49..598077c 100644 --- a/src/peer-connection.ts +++ b/src/peer-connection.ts @@ -1,5 +1,10 @@ import { BrowserInfo } from '@webex/web-capabilities'; -import { ConnectionState, ConnectionStateHandler } from './connection-state-handler'; +import { + ConnectionState, + ConnectionStateHandler, + IceConnectionState, + OverallConnectionState, +} from './connection-state-handler'; import { EventEmitter, EventMap } from './event-emitter'; import { createRTCPeerConnection } from './rtc-peer-connection-factory'; import { logger } from './util/logger'; @@ -29,6 +34,7 @@ enum PeerConnectionEvents { IceGatheringStateChange = 'icegatheringstatechange', IceCandidate = 'icecandidate', ConnectionStateChange = 'connectionstatechange', + IceConnectionStateChange = 'iceconnectionstatechange', CreateOfferOnSuccess = 'createofferonsuccess', CreateAnswerOnSuccess = 'createansweronsuccess', SetLocalDescriptionOnSuccess = 'setlocaldescriptiononsuccess', @@ -39,6 +45,7 @@ interface PeerConnectionEventHandlers extends EventMap { [PeerConnectionEvents.IceGatheringStateChange]: (ev: IceGatheringStateChangeEvent) => void; [PeerConnectionEvents.IceCandidate]: (ev: RTCPeerConnectionIceEvent) => void; [PeerConnectionEvents.ConnectionStateChange]: (state: ConnectionState) => void; + [PeerConnectionEvents.IceConnectionStateChange]: (state: IceConnectionState) => void; [PeerConnectionEvents.CreateOfferOnSuccess]: (offer: RTCSessionDescriptionInit) => void; [PeerConnectionEvents.CreateAnswerOnSuccess]: (answer: RTCSessionDescriptionInit) => void; [PeerConnectionEvents.SetLocalDescriptionOnSuccess]: ( @@ -85,6 +92,13 @@ class PeerConnection extends EventEmitter { } ); + this.connectionStateHandler.on( + ConnectionStateHandler.Events.IceConnectionStateChanged, + (state: IceConnectionState) => { + this.emit(PeerConnection.Events.IceConnectionStateChange, state); + } + ); + // Forward the connection state related events to connection state handler // eslint-disable-next-line jsdoc/require-jsdoc this.pc.oniceconnectionstatechange = () => @@ -118,10 +132,28 @@ class PeerConnection extends EventEmitter { * * @returns The underlying connection's overall state. */ + getOverallConnectionState(): OverallConnectionState { + return this.connectionStateHandler.getOverallConnectionState(); + } + + /** + * Gets the connection state of the underlying RTCPeerConnection. + * + * @returns The underlying RTCPeerConnection connection state. + */ getConnectionState(): ConnectionState { return this.connectionStateHandler.getConnectionState(); } + /** + * Gets the ICE connection state of the underlying RTCPeerConnection. + * + * @returns The underlying RTCPeerConnection ICE connection state. + */ + getIceConnectionState(): IceConnectionState { + return this.connectionStateHandler.getIceConnectionState(); + } + /** * Adds a new media track to the set of tracks which will be transmitted to the other peer. * @@ -374,5 +406,9 @@ class PeerConnection extends EventEmitter { } } -export { ConnectionState } from './connection-state-handler'; +export { + ConnectionState, + IceConnectionState, + OverallConnectionState, +} from './connection-state-handler'; export { MediaStreamTrackKind, PeerConnection, RTCDataChannelOptions }; From 3513785eecd2c9d8d94133bc0bb7e3b6fc01c176 Mon Sep 17 00:00:00 2001 From: kwasniow Date: Mon, 10 Jun 2024 18:03:22 +0200 Subject: [PATCH 3/4] feat: use native webrtc states --- cspell.json | 11 +++-- src/connection-state-handler.spec.ts | 69 ++++++++-------------------- src/connection-state-handler.ts | 62 ++++++++----------------- src/peer-connection.spec.ts | 26 +++++------ src/peer-connection.ts | 40 +++++++--------- 5 files changed, 71 insertions(+), 137 deletions(-) diff --git a/cspell.json b/cspell.json index 5cc19e0..cc4eac8 100644 --- a/cspell.json +++ b/cspell.json @@ -12,6 +12,8 @@ "codecov", "commitlint", "cpaas", + "createansweronsuccess", + "createofferonsuccess", "dbaeumer", "dependabot", "eamodio", @@ -25,22 +27,21 @@ "libauth", "mkdir", "negotiatedneeded", + "peerconnectionstatechange", "preprocessors", "prettierignore", "rohit", "sandboxed", "saucelabs", + "setlocaldescriptiononsuccess", + "setremotedescriptiononsuccess", "transpiled", "typedoc", "untracked", "Wcme", "WCME", "webex", - "webrtc", - "createofferonsuccess", - "createansweronsuccess", - "setlocaldescriptiononsuccess", - "setremotedescriptiononsuccess" + "webrtc" ], "flagWords": [], "ignorePaths": [ diff --git a/src/connection-state-handler.spec.ts b/src/connection-state-handler.spec.ts index 7806764..b05fd85 100644 --- a/src/connection-state-handler.spec.ts +++ b/src/connection-state-handler.spec.ts @@ -1,8 +1,4 @@ -import { - ConnectionState, - ConnectionStateHandler, - IceConnectionState, -} from './connection-state-handler'; +import { ConnectionState, ConnectionStateHandler } from './connection-state-handler'; describe('ConnectionStateHandler', () => { let fakeIceState: RTCIceConnectionState; @@ -21,18 +17,25 @@ describe('ConnectionStateHandler', () => { fakeConnectionState = 'new'; }); - it('reads initial connection state', () => { + it('reads initial peer connection state', () => { expect.assertions(1); const connStateHandler = new ConnectionStateHandler(fakeCallback); - expect(connStateHandler.getConnectionState()).toStrictEqual(ConnectionState.New); + expect(connStateHandler.getPeerConnectionState()).toBe('new'); }); it('reads initial ice connection state', () => { expect.assertions(1); const connStateHandler = new ConnectionStateHandler(fakeCallback); - expect(connStateHandler.getIceConnectionState()).toStrictEqual(IceConnectionState.New); + expect(connStateHandler.getIceConnectionState()).toBe('new'); + }); + + it('reads initial connection state', () => { + expect.assertions(1); + const connStateHandler = new ConnectionStateHandler(fakeCallback); + + expect(connStateHandler.getConnectionState()).toBe('New'); }); it('updates ice connection state on ice connection state change and emits the event', () => { @@ -40,63 +43,27 @@ describe('ConnectionStateHandler', () => { const connStateHandler = new ConnectionStateHandler(fakeCallback); connStateHandler.on(ConnectionStateHandler.Events.IceConnectionStateChanged, (state) => { - expect(state).toStrictEqual(IceConnectionState.Checking); + expect(state).toBe('checking'); }); fakeIceState = 'checking'; connStateHandler.onIceConnectionStateChange(); - expect(connStateHandler.getIceConnectionState()).toStrictEqual(IceConnectionState.Checking); + expect(connStateHandler.getIceConnectionState()).toBe('checking'); }); it("updates connection state on RTCPeerConnection's connection state change", () => { expect.assertions(2); const connStateHandler = new ConnectionStateHandler(fakeCallback); - connStateHandler.on(ConnectionStateHandler.Events.ConnectionStateChanged, (state) => { - expect(state).toStrictEqual(ConnectionState.Connecting); + connStateHandler.on(ConnectionStateHandler.Events.PeerConnectionStateChanged, (state) => { + expect(state).toBe('connecting'); }); fakeConnectionState = 'connecting'; - connStateHandler.onConnectionStateChange(); + connStateHandler.onPeerConnectionStateChange(); - expect(connStateHandler.getConnectionState()).toStrictEqual(ConnectionState.Connecting); - }); - - [ - { iceState: 'new', expected: IceConnectionState.New }, - { iceState: 'checking', expected: IceConnectionState.Checking }, - { iceState: 'connected', expected: IceConnectionState.Connected }, - { iceState: 'completed', expected: IceConnectionState.Completed }, - { iceState: 'failed', expected: IceConnectionState.Failed }, - { iceState: 'disconnected', expected: IceConnectionState.Disconnected }, - ].forEach(({ iceState, expected }) => { - it(`evaluates iceConnectionState to ${expected} when ice state = ${iceState}`, () => { - expect.assertions(1); - const connStateHandler = new ConnectionStateHandler(fakeCallback); - - fakeIceState = iceState as RTCIceConnectionState; - - expect(connStateHandler.getIceConnectionState()).toStrictEqual(expected); - }); - }); - - [ - { connState: 'new', expected: ConnectionState.New }, - { connState: 'connecting', expected: ConnectionState.Connecting }, - { connState: 'connected', expected: ConnectionState.Connected }, - { connState: 'disconnected', expected: ConnectionState.Disconnected }, - { connState: 'failed', expected: ConnectionState.Failed }, - { connState: 'closed', expected: ConnectionState.Closed }, - ].forEach(({ connState, expected }) => { - it(`evaluates ConnectionState to ${expected} when connection state = ${connState}`, () => { - expect.assertions(1); - const connStateHandler = new ConnectionStateHandler(fakeCallback); - - fakeConnectionState = connState as RTCPeerConnectionState; - - expect(connStateHandler.getConnectionState()).toStrictEqual(expected); - }); + expect(connStateHandler.getPeerConnectionState()).toBe('connecting'); }); // test matrix for all possible combinations of iceConnectionState and connectionState @@ -165,7 +132,7 @@ describe('ConnectionStateHandler', () => { fakeConnectionState = connState; fakeIceState = iceState; - expect(connStateHandler.getOverallConnectionState()).toStrictEqual(expected); + expect(connStateHandler.getConnectionState()).toStrictEqual(expected); }) ); }); diff --git a/src/connection-state-handler.ts b/src/connection-state-handler.ts index d8decce..64f7c8e 100644 --- a/src/connection-state-handler.ts +++ b/src/connection-state-handler.ts @@ -1,15 +1,7 @@ import { EventEmitter, EventMap } from './event-emitter'; import { logger } from './util/logger'; -export enum OverallConnectionState { - New = 'New', - Connecting = 'Connecting', - Connected = 'Connected', - Disconnected = 'Disconnected', - Failed = 'Failed', - Closed = 'Closed', -} - +// Overall connection state (based on the ICE and DTLS connection states) export enum ConnectionState { New = 'New', // connection attempt has not been started Closed = 'Closed', // connection closed, there is no way to move out of this state @@ -19,24 +11,14 @@ export enum ConnectionState { Failed = 'Failed', // connection failed, an ICE restart is required } -export enum IceConnectionState { - New = 'New', - Checking = 'Checking', - Connected = 'Connected', - Completed = 'Completed', - Failed = 'Failed', - Disconnected = 'Disconnected', - Closed = 'Closed', -} - enum ConnectionStateEvents { - ConnectionStateChanged = 'ConnectionStateChanged', + PeerConnectionStateChanged = 'PeerConnectionStateChanged', IceConnectionStateChanged = 'IceConnectionStateChanged', } interface ConnectionStateEventHandlers extends EventMap { - [ConnectionStateEvents.ConnectionStateChanged]: (state: ConnectionState) => void; - [ConnectionStateEvents.IceConnectionStateChanged]: (state: IceConnectionState) => void; + [ConnectionStateEvents.PeerConnectionStateChanged]: (state: RTCPeerConnectionState) => void; + [ConnectionStateEvents.IceConnectionStateChanged]: (state: RTCIceConnectionState) => void; } type GetCurrentStatesCallback = () => { @@ -67,10 +49,10 @@ export class ConnectionStateHandler extends EventEmitter value === 'new')) { - mediaConnectionState = OverallConnectionState.New; + mediaConnectionState = ConnectionState.New; } else if (connectionStates.some((value) => value === 'closed')) { - mediaConnectionState = OverallConnectionState.Closed; + mediaConnectionState = ConnectionState.Closed; } else if (connectionStates.some((value) => value === 'failed')) { - mediaConnectionState = OverallConnectionState.Failed; + mediaConnectionState = ConnectionState.Failed; } else if (connectionStates.some((value) => value === 'disconnected')) { - mediaConnectionState = OverallConnectionState.Disconnected; + mediaConnectionState = ConnectionState.Disconnected; } else if (connectionStates.every((value) => value === 'connected' || value === 'completed')) { - mediaConnectionState = OverallConnectionState.Connected; + mediaConnectionState = ConnectionState.Connected; } else { - mediaConnectionState = OverallConnectionState.Connecting; + mediaConnectionState = ConnectionState.Connecting; } logger.log( @@ -121,12 +103,10 @@ export class ConnectionStateHandler extends EventEmitter { mockPc.onconnectionstatechange(); - expect(connectionStateHandler.onConnectionStateChange).toHaveBeenCalledTimes(1); + expect(connectionStateHandler.onPeerConnectionStateChange).toHaveBeenCalledTimes(1); }); it('returns connection state from connection state handler when geConnectionState() is called', () => { expect.assertions(2); const connectionStateHandler = getInstantiatedConnectionStateHandler(); - connectionStateHandler.getConnectionState.mockReturnValueOnce(ConnectionState.Connected); + connectionStateHandler.getConnectionState.mockReturnValueOnce('connected'); - expect(pc.getConnectionState()).toStrictEqual(ConnectionState.Connected); + expect(pc.getConnectionState()).toBe('connected'); expect(connectionStateHandler.getConnectionState).toHaveBeenCalledTimes(1); }); - it("listens on ConnectionStateHandler's ConnectionStateChange event and emits it", () => { + it("listens on ConnectionStateHandler's PeerConnectionStateChange event and emits it", () => { expect.assertions(2); const connectionStateHandler = getInstantiatedConnectionStateHandler(); - pc.on(PeerConnection.Events.ConnectionStateChange, (state) => { - expect(state).toStrictEqual(ConnectionState.Connecting); + pc.on(PeerConnection.Events.PeerConnectionStateChange, (state) => { + expect(state).toBe('connecting'); }); // verify that PeerConnection listens for the right event expect(connectionStateHandler.on.mock.calls[0][0]).toStrictEqual( - ConnectionStateHandler.Events.ConnectionStateChanged + ConnectionStateHandler.Events.PeerConnectionStateChanged ); // trigger the fake event from ConnectionStateHandler const connectionStateHandlerListener = connectionStateHandler.on.mock.calls[0][1]; - connectionStateHandlerListener(ConnectionState.Connecting); + connectionStateHandlerListener('connecting'); }); it("listens on ConnectionStateHandler's IceConnectionStateChange event and emits it", () => { expect.assertions(2); const connectionStateHandler = getInstantiatedConnectionStateHandler(); pc.on(PeerConnection.Events.IceConnectionStateChange, (state) => { - expect(state).toStrictEqual(IceConnectionState.Checking); + expect(state).toBe('checking'); }); // verify that PeerConnection listens for the right event @@ -265,7 +261,7 @@ describe('PeerConnection', () => { // trigger the fake event from ConnectionStateHandler const connectionStateHandlerListener = connectionStateHandler.on.mock.calls[1][1]; - connectionStateHandlerListener(IceConnectionState.Checking); + connectionStateHandlerListener('checking'); }); }); describe('createAnswer', () => { diff --git a/src/peer-connection.ts b/src/peer-connection.ts index 598077c..3b3e0e7 100644 --- a/src/peer-connection.ts +++ b/src/peer-connection.ts @@ -1,10 +1,5 @@ import { BrowserInfo } from '@webex/web-capabilities'; -import { - ConnectionState, - ConnectionStateHandler, - IceConnectionState, - OverallConnectionState, -} from './connection-state-handler'; +import { ConnectionState, ConnectionStateHandler } from './connection-state-handler'; import { EventEmitter, EventMap } from './event-emitter'; import { createRTCPeerConnection } from './rtc-peer-connection-factory'; import { logger } from './util/logger'; @@ -33,7 +28,7 @@ type IceGatheringStateChangeEvent = { enum PeerConnectionEvents { IceGatheringStateChange = 'icegatheringstatechange', IceCandidate = 'icecandidate', - ConnectionStateChange = 'connectionstatechange', + PeerConnectionStateChange = 'peerconnectionstatechange', IceConnectionStateChange = 'iceconnectionstatechange', CreateOfferOnSuccess = 'createofferonsuccess', CreateAnswerOnSuccess = 'createansweronsuccess', @@ -44,8 +39,8 @@ enum PeerConnectionEvents { interface PeerConnectionEventHandlers extends EventMap { [PeerConnectionEvents.IceGatheringStateChange]: (ev: IceGatheringStateChangeEvent) => void; [PeerConnectionEvents.IceCandidate]: (ev: RTCPeerConnectionIceEvent) => void; - [PeerConnectionEvents.ConnectionStateChange]: (state: ConnectionState) => void; - [PeerConnectionEvents.IceConnectionStateChange]: (state: IceConnectionState) => void; + [PeerConnectionEvents.PeerConnectionStateChange]: (state: RTCPeerConnectionState) => void; + [PeerConnectionEvents.IceConnectionStateChange]: (state: RTCIceConnectionState) => void; [PeerConnectionEvents.CreateOfferOnSuccess]: (offer: RTCSessionDescriptionInit) => void; [PeerConnectionEvents.CreateAnswerOnSuccess]: (answer: RTCSessionDescriptionInit) => void; [PeerConnectionEvents.SetLocalDescriptionOnSuccess]: ( @@ -86,15 +81,15 @@ class PeerConnection extends EventEmitter { }); this.connectionStateHandler.on( - ConnectionStateHandler.Events.ConnectionStateChanged, - (state: ConnectionState) => { - this.emit(PeerConnection.Events.ConnectionStateChange, state); + ConnectionStateHandler.Events.PeerConnectionStateChanged, + (state: RTCPeerConnectionState) => { + this.emit(PeerConnection.Events.PeerConnectionStateChange, state); } ); this.connectionStateHandler.on( ConnectionStateHandler.Events.IceConnectionStateChanged, - (state: IceConnectionState) => { + (state: RTCIceConnectionState) => { this.emit(PeerConnection.Events.IceConnectionStateChange, state); } ); @@ -105,7 +100,8 @@ class PeerConnection extends EventEmitter { this.connectionStateHandler.onIceConnectionStateChange(); // eslint-disable-next-line jsdoc/require-jsdoc - this.pc.onconnectionstatechange = () => this.connectionStateHandler.onConnectionStateChange(); + this.pc.onconnectionstatechange = () => + this.connectionStateHandler.onPeerConnectionStateChange(); // Subscribe to underlying PeerConnection events and emit them via the EventEmitter /* eslint-disable jsdoc/require-jsdoc */ @@ -132,8 +128,8 @@ class PeerConnection extends EventEmitter { * * @returns The underlying connection's overall state. */ - getOverallConnectionState(): OverallConnectionState { - return this.connectionStateHandler.getOverallConnectionState(); + getConnectionState(): ConnectionState { + return this.connectionStateHandler.getConnectionState(); } /** @@ -141,8 +137,8 @@ class PeerConnection extends EventEmitter { * * @returns The underlying RTCPeerConnection connection state. */ - getConnectionState(): ConnectionState { - return this.connectionStateHandler.getConnectionState(); + getPeerConnectionState(): RTCPeerConnectionState { + return this.connectionStateHandler.getPeerConnectionState(); } /** @@ -150,7 +146,7 @@ class PeerConnection extends EventEmitter { * * @returns The underlying RTCPeerConnection ICE connection state. */ - getIceConnectionState(): IceConnectionState { + getIceConnectionState(): RTCIceConnectionState { return this.connectionStateHandler.getIceConnectionState(); } @@ -406,9 +402,5 @@ class PeerConnection extends EventEmitter { } } -export { - ConnectionState, - IceConnectionState, - OverallConnectionState, -} from './connection-state-handler'; +export { ConnectionState } from './connection-state-handler'; export { MediaStreamTrackKind, PeerConnection, RTCDataChannelOptions }; From 48e0beae8c403f975d1922008d1f91e992fa9b66 Mon Sep 17 00:00:00 2001 From: kwasniow Date: Wed, 12 Jun 2024 12:05:48 +0200 Subject: [PATCH 4/4] feat: correct check in tests --- src/connection-state-handler.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/connection-state-handler.spec.ts b/src/connection-state-handler.spec.ts index b05fd85..748d81e 100644 --- a/src/connection-state-handler.spec.ts +++ b/src/connection-state-handler.spec.ts @@ -35,7 +35,7 @@ describe('ConnectionStateHandler', () => { expect.assertions(1); const connStateHandler = new ConnectionStateHandler(fakeCallback); - expect(connStateHandler.getConnectionState()).toBe('New'); + expect(connStateHandler.getConnectionState()).toStrictEqual(ConnectionState.New); }); it('updates ice connection state on ice connection state change and emits the event', () => {