UNPKG

@bowbee/peer-lite

Version:

Lightweight WebRTC browser library that supports video, audio and data channels

256 lines (204 loc) 7.84 kB
# PeerLite [![CircleCI](https://circleci.com/gh/skyllo/peer-lite.svg?style=svg&circle-token=cd1df6b2a763871eb9c52ec816a40e0ba0e9beeb)](https://circleci.com/gh/skyllo/peer-lite) [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) ### This is a fork of [peer-lite](https://github.com/skyllo/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 to `removeStream` 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 * [&#34;Perfect negotiation&#34;](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Perfect_negotiation) pattern * Support for [renegotiation](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/onnegotiationneeded) of connection * ICE candidate batching # Installation ```bash yarn add peer-lite ``` # Usage ## Two peers connecting locally ```javascript 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 ```javascript 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](example) with signalling server. # API ## Constructor `new Peer(Options)` ## Peer Options ```typescript 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 ```typescript 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 ```typescript 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](https://playwright.dev/) and [@playwright/test](https://www.npmjs.com/package/@playwright/test). These run quickly and allow testing of WebRTC APIs in real browsers. **Run Tests (Chrome only)** ```bash yarn test ``` **Run Tests (Chrome + Firefox)** ```bash 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