RTC_API_Proposal:PeerListener

anantn edited this page Jul 10, 2011 · 2 revisions

Peer connections

A PeerListener object indicates the clients intent to listen for incoming connections.

constructor PeerListener(DOMString config, optional DOMString negotiationServerURN)
interface PeerListener {
    void listen();
    attribute Function onIncoming;
};
Window implements PeerListener;

function onIncoming(Connection conn);
interface Connection {
    readonly attribute DOMString msg; // Message sent by calling side with open()
    PeerConnection accept(in Function sendSignal);
};

Calling accept() in a PeerListener creates a new PeerConnection with the far end:

interface PeerConnection {
    void receivedSignal(DOMString msg);

    const unsigned short NEW = 1;
    const unsigned short CONNECTING = 2;
    const unsigned short ACTIVE = 3;
    const unsigned short CLOSED = 4;
    readonly attribute unsigned short readyState;

    void addLocalStream(in MediaStream stream);
    void removeLocalStream(in MediaStream stream);
    readonly attribute MediaStream[] localStreams;
    readonly attribute MediaStream[] remoteStreams;

    void open(in DOMString msg);
    void close();

    void send(in DOMString text);

    attribute Function onMessage;
    attribute Function onRemoteStreamAdded;
    attribute Function onRemoteStreamRemoved;
    attribute Function onReadyStateChange;
};
Window implements PeerConnection;

A PeerConnection may also be created independently, for purposes of initiating an outgoing connection:

constructor PeerConnection(DOMString config, Function sendSignal, optional DOMString negotiationServerURN)

Examples

Here are the examples from the RTC API page, rewritten to use PeerListener.

Simple Video Call

Simple video calling between two users A and B. A is making a call to B:

// User-agent A executes
<video id="localPreview"/><video id="remoteView"/>
<script>
navigator.getMediaStream(true, true, function(stream) {
    // Display local video
    document.getElementById("localPreview").stream = stream;

    var conn = new PeerConnection("stun:foobar.net:3476", sendToB);
    function sendToB(msg) { // send via XHR to B }
    function gotFromB(msg) { conn.receivedSignal(msg); }

    conn.addLocalStream(stream);
    conn.onRemoteStreamAdded = function(remoteStream) {
        // Display remote video
        document.getElementById("remoteView").stream = remoteStream;
    };

    conn.open("this is A");
});
</script>

// User-agent B executes
<video id="localPreview"/><video id="remoteView"/>
<script>
navigator.getMediaStream(true, true, function(stream) {
    document.getElementById("localPreview").stream = stream;

    var peer;
    var listener = new PeerListener"stun:foobar.net:3476");
    listener.onIncoming = function(conn) {
        if (conn.msg != "this is A") return;

        peer = conn.accept(sendToA);
        function sendToA(msg) { // send via XHR to A }
        function gotFromA(msg) { conn.receivedSignal(msg); }

        peer.addLocalStream(stream);
        peer.onRemoteStreamAdded = function(remoteStream) {
            document.getElementById("remoteView").stream = remoteStream;
        };
    }

    listener.listen();
});
</script>

Simulcast Video

Simulcasting real-time video & audio streams to multiple clients:

// This code runs on the "server". Some other part of the web page magically paints the game to the canvas
<canvas id="hockeyGame"/>
<script>
var listener = new PeerListener("turns:example.org");
listener.onIncoming = function(conn) {
    switch (conn.msg) {
        ...
        default:
            var peer = conn.accept(sendToPeer);
            // Setup out of band receive for this peer
            function gotFromPeer(msg) {
                peer.receivedSignal(msg);
            }
            peer.addLocalStream(document.getElementById("hockeyGame").stream);
    }
};
listener.listen();
</script>

// All clients subscribing to the simulcast run this code.
// TURN server does the job of initiating onRemoteStreamAdded for every client?
<video id="gameStream"/>
<script>
    function sendToPeer(msg) { // Out of band send }
    function gotFromPeer(msg) { conn.receivedSignal(msg); // Out of band receive }

    var conn = new PeerConnection("turns:example.org", sendToPeer);
    conn.onRemoteStreamAdded = function(stream) {
        document.getElementById("gameStream").stream = stream;
    };

    conn.open(msg); 
</script>

MMORPG

Browser based MMORPG that enables player voice communication (push to talk):

// All players
<button id="ptt"/>
<audio id="otherPlayers"/>
<script>
var mixer;
var worker = new Worker("muxer.js");
var players = ... // this is an array of objects provided by server used in connect to other players
navigator.getMediaStream(true, false, function(stream) {
    var listener = new PeerListener("stuns:game-server.net");
    listener.onIncoming = function(conn) {
        for (var j=0; j<players.length; j++) {
            if (conn.msg == players[i].msg) { // Only accept connections from other players
                setupPeer(conn);
                break;
            }
        }
    };

    function setupPeer(conn) {
        var peer = conn.accept(sendToPeer);
        function sendToPeer(msg) { // Out of band send }
        function gotFromPeer(msg) { peer.receivedSignal(msg); // Out of band receive }

        peer.addLocalStream(stream);
        peer.onRemotetreamAdded = function(remoteStream) {
            if (!mixer) mixer = remoteStream.createProcessor(worker); // StreamProcessor API TBD
            else mixer.addInput(remoteStream);
        };
    }

    listener.listen(); 
    for (i=0; i<players.length; i++) {
         new PeerConnection("stuns:game-server.net", players[i]).open(players[i].msg);
    }

    var streaming = false;
    document.getElementById("ptt").onclick = {
        if (!streaming) {
            streaming = true;
            stream.readyState = stream.LIVE;
        } else {
            streaming = false;
            stream.readyState = stream.BLOCKED;
        }
    };
});
document.getElementById("otherPlayers").stream = mixer.outputStream;