Skip to content

Instantly share code, notes, and snippets.

@TikiTDO
Last active March 8, 2018 17:59
Show Gist options
  • Save TikiTDO/ccc2189813a11a8cc0472d977f28aaab to your computer and use it in GitHub Desktop.
Save TikiTDO/ccc2189813a11a8cc0472d977f28aaab to your computer and use it in GitHub Desktop.
Rewrite of the WebRTC DataChannel Basic example, with all the operations grouped together for clarity. Now with links to relevant places in the spec.
/*
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree.
*/
// Original used from: https://github.com/webrtc/samples/blob/750b0ec7675b3326831bb95261b33d0842bc2b39/src/content/datachannel/basic/js/main.js
'use strict';
// DOM Buttons
var startButton = document.querySelector('button#startButton');
var sendButton = document.querySelector('button#sendButton');
var closeButton = document.querySelector('button#closeButton');
// DOM Data Source/Receiver
var local_data_textarea = document.querySelector('textarea#dataChannelSend');
var remote_data_textarea = document.querySelector('textarea#dataChannelReceive');
// RTC Objects
var local_connection;
var remote_connection;
var local_channel;
var remote_channel;
// RTC Configuration
var rtc_connection_configuration;
var data_channel_configuration;
// Functions to simulate abstract data exchange
function send_to_remote(callback) {callback()}
function send_to_local(callback) {callback()}
// Send data from one element to another
sendButton.onclick = function () {
var data = local_data_textarea.value;
local_channel.send(data);
trace('Sent Data: ' + data);
};
// Close all the channels, connections, and return to initial state
closeButton.onclick = function closeDataChannels() {
// First close the channels created on the connections
local_channel.close();
remote_channel.close();
local_channel = null, remote_channel = null;
trace('Closed Channels');
// Second, close the connections
local_connection.close();
remote_connection.close();
local_connection = null, remote_connection = null;
trace('Closed Connections');
// Finally, clean up the buttons and textareas
startButton.disabled = false, sendButton.disabled = true, closeButton.disabled = true;
local_data_textarea.disabled = true, local_data_textarea.value = '', remote_data_textarea.value = '';
trace('Reset Button States');
};
// Create a connection between the two elements
startButton.onclick = function () {
// Init
local_data_textarea.placeholder = '';
// To be extra clear - STUN/TURN Servers are ICE Servers
// See RTC Connection Configuration https://w3c.github.io/webrtc-pc/#rtcconfiguration-dictionary
rtc_connection_configuration = {
// iceServers: [server1, server2], // Array of {urls: ['server uri'], username: 'string',
// // credential: 'string', credentialType: 'password|token'}
// iceTransportPolicy: 'relay|all', // (Default: all) May force using TURN servers to prevent leaking IP data
// iceCandidatePool: integer, // (Default: 0) How many ICE candidates to wait for befor trying to connect
// rtcpMuxPolicy: 'negotiate|require' // (Default: 'require') May force RTC to run on a single UDP port
// peerIdentity: 'string', // Securely identify a connection, to prevent hijacking
// certificates: [certificate, certificate], // Certificates used to authenticate connection. Only set once.
// bundlePolicy: 'balanced|max-compat|max-bundle', // (Default: 'balanced') How to combine media streams
};
// See Data Channel Configuration https://w3c.github.io/webrtc-pc/#idl-def-rtcdatachannelinit
data_channel_configuration = {
// order: boolean, // (Default: true) Whether data must be delivered in order
// maxPacketLifeTime: int, // Maximum amount of time that client will re-transmit data without ack
// maxRetransmits: int, // Maximum number ot times client will re-transmit data without ack
// protocol: 'string', // (Default: '') Sub-protocol for this channel
// negotiated : boolean, // (Default: false) Whether remote data channels are automatically negotiated
// id: int // Override the numberic identifier for this channel
};
// Initialize the RCP Connections
initializeConnections();
// Initialize the RCP channels
initializeLocalDataChannel();
initializeRemoteDataChannel();
// Connect channels to each other
connectLocalToRemote();
// Put buttons into connected mode
startButton.disabled = true;
closeButton.disabled = false;
};
// Configure the local and remote connections with the minimum functional parameters
function initializeConnections () {
// Start local and remote RCP channel. Nominally this is done in two different browser contexts
window.local_connection = new RTCPeerConnection(rtc_connection_configuration);
trace('Local Connection has been created');
window.remote_connection = new RTCPeerConnection(rtc_connection_configuration);
trace('Remote Connection has been created');
// See RTC Connection Intereface definition https://w3c.github.io/webrtc-pc/#interface-definition
// Exchange ICE server (STUN/TURN) responses between local and remote. This should be done with a signalling server
local_connection.onicecandidate = function (event) {
send_to_remote(function () {
if (!event.candidate) return; // The last event from the server will not have a candidate
remote_connection.addIceCandidate(event.candidate, onAddIceCandidateSuccess, onAddIceCandidateError);
trace('Sent a Local Connection ICE candidate to the Remote Connection.')
});
};
remote_connection.onicecandidate = function (event) {
send_to_local(function () {
if (!event.candidate) return; // The last event from the server will not have a candidate
local_connection.addIceCandidate(event.candidate, onAddIceCandidateSuccess, onAddIceCandidateError);
trace('Sent a Remote Connection ICE candidate to the Local Connection.')
});
}
}
// Initialize the local channel, then listen on that channel for open/close events
function initializeLocalDataChannel () {
// Initialize local RCP channel
local_channel = local_connection.createDataChannel('example_channel_label', data_channel_configuration);
trace('Local Connection has created a Local Channel');
// See Data Channel Interface definition https://w3c.github.io/webrtc-pc/#rtcdatachannel
// Configure local RCP channel
local_channel.onopen = function () {
sendButton.disabled = false, closeButton.disabled = false;
local_data_textarea.disabled = false;
local_data_textarea.focus();
trace('Local Channel state is: ' + local_channel.readyState);
};
local_channel.onclose = function () {
local_data_textarea.disabled = true;
sendButton.disabled = true, closeButton.disabled = true;
trace('Local Channel state is: ' + local_channel.readyState);
};
local_channel.onmessage = function (event) {
trace('Local Channel received a message');
}
};
// Watch the remote connection for a data channel, then listen on that channel for messages, or open/close events
function initializeRemoteDataChannel() {
// See Data Channel Interface definition https://w3c.github.io/webrtc-pc/#rtcdatachannel
// Initialize remote RCP channel, once it is connected to local channel by the connectLocalToRemote function
remote_connection.ondatachannel = function (event) {
remote_channel = event.channel;
trace('Remote Connection has created a Remote Channel');
// Configure remote message receiver
remote_channel.onmessage = function (event) {
remote_data_textarea.value = event.data;
trace('Remote Channel received a message');
};
// Handle remote open/close
remote_channel.onopen = remote_channel.onclose = function () {
trace('Remote Channel state is: ' + remote_channel.readyState);
};
};
}
// Offer the local channel to the remote channel
function connectLocalToRemote() {
var local_offer_promise;
// Create an offer to connect to local connection
local_offer_promise = local_connection.createOffer();
local_offer_promise.catch(onCreateSessionDescriptionError);
local_offer_promise.then(function (offer_description) {
local_connection.setLocalDescription(offer_description);
trace('Created Offer from Local Connection');
});
// "Send" the offer description to remote
local_offer_promise.then(receiveOfferFromLocal);
}
// Connect the remote channel to the local channel
function receiveOfferFromLocal(offer_description) {
var remote_answer_promise;
// Save local offer in remote host
remote_connection.setRemoteDescription(offer_description);
trace('Offer received by Remote Connection: \n' + offer_description.sdp);
// Create answer to send back to local host
remote_answer_promise = remote_connection.createAnswer();
remote_answer_promise.catch(onCreateSessionDescriptionError);
remote_answer_promise.then(function (answer_description) {
remote_connection.setLocalDescription(answer_description);
trace('Created Answer from Remote Connection');
});
// "Send" the answer back to local
remote_answer_promise.then(receiveAnswerFromRemote);
}
// Connect the local channel to the remote channel
function receiveAnswerFromRemote(answer_description) {
local_connection.setRemoteDescription(answer_description);
trace('Answer received by Local Connection: \n' + answer_description.sdp);
}
// Handle errors during offer or answer creation
function onCreateSessionDescriptionError(error) {
trace('Failed to create session description: ' + error.toString());
}
// Signals that an ICE candidate has been added to a connection's DB
function onAddIceCandidateSuccess() {
trace('AddIceCandidate success.');
}
// Signals that an ICE candidate could not be added to a connection's DB
function onAddIceCandidateError(error) {
trace('Failed to add Ice Candidate: ' + error.toString());
}
@Globik
Copy link

Globik commented Apr 14, 2016

But how to implement this basic with a signaler server? No need turn, stun and like? Only null?

@TikiTDO
Copy link
Author

TikiTDO commented May 21, 2016

This example is meant purely to illustrate the steps that happen when connecting two peers together. It does not actually use any ICE servers. If you wish to use ICE features like STUN and TURN then you will need to refer to examples such as these:

  1. Getting info out of ICE servers: https://github.com/webrtc/samples/blob/gh-pages/src/content/peerconnection/trickle-ice/js/main.js
  2. Using ICE servers for connection management: https://github.com/webrtc/samples/blob/gh-pages/src/content/peerconnection/restart-ice/js/main.js

@Globik
Copy link

Globik commented Mar 8, 2018

It's cool, thank you very much.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment