Back to Webrtc Experiment

RTCDataChannel for Beginners

docs/rtc-datachannel-for-beginners.html

latest11.0 KB
Original Source

This tutorial is out-dated (written in 2013). Please check this tutorial instead: https://codelabs.developers.google.com/codelabs/webrtc-web/#0

| If you're newcomer, newbie or beginner; you're suggested to try RTCMultiConnection.js or DataChannel.js libraries. |

|

Try RTCDataChannel on Chrome

| | Copy below code and paste in Console Tab of Chrome Dev Tools (using Ctrl + Shift + i).

var iceServers = {
    iceServers: [{
        url: 'stun:stun.l.google.com:19302'
    }]
};

var optionalRtpDataChannels = {
    optional: [{
        RtpDataChannels: true
    }]
};

var offerer = new webkitRTCPeerConnection(iceServers, optionalRtpDataChannels),
    answerer, answererDataChannel;

var offererDataChannel = offerer.createDataChannel('RTCDataChannel', {
    reliable: false
});
setChannelEvents(offererDataChannel, 'offerer');

offerer.onicecandidate = function (event) {
    if (!event || !event.candidate) return;
    answerer && answerer.addIceCandidate(event.candidate);
};

var mediaConstraints = {
    optional: [],
    mandatory: {
        OfferToReceiveAudio: false, // Hmm!!
        OfferToReceiveVideo: false // Hmm!!
    }
};

offerer.createOffer(function (sessionDescription) {
    offerer.setLocalDescription(sessionDescription);
    createAnswer(sessionDescription);
}, null, mediaConstraints);

function createAnswer(offerSDP) {
    answerer = new webkitRTCPeerConnection(iceServers, optionalRtpDataChannels);
    answererDataChannel = answerer.createDataChannel('RTCDataChannel', {
        reliable: false
    });

    setChannelEvents(answererDataChannel, 'answerer');

    answerer.onicecandidate = function (event) {
        if (!event || !event.candidate) return;
        offerer && offerer.addIceCandidate(event.candidate);
    };

    answerer.setRemoteDescription(offerSDP);
    answerer.createAnswer(function (sessionDescription) {
        answerer.setLocalDescription(sessionDescription);
        offerer.setRemoteDescription(sessionDescription);
    }, null, mediaConstraints);
}

function setChannelEvents(channel, channelNameForConsoleOutput) {
    channel.onmessage = function (event) {
        console.debug(channelNameForConsoleOutput, 'received a message:', event.data);
    };

    channel.onopen = function () {
        channel.send('first text message over RTP data ports');
    };
    channel.onclose = function (e) {
        console.error(e);
    };
    channel.onerror = function (e) {
        console.error(e);
    };
}

| | After executing above code in the console; try to send messages over RTP data ports like this:

offererDataChannel.send('message from offerer');
answererDataChannel.send('message from answerer');

| |

Try RTCDataChannel on Firefox

| | Copy below code and paste in Console Tab of Firefox Dev Tools (using Ctrl + Shift + i).

function setChannelEvents(channel, channelNameForConsoleOutput) {
    channel.onmessage = function (event) {
        console.debug(channelNameForConsoleOutput, 'received a message:', event.data);
    };
    channel.onopen = function () {
        channel.send('first text message over SCTP data ports');
    };
}

function useless() {}

var iceServers = {
    iceServers: [{
            url: 'stun:23.21.150.121'
        }
    ]
};

var offerer = new mozRTCPeerConnection(iceServers),
    answerer, answererDataChannel, offererDataChannel;

offererDataChannel = offerer.createDataChannel('channel', {});
offererDataChannel.binaryType = 'blob';
setChannelEvents(offererDataChannel, 'offerer');

navigator.mozGetUserMedia({
    audio: true,
    fake: true
}, function (stream) {
    offerer.addStream(stream);

    offerer.createOffer(function (sessionDescription) {
        offerer.setLocalDescription(sessionDescription);
        createAnswer(sessionDescription);
    }, null, mediaConstraints);

}, useless);

var mediaConstraints = {
    optional: [],
    mandatory: {
        OfferToReceiveAudio: true,
        OfferToReceiveVideo: true
    }
};

function createAnswer(offerSDP) {
    answerer = new mozRTCPeerConnection(iceServers);
    answerer.ondatachannel = function (event) {
        answererDataChannel = event.channel;
        answererDataChannel.binaryType = 'blob';
        setChannelEvents(answererDataChannel, 'answerer');
    };

    navigator.mozGetUserMedia({
        audio: true,
        fake: true
    }, function (stream) {

        answerer.addStream(stream);
        answerer.setRemoteDescription(offerSDP);

        answerer.createAnswer(function (sessionDescription) {
            answerer.setLocalDescription(sessionDescription);

            offerer.setRemoteDescription(sessionDescription);
        }, null, mediaConstraints);

    }, useless);
}

| | After executing above code in the console; try to send messages over SCTP data ports like this:

offererDataChannel.send('message from offerer');
answererDataChannel.send('message from answerer');

| |

Explanation:

