Source: listener.js

import './listener.css';
import AudioPeer from './audioPeer';

/**
 * @class Handles the listener's side of the connection. Responsible for getting access to user's microphone,
 * and initiating a call to the Speaker.
 * @extends AudioPeer
 */
class Listener extends AudioPeer {
  /**
   * Takes a target element where html elements will be appended.
   * @param {initParameters} params - see type definition for initParameters
   */
  constructor(params) {
    super(params);

    this.startTime = Date.now();
    this.receiverPeerId = null;

    const urlParameters = this.parseURLSearchParams();
    this.speakerPeerId = urlParameters.speakerPeerId;

    this.peer.on('open', this.onPeerOpen);
    this.peer.on('connection', this.onPeerConnection);
    this.peer.on('disconnected', this.onPeerDisconnected);
    this.peer.on('close', this.onPeerClose);
    this.peer.on('error', this.onPeerError);
  }

  onPeerOpen = id => {
    console.log('Listener - onPeerOpen');
    // Workaround for peer.reconnect deleting previous id
    if (id === null) {
      console.log('Received null id from peer open');
      this.peer.id = this.lastPeerId;
    } else {
      this.lastPeerId = this.peer.id;
    }
    this.join();
  };

  onPeerConnection = connection => {
    console.log('Listener - onPeerConnection');
    // Disallow incoming connections
    connection.on('open', () => {
      connection.send('Sender does not accept incoming connections');
      setTimeout(() => {
        connection.close();
      }, 500);
    });
  };

  onConnData = data => {
    console.log('Listener - onConnData');
    // Keypad has received data, namely instructions to update the keypad
    // TODO generalize to a list of properies
    const hasSpeakerID = Object.prototype.hasOwnProperty.call(data, 'speakerPeerId');
    if (!hasSpeakerID) {
      console.error('Error in parsing data received! Must set "speakerPeerId" properties');
    } else {
      // this.conn.close();
      console.log(this.speakerPeerId);
      this.speakerPeerId = data.speakerPeerId;
      const newParams = {
        speakerPeerId: this.speakerPeerId,
      };
      /*
      FUTURE does this limit usable environments?
      ie does this work if internet is lost after initial page load?
      */
      window.location.search = this.queryStringFromObject(newParams); // Redirect to correctly constructed keypad page
    }
  };

  join = () => {
    console.log('Listener - join');
    /**
     * Create the connection between the two Peers.
     *
     * Sets up callbacks that handle any events related to the
     * connection and data received on it.
     */
    // Close old connection
    if (this.conn) {
      this.conn.close();
    }
    // Create connection to destination peer specified by the query param
    this.conn = this.peer.connect(this.speakerPeerId, {
      reliable: true,
    });

    this.conn.on('open', () => {
      // console.log("TODO Implement real on connection fn");
      this.openAudioStream();
    });

    // Handle incoming data (messages only since this is the signal sender)
    this.conn.on('data', this.onConnData);
    this.conn.on('close', () => {
      console.log('Connection closed');
    });
  };

  openAudioStream = async () => {
    navigator.mediaDevices
      .getUserMedia({video: false, audio: true})
      .then(stream => {
        this.peer.call(this.speakerPeerId, stream); // one-way call
        console.log('Listener - openAudioStream');
      })
      .catch(err => {
        console.log(`u got an error:${err}`);
      });
  };
}

export default Listener;