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;