From 7fa67270977f204463a3c005b8ed7ec2157698f7 Mon Sep 17 00:00:00 2001 From: bbaldino Date: Thu, 26 Aug 2021 09:07:12 -0700 Subject: [PATCH] feat: peer connection events; helper functions (#23) * feat: add 'getLocalDescription' method on PeerConnection * feat: derive PeerConnection from EventEmitter; proxy icegatheringstatechange event * feat: add function to wait for description with ice candidates * fix: fix spelling errors * refactor: use reject instead of throw --- README.md | 4 ++-- src/index.ts | 2 ++ src/peer-connection-utils.ts | 26 ++++++++++++++++++++++++++ src/peer-connection.ts | 23 ++++++++++++++++++++++- 4 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 src/peer-connection-utils.ts diff --git a/README.md b/README.md index 3cd7b3c..ea34ff1 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,11 @@ Handles the WebRTC core functionality. -## Developement +## Development 1. `yarn` 1. `yarn watch` ## Usage -This library uses [cspell](https://github.com/streetsidesoftware/cspell) to check spelling throughout the codebase. Any words that need to be ignored (e.g., package names, protocols, etc.), should be added to the `ignoreWords` field in the [cpsell.json](./cspell.json) configuration file. +This library uses [cspell](https://github.com/streetsidesoftware/cspell) to check spelling throughout the codebase. Any words that need to be ignored (e.g., package names, protocols, etc.), should be added to the `ignoreWords` field in the [cspell.json](./cspell.json) configuration file. diff --git a/src/index.ts b/src/index.ts index 508a9ff..5d9e7b2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,3 +5,5 @@ import * as media from './media'; export * from './local-track'; export * from './peer-connection'; export { media }; + +export * from './peer-connection-utils'; diff --git a/src/peer-connection-utils.ts b/src/peer-connection-utils.ts new file mode 100644 index 0000000..c6cbab0 --- /dev/null +++ b/src/peer-connection-utils.ts @@ -0,0 +1,26 @@ +import { PeerConnection } from 'peer-connection'; + +/** + * Wait until the given peer connection has finished gathering ICE candidates and, when it has, + * return the local description with the candidates. + * + * @param peerConnection - The PeerConnection to use. + * @returns A Promise that resolves with the local description with the ICE candidates in it. + */ +export function getLocalDescriptionWithIceCandidates( + peerConnection: PeerConnection +): Promise { + return new Promise((resolve, reject) => { + peerConnection.on(PeerConnection.Events.IceGatheringStateChange, (e) => { + if (e.target.iceGatheringState === 'complete') { + const localDesc = peerConnection.getLocalDescription(); + if (localDesc) { + resolve(localDesc); + } else { + reject(new Error('Local description was null')); + } + } + // TODO(brian): throw an error if we see an error iceGatheringState + }); + }); +} diff --git a/src/peer-connection.ts b/src/peer-connection.ts index cc24f10..b240a3c 100644 --- a/src/peer-connection.ts +++ b/src/peer-connection.ts @@ -1,22 +1,34 @@ import { LocalTrack } from './local-track'; import { log } from './util/logger'; +import { EventEmitter } from './event-emitter'; /** * Manages a single RTCPeerConnection with the server. */ -class PeerConnection { +class PeerConnection extends EventEmitter { + static Events = { + IceGatheringStateChange: 'icegatheringstatechange', + }; + private pc: RTCPeerConnection; /** * Creates an instance of the RTCPeerConnection. */ constructor() { + super(); log('PeerConnection init'); this.pc = new RTCPeerConnection(); // Bind event handlers. this.handleTrackUpdate = this.handleTrackUpdate.bind(this); + + // Subscribe to underlying PeerConnection events and emit them via the EventEmitter + /* eslint-disable jsdoc/require-jsdoc */ + this.pc.onicegatheringstatechange = (ev: Event) => { + this.emit(PeerConnection.Events.IceGatheringStateChange, ev); + }; } /** @@ -107,6 +119,15 @@ class PeerConnection { const sender = this.pc.getSenders().find((s: RTCRtpSender) => s.track?.id === oldTrackId); sender?.replaceTrack(newTrack); } + + /** + * Get the local description from this PeerConnection. + * + * @returns An RTCSessionDescription representing the local description, or null if none has been set. + */ + getLocalDescription(): RTCSessionDescription | null { + return this.pc.localDescription; + } } export { PeerConnection };