peer-connection/helpers/createAnswer.js

import Skylink from '../../index';
import logger from '../../logger';
import { HANDSHAKE_PROGRESS, PEER_TYPE } from '../../constants';
import MediaStream from '../../media-stream/index';
import SessionDescription from '../../session-description';
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 onAnswerCreated = (resolve, targetMid, roomState, answer) => {
  const { room } = roomState;

  logger.log.DEBUG([targetMid, null, null, 'Created answer'], answer);
  handleNegotiationStats.send(room.id, HANDLE_NEGOTIATION_STATS.ANSWER.create, targetMid, answer, false);
  getCommonOfferAnswerMessage(resolve, targetMid, roomState, answer);
};

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

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

/**
 * @param {SkylinkState} roomState
 * @param {String} targetMid
 * @return {*}
 * @memberOf PeerConnection.PeerConnectionHelpers
 * @fires handshakeProgress
 */
const createAnswer = (roomState, targetMid) => {
  const state = Skylink.getSkylinkState(roomState.room.id);
  const {
    peerConnections,
    hasMCU,
    peerConnStatus,
    voiceActivityDetection,
  } = state;
  const peerConnection = peerConnections[targetMid];
  const { AdapterJS } = window;

  logger.log.INFO([targetMid, null, null, 'Creating answer with config:'], roomState.room.connection.sdpConstraints);

  const answerConstraints = AdapterJS.webrtcDetectedBrowser === 'edge' ? {
    offerToReceiveVideo: !(!state.sdpSettings.connection.audio && targetMid !== PEER_TYPE.MCU) && SessionDescription.getSDPCommonSupports(targetMid, peerConnection.remoteDescription, roomState.room.id).video,
    offerToReceiveAudio: !(!state.sdpSettings.connection.video && targetMid !== PEER_TYPE.MCU) && SessionDescription.getSDPCommonSupports(targetMid, peerConnection.remoteDescription, roomState.room.id).audio,
    voiceActivityDetection,
  } : undefined;

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

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

  // No ICE restart constraints for createAnswer as it fails in chrome 48
  // { iceRestart: true }
  return new Promise((resolve, reject) => {
    peerConnection.createAnswer(answerConstraints)
      .then(answer => onAnswerCreated(resolve, targetMid, roomState, answer))
      .catch(err => onAnswerFailed(reject, targetMid, roomState, err));
  });
};

export default createAnswer;