http://stackoverflow.com/questions/14134090/how-is-a-webrtc-peer-connection-established
<br>http://jsfiddle.net/LcQzV/

<div id="messages" contenteditable></div>

<script>
var RTC = {};
RTC.conn    = window.mozRTCPeerConnection;
RTC.session = window.RTCSessionDescription || window.mozRTCSessionDescription || window.webkitRTCSessionDescription || window.msRTCSessionDescription;
RTC.candidate = mozRTCIceCandidate;

var cfg = {}
cfg.server = {};
cfg.server.url = {url: ['stun:stun.l.google.com 19302']};
//cfg.server.url = {iceServers: [{url:'stun:stun.l.google.com 19302'}]};
cfg.server.opt = null;
cfg.server.opt = { 
	optional: [{'DtlsSrtpKeyAgreement': true}, {'RtpDataChannels': true }] 
	};
cfg.channel = [];
cfg.channel[0] = {};
cfg.channel[0].name = 'myChat';
cfg.channel[0].opt  = {};
//cfg.channel_opt =  {ordered: false, maxRetransmitTime: 1000};
cfg.channel[0].opt  = {reliable: false};
// Set RTC options.
//var rtcOpts = {
//    room: 'test-data',
//    signaller: 'https://switchboard.rtc.io',
//    capture: false
//};


var msg = document.getElementById('messages');
var media = {};
media.fake = media.audio = true;
//var client = new mozRTCPeerConnection();
//var server = new mozRTCPeerConnection();
var client0 = new RTC.conn(cfg.server.url,cfg.server.opt);
var client1 = new RTC.conn(cfg.server.url,cfg.server.opt);
var channel = client0.createDataChannel(cfg.channel[0].name, cfg.channel[0].opt);
client1.onicecandidate = function(e){
    if (!peerConnection || !e || !e.candidate) return;
    sendNegotiation("candidate", event.candidate);
}
client0.onicecandidate = function(e){
    if (!peerConnection || !e || !e.candidate) return;
    sendNegotiation("candidate", event.candidate);
}

//client0(cfg.server.url,cfg.server.opt);
// client1(cfg.server.url,cfg.server.opt);

//SignalingChannel.prototype.send = function(message) {
//  var data = JSON.stringify(message);
  // Send messages using your favorite real-time network
//};


client0.onconnection = function () {
//var channel = client0.createDataChannel(cfg.channel[0].name, cfg.channel[0].opt);
	channel.onmessage = function (event) {
//        alert("client1: " + event.data);
		mess.innerHTML += "<br> Client0 receive: " + event.data;
		};
	channel.onopen = function () {
		mess.innerHTML += "<br> client0 send: " + "Client0 login.";
		channel.send("Client0 login.");
	};
	channel.onclose = function () {mess.innerHTML += "<br> client0 logout.";};
	channel.onerror = function () {mess.innerHTML += "<br> client0 error.";};

	client1.ondatachannel = function (event)
		{
		channel = event.channel || event;
		channel.onmessage = function (event) {
			//        alert("client0: " + event.data);
			mess.innerHTML += "<br> Client1 receive: " + event.data;
			};
		channel.onopen = function () {
			mess.innerHTML += "<br> client1 send:: " + "Client1 login.";
		        channel.send("Client1 login");
			};
		channel.onclose = function () {mess.innerHTML += "<br> client1 logout.";};
		channel.onerror = function () {mess.innerHTML += "<br> client1 error.";};
		}
};

var sdpConstraints = {'mandatory':
  {
    'OfferToReceiveAudio': false,
    'OfferToReceiveVideo': false
  }
};

/*
client1.createOffer(function (sdp) {
    peerConnection.setLocalDescription(sdp);
    sendNegotiation("offer", sdp);
    console.log("------ SEND OFFER ------");
}, null, sdpConstraints);

client0.createOffer(function (sdp) {
    peerConnection.setLocalDescription(sdp);
    sendNegotiation("offer", sdp);
    console.log("------ SEND OFFER ------");
}, null, sdpConstraints);
*/
function processIce(iceCandidate){
  client0.addIceCandidate(new RTC.candidate(iceCandidate));
}
function processAnswer(answer){
  client0.setRemoteDescription(new RTC.session(answer));
  console.log("------ PROCESSED ANSWER ------");
};


/*
client0.setRemoteDescription(new RTC.session(offer));

client0.createAnswer(function (sdp) {
  client0.setLocalDescription(sdp);
  sendNegotiation("answer", sdp);
  console.log("------ SEND ANSWER ------");
}, null, sdpConstraints);

//function processIce(iceCandidate){
//  peerConnection.addIceCandidate(new RTCIceCandidate(iceCandidate));
//}
*/

/*
navigator.mozGetUserMedia(media, callback, errback);

function callback(fakeAudio) {
    client1.addStream(fakeAudio);
    client0.addStream(fakeAudio);
    client0.createOffer(offer);
}

function errback(error) {
    alert(error);
}


function offer(description) {
    client0.setLocalDescription(description, function () {
        client1.setRemoteDescription(description, function () {
            client1.createAnswer(answer);
        });
    });
}


function answer(description) {
    client1.setLocalDescription(description, function () {
        client0.setRemoteDescription(description, function () {
            var port1 = Date.now();
            var port2 = port1 + 1;

            client0.connectDataConnection(port1, port2);
            client1.connectDataConnection(port2, port1);
        });
    });
}
*/


msg.innerHTML += "<br>"+channel.readyState;
msg.innerHTML += "<br>"+client0.iceConnectionState;
msg.innerHTML += "<br>"+client1.iceConnectionState;

channel.send("Hello World!");
//alert(client.open())

</script>