@bowbee/peer-lite
v2.1.0
Published
Lightweight WebRTC browser library that supports video, audio and data channels
Downloads
215
Maintainers
Readme
PeerLite
This is a fork of peer-lite - thanks to skyllo for the base code.
This fork adds the ability to optionally stop the tracks of a stream when removing it from a peer. This behaviour is on by default, but can be disabled by passing
false
as the third argument toremoveStream
or any other relevant method.
Lightweight WebRTC browser library that supports video, audio and data channels.
Features
- Lightweight! 3kb (gzipped)
- Zero dependencies
- Ships with TypeScript definitions
- Uses modern WebRTC APIs
- "Perfect negotiation" pattern
- Support for renegotiation of connection
- ICE candidate batching
Installation
yarn add peer-lite
Usage
Two peers connecting locally
import Peer from 'peer-lite';
const peer1 = new Peer();
const peer2 = new Peer();
peer1.on('signal', async (description) => {
await peer2.signal(description);
})
peer2.on('signal', async (description) => {
await peer1.signal(description);
})
peer1.on('onicecandidates', async (candidates) => {
const promises = candidates.map(async candidate => peer2.addIceCandidate(candidate));
await Promise.all(promises);
});
peer2.on('onicecandidates', async (candidates) => {
const promises = candidates.map(async candidate => peer1.addIceCandidate(candidate));
await Promise.all(promises);
});
peer1.on('streamRemote', (stream) => {
document.querySelector('#video1').srcObject = stream;
});
peer2.on('streamRemote', (stream) => {
document.querySelector('#video2').srcObject = stream;
});
(async () => {
const stream = await Peer.getUserMedia();
peer1.addStream(stream);
peer2.addStream(stream);
peer1.start();
})();
Peer connection with fake signalling server
import Peer from 'peer-lite';
const peer = new Peer();
const fakeSocket = new Socket();
// Peer events
peer.on('signal', async (description) => {
fakeSocket.emit('signal', description);
});
peer.on('onicecandidates', async (candidates) => {
fakeSocket.emit('onicecandidates', candidates);
});
peer.on('streamLocal', (stream) => {
document.querySelector('#videoLocal').srcObject = stream;
});
peer.on('streamRemote', (stream) => {
document.querySelector('#videoRemote').srcObject = stream;
});
// Socket events
fakeSocket.on('signal', async (description) => {
await peer.signal(description);
});
fakeSocket.on('onicecandidates', async (candidates) => {
const promises = candidates.map(async candidate => peer.addIceCandidate(candidate));
await Promise.all(promises);
});
(async () => {
const stream = await Peer.getUserMedia();
peer.addStream(stream);
peer.start();
})();
Examples
See more examples here with signalling server.
API
Constructor
new Peer(Options)
Peer Options
interface PeerOptions {
/** Enable support for batching ICECandidates */
batchCandidates?: boolean;
/** Timeout in MS before emitting batched ICECandidates */
batchCandidatesTimeout?: number;
/** Peer id used when emitting errors */
id?: string;
/** RTCPeerConnection options */
config?: RTCConfiguration;
/** RTCOfferOptions options */
offerOptions?: RTCOfferOptions;
/** Enable support for RTCDataChannels */
enableDataChannels?: boolean;
/** Default RTCDataChannel label */
channelLabel?: string;
/** Default RTCDataChannel options */
channelOptions?: RTCDataChannelInit;
/** Function to transform offer/answer SDP */
sdpTransform?: (sdp: string) => string;
}
Peer API
interface Peer {
/** Create a peer instance */
constructor(options?: PeerOptions);
/** Initialize the peer */
init(): RTCPeerConnection;
/** Start the RTCPeerConnection signalling */
start({ polite }?: {
polite?: boolean | undefined;
}): void;
/** Process a RTCSessionDescriptionInit on peer */
signal(description: RTCSessionDescriptionInit): Promise<void>;
/** Add RTCIceCandidate to peer */
addIceCandidate(candidate: RTCIceCandidate): Promise<void>;
/** Send data to connected peer using an RTCDataChannel */
send(data: string | Blob | ArrayBuffer | ArrayBufferView, label?: string): boolean;
/** Add RTCDataChannel to peer */
addDataChannel(label?: string, options?: RTCDataChannelInit): void;
/** Get RTCDataChannel added to peer */
getDataChannel(label?: string): RTCDataChannel | undefined;
/** Close peer if active */
destroy(): void;
/** Return the ICEConnectionState of the peer */
status(): RTCIceConnectionState;
/** Return true if the peer is connected */
isConnected(): boolean;
/** Return true if the peer is closed */
isClosed(): boolean;
/** Return the RTCPeerConnection */
get(): RTCPeerConnection;
/** Return the local stream */
getStreamLocal(): MediaStream;
/** Add stream to peer, optionally replacing existing streams, and stopping existing tracks */
addStream(stream: MediaStream, replace?: boolean, stopTracks?: boolean): void;
/** Remove stream from peer */
removeStream(stream: MediaStream, stopTracks?: boolean): void;
/** Add track to peer */
addTrack(track: MediaStreamTrack): void;
/** Remove track on peer */
removeTrack(track: MediaStreamTrack, stopTrack?: boolean): void;
/** Remove tracks on peer */
removeTracks(tracks: MediaStreamTrack[], stopTracks?: boolean): void;
/** Replace track with another track on peer */
replaceTrack(track: MediaStreamTrack, newTrack: MediaStreamTrack, stopOldTrack?: boolean): Promise<void>;
on<E extends keyof PeerEvents>(event: E, listener: PeerEvents[E]): TypedEmitter<PeerEvents>;
off<E extends keyof PeerEvents>(event: E, listener: PeerEvents[E]): TypedEmitter<PeerEvents>;
offAll<E extends keyof PeerEvents>(event?: E): TypedEmitter<PeerEvents>;
}
Peer Events
interface PeerEvents {
error: (data: { id: string; message: string; error?: Error }) => void;
// Connection Status
connecting: VoidFunction;
connected: VoidFunction;
disconnected: VoidFunction;
status: (status: RTCIceConnectionState) => void;
// Signal and RTCIceCandidates
signal: (description: RTCSessionDescriptionInit) => void;
onicecandidates: (iceCandidates: RTCIceCandidate[]) => void;
// MediaStreams
streamLocal: (stream: MediaStream) => void;
streamRemote: (stream: MediaStream) => void;
// RTCDataChannel
channelOpen: (data: { channel: RTCDataChannel }) => void;
channelClosed: (data: { channel: RTCDataChannel }) => void;
channelError: (data: { channel: RTCDataChannel; event: RTCErrorEvent }) => void;
channelData: (data: {
channel: RTCDataChannel;
source: 'incoming' | 'outgoing';
data: string | Blob | ArrayBuffer | ArrayBufferView;
}) => void;
}
Testing
The tests run inside a headless Chrome and Firefox with Playwright and @playwright/test. These run quickly and allow testing of WebRTC APIs in real browsers.
Run Tests (Chrome only)
yarn test
Run Tests (Chrome + Firefox)
CI=true yarn test
Similar Projects
- PeerJS: https://github.com/peers/peerjs
- Simple Peer: https://github.com/feross/simple-peer
- SimpleWebRTC: https://github.com/andyet/SimpleWebRTC
- More here: https://stackoverflow.com/questions/24857637/current-state-of-javascript-webrtc-libraries