media-stream/helpers/sendStream.js

import {
  isAObj, isAFunction, hasVideoTrack, hasAudioTrack,
} from '../../utils/helpers';
import logger from '../../logger';
import { dispatchEvent } from '../../utils/skylinkEventManager';
import PeerData from '../../peer-data';
import { peerUpdated, onIncomingStream } from '../../skylink-events';
import PeerConnection from '../../peer-connection/index';
import MediaStream from '../index';
import MESSAGES from '../../messages';

const dispatchEvents = (roomState, stream) => {
  const { user, room } = roomState;
  const isSelf = true;
  const peerId = user.sid;
  const peerInfo = PeerData.getCurrentSessionInfo(room);

  dispatchEvent(onIncomingStream({
    room,
    stream,
    streamId: stream.id,
    isSelf,
    peerId,
    peerInfo,
    isScreensharing: false,
    isVideo: hasVideoTrack(stream),
    isAudio: hasAudioTrack(stream),
  }));

  dispatchEvent(peerUpdated({
    isSelf,
    peerId,
    peerInfo,
  }));
};

const dispatchEventsToLocalEnd = (roomState, streams) => {
  for (let i = 0; i < streams.length; i += 1) {
    if (!streams[i]) break;

    if (Array.isArray(streams[i])) {
      for (let x = 0; x < streams[i].length; x += 1) {
        if (streams[i][x]) {
          dispatchEvents(roomState, streams[i][x]);
        }
      }
    } else {
      dispatchEvents(roomState, streams[i]);
    }
  }
};

const restartFn = (roomState, streams, resolve, reject) => {
  const { AdapterJS } = window;
  const { peerConnections, hasMCU } = roomState;

  if (AdapterJS.webrtcDetectedBrowser === 'edge') {
    reject(new Error(MESSAGES.PEER_CONNECTION.refresh_no_edge_support));
  }

  try {
    dispatchEventsToLocalEnd(roomState, streams);

    if (Object.keys(peerConnections).length > 0 || hasMCU) {
      const refreshPeerConnectionPromise = PeerConnection.refreshPeerConnection(Object.keys(peerConnections), roomState, false, {});

      refreshPeerConnectionPromise.then(() => {
        resolve(streams);
      }).catch((error) => {
        logger.log.ERROR(MESSAGES.PEER_CONNECTION.ERRORS.REFRESH);
        reject(error);
      });
    } else {
      logger.log.WARN(MESSAGES.ROOM.ERRORS.NO_PEERS);
      resolve(streams);
    }
  } catch (error) {
    logger.log.ERROR(error);
  }
};

const processMediaOptions = (roomState, stream, resolve, reject) => {
  const getUserMediaPromise = MediaStream.getUserMedia(roomState, stream);

  return getUserMediaPromise.then((userMediaStreams) => {
    restartFn(roomState, userMediaStreams, resolve, reject);
  }).catch((error) => {
    reject(error);
  });
};

const processMediaStream = (roomState, stream, resolve, reject) => {
  const usePrefetchedStreamPromise = MediaStream.usePrefetchedStream(roomState.room.id, stream);

  return usePrefetchedStreamPromise.then((prefetchedStreams) => {
    restartFn(roomState, prefetchedStreams, resolve, reject);
  }).catch((error) => {
    reject(error);
  });
};

const processMediaStreamArray = (roomState, streams, resolve, reject) => {
  const usePrefetchedStreamsPromises = [];

  streams.forEach((stream) => {
    usePrefetchedStreamsPromises.push(MediaStream.usePrefetchedStream(roomState.room.id, stream));
  });

  return Promise.all(usePrefetchedStreamsPromises)
    .then((results) => {
      restartFn(roomState, results, resolve, reject);
    })
    .catch((error) => {
      reject(error);
    });
};

/**
 * Function that sends a MediaStream if provided or gets and sends an new getUserMedia stream.
 * @param {SkylinkState} roomState
 * @param {MediaStream|Object} options
 * @memberOf MediaStreamHelpers
 * @fires onIncomingStream, peerUpdated
 */
// eslint-disable-next-line consistent-return
const sendStream = (roomState, options = null) => new Promise((resolve, reject) => {
  if (!roomState) {
    return reject(new Error(MESSAGES.ROOM_STATE.NO_ROOM_NAME));
  }

  const { inRoom, streams } = roomState;
  const { AdapterJS } = window;
  const isNotObjOrNullOrPlugin = (!isAObj(options) || options === null) && !(AdapterJS && AdapterJS.WebRTCPlugin && AdapterJS.WebRTCPlugin.plugin);

  if (!inRoom) {
    logger.log.WARN(MESSAGES.ROOM.ERRORS.NOT_IN_ROOM);
    return reject(new Error(`${MESSAGES.ROOM.ERRORS.NOT_IN_ROOM}`));
  }

  if (streams.userMedia) {
    return reject(new Error(MESSAGES.MEDIA_STREAM.ERRORS.ACTIVE_STREAMS));
  }

  if (isNotObjOrNullOrPlugin) {
    return reject(new Error(`${MESSAGES.MEDIA_STREAM.ERRORS.INVALID_GUM_OPTIONS} ${options}`));
  }

  let isTypeStream = false;

  try {
    if (Array.isArray(options)) {
      let isArrayOfTypeStream = true;
      options.forEach((item) => {
        if (!isAFunction(item.getAudioTracks) || !isAFunction(item.getVideoTracks)) {
          isArrayOfTypeStream = false;
        }
      });

      if (!isArrayOfTypeStream) {
        return reject(new Error(MESSAGES.MEDIA_STREAM.ERRORS.INVALID_MEDIA_STREAM_ARRAY));
      }

      return processMediaStreamArray(roomState, options, resolve, reject);
    }

    isTypeStream = options ? (isAFunction(options.getAudioTracks) || isAFunction(options.getVideoTracks)) : false;
    if (isTypeStream) {
      return processMediaStream(roomState, options, resolve, reject);
    }

    return processMediaOptions(roomState, options, resolve, reject);
  } catch (error) {
    logger.log.ERROR(MESSAGES.MEDIA_STREAM.ERRORS.SEND_STREAM, error);
  }
});

export default sendStream;