constructor(
    socket,
    isRoot,
    messageHandlers = {},
    addedIceServers = [],
    iceDisconnHandler
  ) {
    // ref to Viewer's socket connection
    this.socket = socket;
    // indicates whether this node is the root connecting to the server
    this.isRoot = isRoot;
    // event handlers for DataChannel messages
    this.messageHandlers = messageHandlers;
    // function provided by Viewer class to run when ICE disconnects
    this.iceDisconnHandler = iceDisconnHandler;

    // reserved variables
    // RTC DataChannel
    this.channel;
    // Peer's socket ID
    this.peerId;

    // set up wrapped WebRTCConnection
    this.RTCconn = new RTCPeerConnection({
      iceServers: [
        // Default STUN servers
        { urls: 'stun:stun.l.google.com:19302' },
        { urls: 'stun:stun1.l.google.com:19302' },
        { urls: 'stun:stun2.l.google.com:19302' },
        { urls: 'stun:stun3.l.google.com:19302' },
        { urls: 'stun:stun4.l.google.com:19302' },
        // user-provided TURN servers go here
        ...addedIceServers
      ]
    });

    /**
     * Useful diagrams for WebRTC signaling process:
     * 
     * 1. Initiating negotiation:
     * https://mdn.mozillademos.org/files/12363/WebRTC%20-%20Signaling%20Diagram.svg
     * -Caller creates offer
     * 
     * 2. Exchanging ICE candidates:
     * https://mdn.mozillademos.org/files/12365/WebRTC%20-%20ICE%20Candidate%20Exchange.svg
     * 
     */

    // Handle negotiation needed (i.e. when opening data channel)
    this.RTCconn.onnegotiationneeded = this.initOffer.bind(this);

    // Handle connection state changes
    this.RTCconn.onconnectionstatechange = this._connectionStateHandler.bind(this);

    // Handle ICE connection state changes
    this.RTCconn.oniceconnectionstatechange = this._iceConnectionStateHandler.bind(this);

    // when ICE candidates need to be sent to callee
    this.RTCconn.onicecandidate = this._iceCandidateHandler.bind(this);

    // Handle requests to open data channel
    this.RTCconn.ondatachannel = this._receiveDataChannel.bind(this);

    // Signaling state changes - uncomment to get signaling state logs
    // this.RTCconn.onsignalingstatechange = this._signalingStateHandler.bind(this);
  }
Wrapper class for RTC connection between parent and child viewers