Home Reference Source

src/PeerConnectionHandler.js

import Context from './Context';
import Health from './Health';
import util from './Util';
import RemonRecorder from './RemonRecorder';
import Recorder from './Recorder';
import l from './Logger';

function bindPeerConnectionEvents({
  context,
  media,
}) {
  function handleIceCandidateEvent(event) {
    l.i('PeerCon: HandleICECandidateEvent');
    l.d('Event:', event);
    l.d('-> Candidate:', event.candidate);

    const message = context.signalingConnection.createMessage({ command: 'ice', body: JSON.stringify(event.candidate) });

    if (event.candidate) {
      l.i('Message ->: ', message);
      if (context.channel.type==="BROADCAST"){
        message.channel.type="BROADCAST";
      }
      if (typeof message !=='undefined')context.signalingConnection.send(JSON.stringify(message));
    }
  }

  function handleIceGatheringStateChangeEvent() {
    l.i('PeerCon: Handle ice gathering state event');
    l.d(`Event: ${context.peerConnection.iceGatheringState}:`, event);
  }



  function handleSignalingStateChangeEvent(event) {
    l.i('PeerCon: Handle signaling state change event');
    l.d(`Event: ${context.peerConnection.signalingState}:`, event);
    switch (context.peerConnection.signalingState) {
      case 'stable': {
        context.endTime = new Date().getTime();
        if (context.eventManager.hasEventListener('onAddRemoteStream')) {
          context.eventManager.dispatchEvent('onAddRemoteStream', context.remoteStream);
        }
        break;
      }
      case 'have-local-offer': { break; }
      case 'have-remote-offer': { break; }
      case 'have-local-pranswer': { break; }
      case 'have-remote-pranswer': { break; }
      case 'closed': { break; }
      default: {
        l.e('Unknown signaling state event:', context.peerConnection.signalingState);
        break;
      }
    }
  }

  function handleNegotiationNeededEvent(event) {
    l.i('PeerCon: Handle negotiation needed event');
    l.d('Event:', event);
  }

  function handleIceConnectionStateChangeEvent(event) {
    l.i('PeerCon: Handle ICE state change event');
    l.v(`Event: ${context.peerConnection.iceConnectionState}:`, event);

    let message;
    switch (context.peerConnection.iceConnectionState) {
      case 'connected': {
        l.i('ice State:connected');
        if (context.eventManager.hasEventListener('onStateChange')) { context.eventManager.dispatchEvent('onStateChange', 'COMPLETE'); }
        if (context.eventManager.hasEventListener('onComplete')) { context.eventManager.dispatchEvent('onComplete'); }
        message = context.signalingConnection.createMessage({ command: 'stateChange', body: 'COMPLETE' });
        var health = new Health(context);
        health.getStats(util.bind(function(stats){
          this.oldStats = stats;
        },health));
        health.start();
        context.health = health;
        if (context.channel.type==="BROADCAST" || context.channel.type ==="VIEWER")return;
        break;
      }
      case 'failed': {
        // 간혹 browser가 refresh될때 netty는 이것을 감지못하나 ice failed가 발생한다. 이것 역시 상대 peer로부터 발생한 close이벤트라고 판단해야할까?
        l.i('ice State:failed');
        if (context.eventManager.hasEventListener('onError')) { context.eventManager.dispatchEvent('onError', 'ICEFailedError'); }
        l.e('Ice connection state change failed');
        context.health.stop();
        if (context.useRecord) {
          context.remoteRecorder.stop();
          context.localRecorder.stop();
          context.useRecord=false;
        }
        context.peerConnection.close();
        //context.signalingConnection.close();
        // 상대편이 뭔가 문제가 있어서 그런듯 한데 굳이 보내야? 하긴 signal server는 모르고 있을 듯.
        message = context.signalingConnection.createMessage({ command: 'stateChange', body: 'FAIL' });
        break;
      }
      case 'closed': {
        l.i('ice State:closed');
        return;
        //message = context.signalingConnection.createMessage({ command: 'stateChange', body: 'CLOSE' });
        break;
      }
      case 'disconnected': {
        l.i('ice State:disconnected');
        message = context.signalingConnection.createMessage({ command: 'stateChange', body: 'CLOSE' });
        break;
      }
      case 'completed': { l.v('iceconState:completed');break; }
      case 'checking': { l.v('iceconState:checking');break; }
      default: {
        l.e('Unknown ice connection change event:', context.peerConnection.iceConnectionState);
        break;
      }
    }
    l.v('Message ->:', message);
    l.i('Sending ice state to other');
    if (typeof message !== 'undefined')
    context.signalingConnection.send(JSON.stringify(message));

  }

  function handleRemoveStreamEvent(event) {
    l.v('PeerCon: Handle remove stream event');
  }
  function handleRemoteStreamEvent(event) {
    l.g('PeerCon: Bind remote stream');
    l.v('bindRemoteStream:', event);

    let stream;
    // FIXME: Chrome, adapter does not support addTrack
    if (context.hasAddTrack) {
      l.v("PeerCon: context has track");
      stream = event.streams[0];
    } else {
      l.v("PeerCon: context has stream");
      stream = event.stream;
    }
    l.v('Stream:', stream);
    context.remoteVideo.srcObject = stream;
    context.remoteStream = stream;

    // window.AudioContext = window.AudioContext || window.webkitAudioContext;
    //   navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;
    //   window.URL = window.URL || window.webkitURL;
    //context.remonRecorder = new Recorder((new window.AudioContext).createMediaStreamSource(stream));
    //context.remonRecorder.record();
    if (context.useRecord){
      context.remoteRecorder = new RemonRecorder(context, stream,"RR");
      context.remoteRecorder.start();
      context.localRecorder.start();
    }
    l.gEnd();
  }
  /* eslint-disable no-param-reassign */
  context.peerConnection.onicecandidate = handleIceCandidateEvent;
  context.peerConnection.onicegatheringstatechange = handleIceGatheringStateChangeEvent;
  context.peerConnection.onsignalingstatechange = handleSignalingStateChangeEvent;
  context.peerConnection.onnegotiationneeded = handleNegotiationNeededEvent;
  context.peerConnection.oniceconnectionstatechange = handleIceConnectionStateChangeEvent;
  // FIXME: Chrome, adapter does not support addTrack
  // NOTE: ontrack called twice. Maybe for audio, video. Is it right?
  if (context.hasAddTrack) {
    l.v("PeerCon: context has addTrack");
    context.peerConnection.ontrack = handleRemoteStreamEvent;
  } else {
    l.v("PeerCon: context has onAddstream");
    context.peerConnection.onaddstream = handleRemoteStreamEvent;
  }
  context.peerConnection.onremovestream = handleRemoveStreamEvent;
  /* eslint-enable no-param-reassign */
}

export default bindPeerConnectionEvents;