Git Product home page Git Product logo

sdp-interop's Introduction

Build Status

Introduction

(or Unified Plan, Plan B and the answer to life, the universe and eveything!)

If somebody wants to talk about interoperability between Firefox and Chome when doing multi-party video conferences, it is impossible to not talk a little bit (or a lot!) about Unified Plan and Plan B. Unified Plan and Plan B were two competing IETF drafts for the negotiation and exchange of multiple media sources (AKA MediaStreamTracks, or MSTs) between two WebRTC endpoints. Unified Plan is being incorporated in the JSEP draft and is on its way to becoming an IETF standard while Plan B has expired in 2013 and nobody should care about it anymore, right? Wrong!

Plan B lives on in the Chrome and its derivatives, like Chromium and Opera. There's actually an issue in the Chromium bug tracker to add support for Unified Plan in Chromium, but that'll take some time. Firefox, on the other hand, has, as of recently, implemented Unified Plan.

Developers that want to support both Firefox and Chrome have to deal with this situation and implement some kind of interoperability layer between Chrome and it derivatives and Firefox.

The most substantial difference between Unified Plan and Plan B is how they represent media stream tracks. Unified Plan extends the standard way of encoding this information in SDP which is to have each RTP flow (i.e., SSRC) appear on its own m-line. So, each media stream track is represented by its own unique m-line. This is a strict one-to-one mapping; a single media stream track cannot be spread across several m-lines, nor may a single m-line represent multiple media stream tracks.

Plan B takes a different approach, and creates a hierarchy within SDP; a m= line defines an "envelope", specifying codec and transport parameters, and a=ssrc lines are used to describe individual media sources within that envelope. So, typically, a Plan B SDP has three channels, one for audio, one for video and one for the data.

Installation

Install locally from npm:

$ npm install sdp-interop

Implementation

This module gives a general solution to the problem of SDP interoperability described in the previous section and deals with it at the lowest level. The idea is to build a PeerConnection adapter that will feed the right SDP to the browser, i.e. Unified Plan to Firefox and Plan B to Chrome and that would give a Plan B SDP to the application.

The SDP interoperability layer

sdp-interop is a reusable npm module that offers the two simple methods:

  • toUnifiedPlan(sdp) that takes an SDP string and transforms it into a Unified Plan SDP.
  • toPlanB(sdp) that, not surprisingly, takes an SDP string and transforms it to Plan B SDP.

The PeerConnection adapter wraps the setLocalDescription(), setRemoteDescription() methods and the success callbacks of the createAnswer() and createOffer() methods. If the browser is Chrome, the adapter does nothing. If, on the other hand, the browser is Firefox the PeerConnection adapter...

  • calls the toUnifiedPlan() method of the sdp-interop module prior to calling the setLocalDescription() or the setRemoteDescription() methods, thus converting the Plan B SDP from the application to a Unified Plan SDP that Firefox can understand.
  • calls the toPlanB() method prior to calling the createAnswer() or the createOffer() success callback, thus converting the Unified Plan SDP from Firefox to a Plan B SDP that the application can understand.

Here's a sample PeerConnection adapter:

function PeerConnectionAdapter(ice_config, constraints) {
    var RTCPeerConnection = navigator.mozGetUserMedia
      ? mozRTCPeerConnection : webkitRTCPeerConnection;
    this.peerconnection = new RTCPeerConnection(ice_config, constraints);
    this.interop = new require('sdp-interop').Interop();
}

PeerConnectionAdapter.prototype.setLocalDescription
  = function (description, successCallback, failureCallback) {
    // if we're running on FF, transform to Unified Plan first.
    if (navigator.mozGetUserMedia)
        description = this.interop.toUnifiedPlan(description);

    var self = this;
    this.peerconnection.setLocalDescription(description,
        function () { successCallback(); },
        function (err) { failureCallback(err); }
    );
};

PeerConnectionAdapter.prototype.setRemoteDescription
  = function (description, successCallback, failureCallback) {
    // if we're running on FF, transform to Unified Plan first.
    if (navigator.mozGetUserMedia)
        description = this.interop.toUnifiedPlan(description);

    var self = this;
    this.peerconnection.setRemoteDescription(description,
        function () { successCallback(); },
        function (err) { failureCallback(err); }
    );
};

PeerConnectionAdapter.prototype.createAnswer
  = function (successCallback, failureCallback, constraints) {
    var self = this;
    this.peerconnection.createAnswer(
        function (answer) {
            if (navigator.mozGetUserMedia)
                answer = self.interop.toPlanB(answer);
            successCallback(answer);
        },
        function(err) {
            failureCallback(err);
        },
        constraints
    );
};

PeerConnectionAdapter.prototype.createOffer
  = function (successCallback, failureCallback, constraints) {
    var self = this;
    this.peerconnection.createOffer(
        function (offer) {
            if (navigator.mozGetUserMedia)
                offer = self.interop.toPlanB(offer);
            successCallback(offer);
        },
        function(err) {
            failureCallback(err);
        },
        constraints
    );
};

Beyond the basics

Like everything in life, sdp-interop is not "perfect", it makes certain assumptions and it has some limitations. First and foremost, unfortunately, a Plan B offer/answer does not have enough information to rebuild an equivalent Unified Plan offer/answer. So, while it is easy to go from Plan B to Unified Plan, the opposite is not possible without keeping some state.

Suppose, for example, that a Firefox client gets an offer from the Focus to join a large call. In the native create answer success callback you get a Unified Plan answer that contains multiple m-lines. You convert it in a Plan B answer using the sdp-interop module and hand it over to the app to do its thing. At some point later-on, the app calls the adapter's setLocalDescription() method. The adapter will have to convert the Plan B answer back to a Unified Plan one to pass it to Firefox.

That's the tricky part because you can't naively put any SSRC in any m-line, each SSRC has to be put back into the same m-line that it was in the original answer from the native create answer success callback. The order of the m-lines is important too, so each m-line has to be in the same position it was in the original answer from the native create answer success callback (which matches the position of the m-line in the Unified Plan offer). It is also forbidden to remove an m-line, instead they must be marked as inactive, if they're no longer used. Similar considerations have to be taken into account when converting a Plan B offer to a Unified Plan one when doing renegotiation, for example.

We solved this issue by passing the current description set on the peerconnection when converting a Plan B offer to a Unified Plan offer.

Another soft limitation (in the sense that it can be removed given enough effort) is that we require bundle and rtcp-mux for both Chrome and Firefox endpoints, so all the media whatever the channel is, go through a single port. This is tracked in issue #3.

Firefox can also be the offerer, i.e., it can create an offer and send it to another client for establishing a peer-to-peer connection.

Copyright notice

Copyright @ 2015 - Present, 8x8 Inc

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

sdp-interop's People

Contributors

bgrozev avatar changzhn avatar dependabot[bot] avatar emcho avatar gpolitis avatar hristoterezov avatar jallamsetty1 avatar mishurov avatar mparis avatar nils-ohlmeier avatar saghul avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sdp-interop's Issues

Build / release

Can you please add a build task with grunt or gulp that creates a single debug and minified files of the whole code and dependencies (sdp-transform) under a namespace?

That will make it easier to use in the browser with projects that are not using require().

README is outdated (describes state of 2015)

README.md describes the landscape, but as it looked 5 years ago.
Firefox implemented Unified Plan "as of recently" - in March 2015.
Chromium-based browsers transitioning from Plan B to Unified Plan still "take some time" but referenced bug about implementing Unified Plan is now done (even if not yet formally closed) and it makes sense to instead (or also?) link to https://bugs.chromium.org/p/chromium/issues/detail?id=857004 about making it the default.

datachannel doesn't have rtcp-mux attribute

When creating a pc with only a datachannel, Firefox 38 doesn't set the rcp-mux attribute and toPlanB fails with an error:

Cannot convert to Plan B because m-lines without the rtcp-mux attribute were found.

Is it a problem with FF or does the interop need to relax the rtcp-mux requirement on the application m-section?

var pcConfig = {
    "iceServers": [{"url": "stun:stun.l.google.com:19302"}],
    "RTCBundlePolicy": "max-bundle"
};
pc = new RTCPeerConnection(pcConfig);
var dataChannel = pc.createDataChannel("label", {});

var mediaConstraints = {
  'mandatory': {
    'OfferToReceiveAudio': false, 
    'OfferToReceiveVideo': false},
  'optional': []};
pc.createOffer(
    function(description) {
      pc.setLocalDescription(
        description,
        function() {
          description = interop.toPlanB(description);
          //sendMessage(description);
        },
        function () {}
      );
    },
    function() {},
    mediaConstraints
  );

session.groups is not defined in toPlanB() & toUnifiedPlan()

Hi, thanks for providing the polyfill for the inter-browser RTC.

I just discovered this package today, and gave it a try.
I found that the library will throw an error inside toPlanB() and toUnifiedPlan() while the call in connecting.
Giving a simple check before accessing session.groups is not working, another error will come out.

My guess is that the library was not maintained and thus those conversions have became outdated.
(Chrome 49 and Firefox 45 were used)
We have to update the parsing function in order to get it work.

Is my guess correct?
If so, would it be possible to update those features? Or could you point out where we can find the document to fix them ourself?

Many thanks.

refactor/sanitize the code

The toPlanB() and toUnifiedPlan() methods way are too long. Also there are some excessive type checks that could be removed to simplify/lighten the code.

Client side use

Is it possible to get this module loaded into the client side?

I've tried packing it up using both browserify and webpack and they both do create a .js file (for example: interop.js)

./node_modules/.bin/webpack node_modules/sdp-interop/lib/index.js public/interop.js

I can load the interop.js script (created by browserify or webpack) into the browser using a script tag and node/express do deliver it into browser no problem. However that doesn't seem to get the Interop() object exported into browser's space. If I try something like "var abc = new Interop()" that totally fails with "Interop is undefined" or similar (I don't remember the exactly wording, that's the gist of it).

Am I approaching this totally wrong? Or did I miss something? I'd like to get it into browser space so that I don't have to totally rewrite my server.js and client.js code (I'm adding a new feature and that feature requires negotiation that fails due to the UnifiedPlan - PlanB incompatibility issues. Otherwise without my new features RTC between the browser does work. But, I gotta add the feature.

Anyone have pointers? Thanks in advance for help.

How to use sdp-interop on browser side ?

I was trying to implement this on browser side , But can't find any good doc for how to do that , or can't find any js file that I can directly use

Tried :
First I have tried to generate files browser compatible with browserify , I have also deep into it and able to call the function like toPlanB() and toUnifiedPlan() , But was throwing error this.cache is not defined.

So is there any cdn file , so we can use that easily?

Does this work only if chrome is offerer or it works vice versa ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.