peer-connection/helpers/createOffer.js

import Skylink from '../../index';
import logger from '../../logger';
import PeerConnection from '../index';
import MediaStream from '../../media-stream/index';
import SessionDescription from '../../session-description';
import { HANDSHAKE_PROGRESS, PEER_TYPE } from '../../constants';
import getCommonOfferAnswerMessage from '../../server-communication/signaling-server/message-builder/builders/commons/offerAndAnswer';
import handleNegotiationStats from '../../skylink-stats/handleNegotiationStats';
import MESSAGES from '../../messages';
import { dispatchEvent } from '../../utils/skylinkEventManager';
import { handshakeProgress } from '../../skylink-events';

const { STATS_MODULE: { HANDLE_NEGOTIATION_STATS } } = MESSAGES;

const onOfferCreated = (resolve, targetMid, roomState, restartOfferMsg, offer) => {
  const { room } = roomState;

  logger.log.DEBUG([targetMid, null, null, 'Created offer'], offer);
  handleNegotiationStats.send(room.id, HANDLE_NEGOTIATION_STATS.OFFER.create, targetMid, offer, false);

  getCommonOfferAnswerMessage(resolve, targetMid, roomState, offer, restartOfferMsg);
};

const onOfferFailed = (reject, targetMid, roomState, error) => {
  const { room } = roomState;

  logger.log.ERROR([targetMid, null, null, 'Failed creating an offer:'], error);
  handleNegotiationStats.send(room.id, HANDLE_NEGOTIATION_STATS.OFFER.create_error, targetMid, null, false, error);
  dispatchEvent(handshakeProgress({
    state: HANDSHAKE_PROGRESS.ERROR,
    peerId: targetMid,
    error,
    room: roomState.room,
  }));
  reject(error);
};

/**
 * @param {SkylinkRoom} currentRoom
 * @param {String} targetMid
 * @param {Boolean} iceRestart
 * @param {object} restartOfferMsg
 * @return {*}
 * @memberOf PeerConnection.PeerConnectionHelpers
 * @fires handshakeProgress
 */
const createOffer = (currentRoom, targetMid, iceRestart = false, restartOfferMsg) => {
  const state = Skylink.getSkylinkState(currentRoom.id);
  const initOptions = Skylink.getInitOptions();
  const { enableDataChannel } = initOptions;
  const {
    peerConnections,
    // sdpSettings,
    hasMCU,
    enableIceRestart,
    peerInformations,
    voiceActivityDetection,
    peerConnStatus,
    dataChannels,
  } = state;
  const { AdapterJS } = window;
  const peerConnection = peerConnections[targetMid];

  const offerConstraints = {
    offerToReceiveAudio: !(!state.sdpSettings.connection.audio && targetMid !== PEER_TYPE.MCU) && SessionDescription.getSDPCommonSupports(targetMid, null, currentRoom.id).video,
    offerToReceiveVideo: !(!state.sdpSettings.connection.video && targetMid !== PEER_TYPE.MCU) && SessionDescription.getSDPCommonSupports(targetMid, null, currentRoom.id).audio,
    iceRestart: !!((peerInformations[targetMid] || {}).config || {}).enableIceRestart && iceRestart && enableIceRestart,
    voiceActivityDetection,
  };

  if (hasMCU && typeof peerConnection.addTransceiver !== 'function') {
    offerConstraints.offerToReceiveVideo = true;
  }

  // Add stream only at offer/answer end
  if (!hasMCU || targetMid === PEER_TYPE.MCU) {
    MediaStream.addLocalMediaStreams(targetMid, state);
  }

  if (enableDataChannel && peerInformations[targetMid].config.enableDataChannel) {
    if (!(dataChannels[targetMid] && dataChannels[targetMid].main)) {
      PeerConnection.createDataChannel({
        peerId: targetMid,
        roomState: state,
      });
      state.peerConnections[targetMid].hasMainChannel = true;
    }
  }

  logger.log.DEBUG([targetMid, null, null, 'Creating offer with config:'], offerConstraints);

  peerConnection.endOfCandidates = false;
  peerConnection.negotiating = true;

  if (peerConnStatus[targetMid]) {
    state.peerConnStatus[targetMid].sdpConstraints = offerConstraints;
  }

  Skylink.setSkylinkState(state, currentRoom.id);

  return new Promise((resolve, reject) => {
    peerConnection.createOffer(AdapterJS.webrtcDetectedType === 'plugin' ? {
      mandatory: {
        OfferToReceiveAudio: offerConstraints.offerToReceiveAudio,
        OfferToReceiveVideo: offerConstraints.offerToReceiveVideo,
        iceRestart: offerConstraints.iceRestart,
        voiceActivityDetection: offerConstraints.voiceActivityDetection,
      },
    } : offerConstraints)
      .then(offer => onOfferCreated(resolve, targetMid, state, restartOfferMsg, offer))
      .catch(err => onOfferFailed(reject, targetMid, state, err));
  });
};

export default createOffer;