There are following possible situations:

  1. A person wants to chat with his friend(s); share files directly; or share a part of the screen in realtime!
    He is the offerer.
  2. A person who receives an offer from a friend: so, he will join him. He is the answerer.

There are so many other possible situations. Let us go to the point.

| |

Offerer

| |

The first situation: a person wants to make an offer request to his friend. He will create offer sdp and send that sdp to his friend.

First of all: we need to open a peer connection:

varpeerConnection= new **webkitRTCPeerConnection** (
    { " **iceServers**": [{ "url": " **stun** :stun.l.google.com:19302" }] },
    { **optional** : [{ **RtpDataChannels** : true}] }
);

RTCPeerConnection constructor takes two objects:

  1. ICE servers (STUN or TURN)
  2. Optional (like RtpDataChannels)

| |

Setting event handlers for peer connection object:

[peerConnection](#peerConnection). **onicecandidate** =[onicecandidate](#onicecandidate-func);[openDataChannel](#openDataChannel)();

In simple words: onicecandidate returns locally generated ICE candidates so you can pass them over other peer(s) via XHR or Socket.

| |

openDataChannel

| |

var **channel** ;
function **openDataChannel** () {
    if (! [peerConnection](#peerConnection)|| typeof[peerConnection](#peerConnection). **createDataChannel** == ' **undefined**') {
        console.log('RTCDataChannel is not enabled. Use Chrome Canary '+
                    'and enable this flag via chrome://flags');
        return;
    }[channel](#channel)=[peerConnection](#peerConnection). **createDataChannel** (' **RTCDataChannel**',
        { **reliable** : false
        }
    );[channel](#channel). **onmessage** = function (event) {
        console.log(event. **data** );
    };[channel](#channel). **onopen** = function (event) {[channel](#channel). **send** ('RTCDataChannel opened.');
    };[channel](#channel). **onclose** = function (event) {
        console.log('RTCDataChannel closed.');
    };[channel](#channel). **onerror** = function (event) {
        console.error(event);
    };[peerConnection](#peerConnection). **ondatachannel** = function () {
        console.log('peerConnection.ondatachannel event fired.');
    };
}

| |

How to send data?

| |

[channel](#channel). **send** ('JUST a text message');[channel](#channel). **send** (
    JSON. **stringify** (
        {
            boolean: true, 
            integer: 1, 
            string: 'Wow!', 
            obj: { etc: 'etcetera' }
        }
    )
);

| |

Creating Offer SDP

| |

[peerConnection](#peerConnection). **createOffer** (function (sessionDescription) {[peerConnection](#peerConnection). **setLocalDescription** (sessionDescription);// POST-Offer-SDP-For-Other-Peer(sessionDescription. **sdp** , sessionDescription. **type** );}, null, { ' **mandatory**': { ' **OfferToReceiveAudio**': true, ' **OfferToReceiveVideo**': true } });

| |

Answerer

| |

Assume that you sent offer sdp to your friend using XHR. Now, "process" that offer sdp and then create answer sdp and send it back to offerer:

[peerConnection](#peerConnection). **setRemoteDescription** (new **RTCSessionDescription** ([offerSDP](#offer-sdp)));[peerConnection](#peerConnection). **createAnswer** (function (sessionDescription) {[peerConnection](#peerConnection). **setLocalDescription** (sessionDescription);// POST-answer-SDP-back-to-Offerer(sessionDescription. **sdp** , sessionDescription. **type** );}, null, { ' **mandatory**': { ' **OfferToReceiveAudio**': true, ' **OfferToReceiveVideo**': true } });

| |

Offerer received answer sdp from answerer

| |

[peerConnection](#peerConnection). **setRemoteDescription** (new **RTCSessionDescription** ([answerSDP](#answer-sdp)));

| | Offer/Answer exchange is done. What remaining are ICE candidates. | |

On getting locally generated ICE

| |

function[onicecandidate](#onicecandidate)(event) {
    if (! [peerConnection](#peerConnection)|| !event || !event.candidate) return;
    var candidate = event. **candidate** ;// POST-ICE-to-other-Peer(candidate. **candidate** , candidate. **sdpMLineIndex** );}

| |

On getting ICE sent by other peer

| |

[peerConnection](#peerConnection). **addIceCandidate** (new **RTCIceCandidate** ({ **sdpMLineIndex** : candidate. **sdpMLineIndex** , **candidate** : candidate. **candidate** }));

| |

A few tips:

| |

  1. createDataChannel must be called before creating offer-sdp.
  2. Maximum length for a single message over RTP data ports is about 1280 bytes (chars).
  3. On RTP data ports, you can't send data over more than one channel simultaneously.
  4. Because RTP-channels are currently unreliable...so be careful because it is "unordered (UDP-Like)" delivery of messages!

| |

Are you interested in a "more" simple full-fledged guide? Read this document.

| |

Are you interested in a "simple" guide about RTCDataChannel? Read this document.

| | Are you interested to learn How to share files using RTCDataChannel APIs? |

Feedback

Send MessageEnter your email too; if you want "direct" reply!