Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
163 views
in Technique[技术] by (71.8m points)

javascript - WebRTC Between two pages in the same machine

I'm trying to implement a mechanism to send textual data (JSON for instance) in from page to page, using javascript at the same machine.
I found some code and wrapped it but it only works at the same page.
At the moment I don't want to use a WwebRTC framework, only adapter.js.

//Must include adapter.js before

var WebRTCManager = (function () {

    'use strict';

    //Ctor
    function WebRTCManagerFn() {

      console.log('WebRTCManagerFn ctor reached');

      this._events = {};

      this._localConnection = null
      this._remoteConnection = null;
      this._sendChannel = null;
      this._receiveChannel = null;
    }

    WebRTCManagerFn.prototype.addEventListener = function (name, handler)        {
      if (this._events.hasOwnProperty(name))
          this._events[name].push(handler);
      else
          this._events[name] = [handler];
    };

    WebRTCManagerFn.prototype._fireEvent = function (name, event) {
       if (!this._events.hasOwnProperty(name))
          return;

       if (!event)
          event = {};

       var listeners = this._events[name], l = listeners.length;
       for (var i = 0; i < l; i++) {
          listeners[i].call(null, event);
       }
    };

WebRTCManagerFn.prototype.createConnection = function () {
    var servers = null;
    var pcConstraint = null;
    var dataConstraint = null;

    console.log('Using SCTP based data channels');

    // SCTP is supported from Chrome 31 and is supported in FF.
    // No need to pass DTLS constraint as it is on by default in Chrome 31.
    // For SCTP, reliable and ordered is true by default.
    // Add localConnection to global scope to make it visible
    // from the browser console.
    window.localConnection = this._localConnection =
        new RTCPeerConnection(servers, pcConstraint);
    console.log('Created local peer connection object localConnection');

    this._sendChannel = this._localConnection.createDataChannel('sendDataChannel',
            dataConstraint);
    console.log('Created send data channel');
    this._localConnection.onicecandidate = this._localIceCallback.bind(this);
    this._sendChannel.onopen = this._onSendChannelStateChange.bind(this);
    this._sendChannel.onclose = this._onSendChannelStateChange.bind(this);

    // Add remoteConnection to global scope to make it visible
    // from the browser console.
    window.remoteConnection = this._remoteConnection =
        new RTCPeerConnection(servers, pcConstraint);
    console.log('Created remote peer connection object remoteConnection');
    this._remoteConnection.onicecandidate = this._remoteIceCallback.bind(this);
    this._remoteConnection.ondatachannel = this._receiveChannelCallback.bind(this);

    this._localConnection.createOffer(this._gotOfferFromLocalConnection.bind(this), this._onCreateSessionDescriptionError.bind(this));
}

WebRTCManagerFn.prototype._onCreateSessionDescriptionError = function (error) {
    console.log('Failed to create session description: ' + error.toString());
}

WebRTCManagerFn.prototype.sendMessage = function (msgText) {
    var msg = new Message(msgText);

    // Send the msg object as a JSON-formatted string.
    var data = JSON.stringify(msg);
    this._sendChannel.send(data);

    console.log('Sent Data: ' + data);
}

WebRTCManagerFn.prototype.closeDataChannels = function () {
    console.log('Closing data channels');
    this._sendChannel.close();
    console.log('Closed data channel with label: ' + this._sendChannel.label);
    this._receiveChannel.close();
    console.log('Closed data channel with label: ' + this._receiveChannel.label);
    this._localConnection.close();
    this._remoteConnection.close();
    this._localConnection = null;
    this._remoteConnection = null;
    console.log('Closed peer connections');
}

WebRTCManagerFn.prototype._gotOfferFromLocalConnection = function (desc) {
    console.log('reached _gotOfferFromLocalConnection');
    if (this && this._localConnection != 'undefined' && this._remoteConnection != 'undefined') {
        this._localConnection.setLocalDescription(desc);
        console.log('Offer from localConnection 
' + desc.sdp);
        this._remoteConnection.setRemoteDescription(desc);
        this._remoteConnection.createAnswer(this._gotAnswerFromRemoteConnection.bind(this),
            this._onCreateSessionDescriptionError.bind(this));
    }
}

WebRTCManagerFn.prototype._gotAnswerFromRemoteConnection = function (desc) {
    console.log('reached _gotAnswerFromRemoteConnection');
    if (this && this._localConnection != 'undefined' && this._remoteConnection != 'undefined') {
        this._remoteConnection.setLocalDescription(desc);
        console.log('Answer from remoteConnection 
' + desc.sdp);
        this._localConnection.setRemoteDescription(desc);
    }
}

WebRTCManagerFn.prototype._localIceCallback = function (event) {
    console.log('local ice callback');
    if (event.candidate) {
        this._remoteConnection.addIceCandidate(event.candidate,
            this._onAddIceCandidateSuccess.bind(this), this._onAddIceCandidateError.bind(this));
        console.log('Local ICE candidate: 
' + event.candidate.candidate);
    }
}

WebRTCManagerFn.prototype._remoteIceCallback = function (event) {
    console.log('remote ice callback');
    if (event.candidate) {
        this._localConnection.addIceCandidate(event.candidate,
            this._onAddIceCandidateSuccess.bind(this), this._onAddIceCandidateError.bind(this));
        console.log('Remote ICE candidate: 
 ' + event.candidate.candidate);
    }
}

WebRTCManagerFn.prototype._onAddIceCandidateSuccess = function (evt) {
    debugger;
    console.log('AddIceCandidate success. evt: '+ evt);
}

WebRTCManagerFn.prototype._onAddIceCandidateError = function (error) {
    console.log('Failed to add Ice Candidate: ' + error.toString());
}

WebRTCManagerFn.prototype._receiveChannelCallback = function (event) {
    console.log('Receive Channel Callback');
    this._receiveChannel = event.channel;
    this._receiveChannel.onmessage = this._onReceiveMessageCallback.bind(this);
    this._receiveChannel.onopen = this._onReceiveChannelStateChange.bind(this);
    this._receiveChannel.onclose = this._onReceiveChannelStateChange.bind(this);
}

WebRTCManagerFn.prototype._onReceiveMessageCallback = function (event) {
    console.log('Received Message: ' + event.data);
    console.log('Received Message this is: ' + this);

    var msgObj = JSON.parse(event.data);

    this._fireEvent("messageRecieved", {
        details: {
            msg: msgObj
        }
    });
}

WebRTCManagerFn.prototype._onSendChannelStateChange = function () {
    console.log('_onSendChannelStateChange');
    var readyState = this._sendChannel.readyState;
    console.log('Send channel state is: ' + readyState);
}

WebRTCManagerFn.prototype._onReceiveChannelStateChange = function () {
    var readyState = this._receiveChannel.readyState;
    console.log('Receive channel state is: ' + readyState);
}

return WebRTCManagerFn;
})();

My question is how to pass data between two pages on the same machine using WebRTC?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This WebRTC tab chat demo works across tabs or windows in the same browser without a server: https://jsfiddle.net/f5y48hcd/ (I gave up making it work in a code snippet due to a SecurityError.)

Open the fiddle in two windows and try it out. For reference, here's the WebRTC code:

var pc = new RTCPeerConnection(), dc, enterPressed = e => e.keyCode == 13;

var connect = () => init(dc = pc.createDataChannel("chat"));
pc.ondatachannel = e => init(dc = e.channel);

var init = dc => {
  dc.onopen = e => (dc.send("Hi!"), chat.select());
  dc.onclose = e => log("Bye!");
  dc.onmessage = e => log(e.data);
};

chat.onkeypress = e => {
  if (!enterPressed(e)) return;
  dc.send(chat.value);
  log("> " + chat.value);
  chat.value = "";
};

var sc = new localSocket(), send = obj => sc.send(JSON.stringify(obj));
var incoming = msg => msg.sdp &&
  pc.setRemoteDescription(new RTCSessionDescription(msg.sdp))
  .then(() => pc.signalingState == "stable" || pc.createAnswer()
    .then(answer => pc.setLocalDescription(answer))
    .then(() => send({ sdp: pc.localDescription })))
  .catch(log) || msg.candidate &&
  pc.addIceCandidate(new RTCIceCandidate(msg.candidate)).catch(log);
sc.onmessage = e => incoming(JSON.parse(e.data));

pc.oniceconnectionstatechange = e => log(pc.iceConnectionState);
pc.onicecandidate = e => send({ candidate: e.candidate });
pc.onnegotiationneeded = e => pc.createOffer()
  .then(offer => pc.setLocalDescription(offer))
  .then(() => send({ sdp: pc.localDescription }))
  .catch(log);

var log = msg => div.innerHTML += "<br>" + msg;

I use this for demoing WebRTC data channels. Note that the secret sauce is the localSocket.js that I wrote for this, which looks like this:

function localSocket() {
  localStorage.a = localStorage.b = JSON.stringify([]);
  this.index = 0;
  this.interval = setInterval(() => {
    if (!this.in) {
      if (!JSON.parse(localStorage.a).length) return;
      this.in = "a"; this.out = "b";
    }
    var arr = JSON.parse(localStorage[this.in]);
    if (arr.length <= this.index) return;
    if (this.onmessage) this.onmessage({ data: arr[this.index] });
    this.index++;
  }, 200);
  setTimeout(() => this.onopen && this.onopen({}));
}
localSocket.prototype = {
  send: function(msg) {
    if (!this.out) {
      this.out = "a"; this.in = "b";
    }
    var arr = JSON.parse(localStorage[this.out]);
    arr.push(msg);
    localStorage[this.out] = JSON.stringify(arr);
  },
  close: function() {
    clearInterval(this.interval);
  }
};

It basically uses localStorage to simulate web sockets locally between two tabs. If this is all you want to do, then you don't even need WebRTC data channels.

Disclaimer: It's not very robust, and relies on two pages being ready to communicate, so not production-ready by any means.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...