@pexip/peer-connection
TypeScript icon, indicating that this package has built-in type declarations

17.10.1 • Public • Published

@pexip/peer-connection

Wrapper for RTCPeerConnection with @pexip/signal

Install

npm install @pexip/peer-connection

APIs

Cores

  • PeerConnection: The general purpose RTCPeerConnection wrapper, which can be used to create different kind of peer connection with different behavior based on needs. See MainPeerConnection or PresentationPeerConnection.
  • MainPeerConnection: Logical layer on top of PeerConnection to handle media connection with the common interface BasePeerConnection.
  • PresentationPeerConnection: Logical layer on top of PeerConnection to handle presentation media connection with the common interface BasePeerConnection.

Utilities

  • createPCSignals: Create the signals used for MainPeerConnection and PresentationPeerConnection creation.

    Example:

    // Create all the required signals, and `onConnectionStateChange`
    const mainSignals = createPCSignals('main', ['onConnectionStateChange']);

Signals

Optional

Useful when custom implementation of peer connection to handle different behavior

  • onConnectionStateChange: Signal<RTCPeerConnectionState>;: RTCPeerConnection counterpart onconnectionstatechange
  • onDataChannel: Signal<RTCDataChannel>;: RTCPeerConnection counterpart ondatachannel
  • onIceCandidate: Signal<RTCIceCandidate | null>;: RTCPeerConnection counterpart onicecandidate, and use this signal for trickleIce. If this signal is NOT provided, trickleIce feature will be disabled.
  • onIceCandidateError: Signal<RTCPeerConnectionIceErrorEvent>;: RTCPeerConnection counterpart onicecandidateerror.
  • onIceConnectionStateChange: Signal<RTCIceConnectionState>;: RTCPeerConnection counterpart oniceconnectionstatechange
  • onIceGatheringStateChange: Signal<RTCIceGatheringState>;: RTCPeerConnection counterpart onicegatheringstatechange
  • onSignalingStateChange: Signal<RTCSignalingState>;: RTCPeerConnection counterpart onsignalingstatechange
  • onTrack: Signal<RTCTrackEvent>;: RTCPeerConnection counterpart ontrack
  • onNegotiationNeeded: Signal<RTCOfferOptions | undefined>;: RTCPeerConnection counterpart onnegotiationneeded
  • onRemoteStreams: Signal<MediaStream[]>;: Based on ontrack to emit MediaStream[] when there is one from RTCPeerConnection['ontrack'].
  • onRemoteContentStreams: Signal<MediaStream[]>;: Based on ontrack to emit MediaStream[] when there is one from RTCPeerConnection['ontrack'].

The following signals are listened by the peer connection, they can be used for signal data from remote peer

  • onReceiveIceCandidate: Signal<RTCIceCandidate | RTCIceCandidateInit>;: Signaling counterpart should emit an ICE candidate when the remote peer sends an ICE candidate via this signal.

Required

The following signals are required to handle for signaling purpose

  • onError: Signal<Error>;: Emit error when there is error from the peer connection
  • onOffer: Signal<RTCSessionDescriptionInit>;: Emit offer SDP after createOffer
  • onAnswer: Signal<RTCSessionDescriptionInit>;: Emit answer SDP after createAnswer

The following signals are listened by the peer connection, they can be used for signal data from remote peer

  • onReceiveAnswer: Signal<RTCSessionDescriptionInit>;: Signaling counterpart should emit the answer when the remote peer sends an answer via this signal
  • onReceiveOffer: Signal<RTCSessionDescriptionInit>;: Signaling counterpart should emit an offer when the remote peer sends an offer via this signal
  • onOfferRequired: Signal<MediaStream | undefined>;: This is an alternative way to setLocalStream to trigger RTCPeerConnection['createOffer']

Usage

// Create a set of required signals to share with the app
// signals.ts
import {createPCSignals} from '@pexip/peer-connection';

// This utility function creates the following signals
//     onOfferRequired: Signal<undefined>;
//     onReceiveAnswer: Signal<RTCSessionDescriptionInit>;
//     onReceiveOffer: Signal<RTCSessionDescriptionInit>;
//     onError: Signal<Error>;
//     onOffer: Signal<RTCSessionDescriptionInit>;
//     onAnswer: Signal<RTCSessionDescriptionInit>;
// and the following from the `more` parameter
//     onRemoteStreams: Signal<MediaStream[]>;
//     onReceiveIceCandidate: Signal<RTCIceCandidate | RTCIceCandidateInit>;
//     onIceCandidate: Signal<RTCIceCandidate | null>;
export const mainSignals = createPCSignals({
  scope: 'main',
  more: ['onRemoteStreams', 'onReceiveIceCandidate', 'onIceCandidate'],
});

// Here are the signal keys and signatures to map `RTCPeerConnection` events
// accordingly you can create any of them to pass in the `PeerConnection` when
// creating the object
//     onConnectionStateChange: Signal<RTCPeerConnectionState>;
//     onDataChannel: Signal<RTCDataChannel>;
//     onIceCandidate: Signal<RTCIceCandidate | null>;
//     onIceCandidateError: Signal<RTCPeerConnectionIceErrorEvent>;
//     onIceConnectionStateChange: Signal<RTCIceConnectionState>;
//     onIceGatheringStateChange: Signal<RTCIceGatheringState>;
//     onSignalingStateChange: Signal<RTCSignalingState>;
//     onTrack: Signal<RTCTrackEvent>;
//     onNegotiationNeeded: Signal<RTCOfferOptions | undefined>;
//     onRemoteStreams: Signal<MediaStream[]>;

// app.ts
import {createMainPeerConnection} from '@pexip/peer-connection';
import {mainSignals} from './signals';

// NOTE: Use `trickleIce` here since we have provided the `onIceCandidate` signal
const mainPeer = createMainPeerConnection(mainSignals, {bandwidth: 1024});

const stream = await navigator.mediaDevices.getUserMedia({
  audio: true,
  video: true,
});

// set local media stream
// Offer will be created based on `negotiationneeded` flag according to the
// spec, and `onOfferSignal` will be emitted afterwards
await mainPeer.setLocalStream(stream);

// Later on to start presentation
const presentationStream = await navigator.mediaDevices.getDisplayMedia();
await peer.setLocalStream(presentationStream, 'slides');

// cleanup
mainPeer.close();

// Change bandwidth, and trigger `RTCPeerConnection['restartIce']` automatically
mainPeer.bandwidth = 2048;

// signaling.ts
// Handle remote peer events
switch (event.type) {
  case 'onIceCandidate':
    mainSignals.onReceiveIceCandidate.emit(event.candidate);
    break;
  case 'onOffer':
    mainSignals.onReceiveOffer.emit(event.offer);
    break;
  case 'onAnswer':
    mainSignals.onReceiveAnswer.emit(event.answer);
    break;
}

// Handle the local peer signals
const subscriptions = [
  mainSignals.onOffer.add(offer => {
    signaling.send({offer});
  }),
  mainSignals.onAnswer.add(answer => {
    signaling.send({answer});
  }),
  mainSignals.onError.add(error => {
    // Something is wrong with the local peer connection
    console.error(error);
  }),
  mainSignals.onRemoteStreams.add([stream] => {
    setStream(stream);
  }),
  mainSignals.onIceCandidate.add(candidate => {
    if (candidate) {
      signaling.send({candidate});
    }
  }),
];

Sequence Diagrams

Initial connection and media setup for Direct Media

sequenceDiagram
    participant A as Alice
    participant M as MCU (Direct Media)
    participant B as Bob

    A->>+M: /calls offer
    M-->M: Discard offer
    M-->>-A: 200 OK

    Note over A,B: Starts setting up connection

    B-->B: Create DataChannel
    B-->B: Negotiation needed
    B-->B: Create offer
    B->>+M: /calls {"sdp": offer}
    M-->>+A: new_offer {"sdp": offer}
    A-->A: Marked as a Polite Peer
    A-->A: Drop Prev Offer with setRemoteDescription offer
    A-->A: Create answer
    A->>-M: /ack {"sdp": answer}
    M-->>-B: {"sdp": answer}

    Note over A,B: Start setting up media

    B-->B: Schedule to sync transceivers/media
    B-->B: Negotiation needed
    B-->B: Create offer
    B->>+M: /update {"sdp": offer}
    M-->>+A: update_sdp {"sdp": offer}
    A-->A: setRemoteDescription offer
    A-->A: Sync transceivers/media
    A-->A: Create answer
    A->>-M: /ack {"sdp": answer}
    M-->>-B: {"sdp": answer}

Perfect Negotiation

sequenceDiagram
    participant A as Alice
    participant M as MCU
    participant B as Bob

    Note over A,B: Perfect Negotiation after Initial connection & media setup

    par A to M
        A->>+M: /update {"sdp": offer}
        M-->>+B: update_sdp  {"sdp": offer}
        B-->B: Ignore offer
    and B to M
        B->>+M: /update {"sdp": offer}
        M-->>+A: update_sdp  {"sdp": offer}
        A-->A: setRemoteDescription offer
        A-->A: Sync Transceivers
        A-->A: Create Answer
    end
    A--xM: Cancel /update {"sdp": offer}
    A->>-M: /ack {"sdp": answer}
    M-->>-B: {"sdp": answer}

Initial connection and media setup for Normal VMR

sequenceDiagram
    participant A as Alice
    participant M as MCU

    Note over A,M: Initial connection & media setup for Nromal VMR

    A-->A: Create inactive transceivers for warmup
    A-->A: Triggerred Negotiation needed
    A-->A: Create offer
    A->>+M: /calls {"sdp": offer}
    M-->>-A: {"sdp": answer}
    A-->A: setRemoteDescription answer
    A-->A: Schedule to sync Transceivers
    A-->A: Negotiation needed
    A->>+M: /update {"sdp": offer}
    M-->>-A: {"sdp": answer}

Readme

Keywords

none

Package Sidebar

Install

npm i @pexip/peer-connection

Weekly Downloads

14

Version

17.10.1

License

Apache-2.0

Unpacked Size

154 kB

Total Files

20

Last publish

Collaborators

  • npm-pexip