'use strict';
var remoteVideo = $('#remote-video');
var UI_CONSTANTS = {
confirmJoinButton: '#confirm-join-button',
confirmJoinDiv: '#confirm-join-div',
confirmJoinRoomSpan: '#confirm-join-room-span',
fullscreenSvg: '#fullscreen',
hangupSvg: '#hangup',
icons: '#icons',
infoDiv: '#info-div',
localVideo: '#local-video',
miniVideo: '#mini-video',
muteAudioSvg: '#mute-audio',
muteVideoSvg: '#mute-video',
newRoomButton: '#new-room-button',
newRoomLink: '#new-room-link',
privacyLinks: '#privacy',
remoteVideo: '#remote-video',
rejoinButton: '#rejoin-button',
rejoinDiv: '#rejoin-div',
rejoinLink: '#rejoin-link',
roomLinkHref: '#room-link-href',
roomSelectionDiv: '#room-selection',
roomSelectionInput: '#room-id-input',
roomSelectionInputLabel: '#room-id-input-label',
roomSelectionJoinButton: '#join-button',
roomSelectionRandomButton: '#random-button',
roomSelectionRecentList: '#recent-rooms-list',
sharingDiv: '#sharing-div',
statusDiv: '#status-div',
turnInfoDiv: '#turn-info-div',
videosDiv: '#videos',
};
var AppController = function(loadingParams) {
trace('Initializing; server= ' + loadingParams.roomServer + '.');
trace('Initializing; room=' + loadingParams.roomId + '.');
this.hangupSvg_ = $(UI_CONSTANTS.hangupSvg);
this.icons_ = $(UI_CONSTANTS.icons);
this.localVideo_ = $(UI_CONSTANTS.localVideo);
this.miniVideo_ = $(UI_CONSTANTS.miniVideo);
this.sharingDiv_ = $(UI_CONSTANTS.sharingDiv);
this.statusDiv_ = $(UI_CONSTANTS.statusDiv);
this.turnInfoDiv_ = $(UI_CONSTANTS.turnInfoDiv);
this.remoteVideo_ = $(UI_CONSTANTS.remoteVideo);
this.videosDiv_ = $(UI_CONSTANTS.videosDiv);
this.roomLinkHref_ = $(UI_CONSTANTS.roomLinkHref);
this.rejoinDiv_ = $(UI_CONSTANTS.rejoinDiv);
this.rejoinLink_ = $(UI_CONSTANTS.rejoinLink);
this.newRoomLink_ = $(UI_CONSTANTS.newRoomLink);
this.rejoinButton_ = $(UI_CONSTANTS.rejoinButton);
this.newRoomButton_ = $(UI_CONSTANTS.newRoomButton);
this.muteAudioIconSet_ =
new AppController.IconSet_(UI_CONSTANTS.muteAudioSvg);
this.muteVideoIconSet_ =
new AppController.IconSet_(UI_CONSTANTS.muteVideoSvg);
this.fullscreenIconSet_ =
new AppController.IconSet_(UI_CONSTANTS.fullscreenSvg);
this.loadingParams_ = loadingParams;
this.loadUrlParams_();
var paramsPromise = Promise.resolve({});
Promise.resolve(paramsPromise).then(function(newParams) {
if (newParams) {
Object.keys(newParams).forEach(function(key) {
this.loadingParams_[key] = newParams[key];
}.bind(this));
}
this.newRoomButton_.addEventListener('click',
this.onNewRoomClick_.bind(this), false);
this.rejoinButton_.addEventListener('click',
this.onRejoinClick_.bind(this), false);
this.roomLink_ = '';
this.roomSelection_ = null;
this.localStream_ = null;
this.remoteVideoResetTimer_ = null;
if (this.loadingParams_.roomId) {
this.createCall_();
if (!RoomSelection.matchRandomRoomPattern(this.loadingParams_.roomId)) {
$(UI_CONSTANTS.confirmJoinRoomSpan).textContent = ' "' +
this.loadingParams_.roomId + '"';
}
var confirmJoinDiv = $(UI_CONSTANTS.confirmJoinDiv);
this.show_(confirmJoinDiv);
$(UI_CONSTANTS.confirmJoinButton).onclick = function() {
this.hide_(confirmJoinDiv);
var recentlyUsedList = new RoomSelection.RecentlyUsedList();
recentlyUsedList.pushRecentRoom(this.loadingParams_.roomId);
this.finishCallSetup_(this.loadingParams_.roomId);
}.bind(this);
if (this.loadingParams_.bypassJoinConfirmation) {
$(UI_CONSTANTS.confirmJoinButton).onclick();
}
} else {
this.showRoomSelection_();
}
}.bind(this)).catch(function(error) {
trace('Error initializing: ' + error.message);
}.bind(this));
};
AppController.prototype.createCall_ = function() {
var privacyLinks = $(UI_CONSTANTS.privacyLinks);
this.hide_(privacyLinks);
this.call_ = new Call(this.loadingParams_);
this.infoBox_ = new InfoBox($(UI_CONSTANTS.infoDiv), this.call_,
this.loadingParams_.versionInfo);
var roomErrors = this.loadingParams_.errorMessages;
var roomWarnings = this.loadingParams_.warningMessages;
if (roomErrors && roomErrors.length > 0) {
for (var i = 0; i < roomErrors.length; ++i) {
this.infoBox_.pushErrorMessage(roomErrors[i]);
}
return;
} else if (roomWarnings && roomWarnings.length > 0) {
for (var j = 0; j < roomWarnings.length; ++j) {
this.infoBox_.pushWarningMessage(roomWarnings[j]);
}
}
this.call_.onremotehangup = this.onRemoteHangup_.bind(this);
this.call_.onremotesdpset = this.onRemoteSdpSet_.bind(this);
this.call_.onremotestreamadded = this.onRemoteStreamAdded_.bind(this);
this.call_.onlocalstreamadded = this.onLocalStreamAdded_.bind(this);
this.call_.onsignalingstatechange =
this.infoBox_.updateInfoDiv.bind(this.infoBox_);
this.call_.oniceconnectionstatechange =
this.infoBox_.updateInfoDiv.bind(this.infoBox_);
this.call_.onnewicecandidate =
this.infoBox_.recordIceCandidateTypes.bind(this.infoBox_);
this.call_.onerror = this.displayError_.bind(this);
this.call_.onturnstatusmessage = this.displayTurnStatus_.bind(this);
this.call_.oncallerstarted = this.displaySharingInfo_.bind(this);
};
AppController.prototype.showRoomSelection_ = function() {
var roomSelectionDiv = $(UI_CONSTANTS.roomSelectionDiv);
this.roomSelection_ = new RoomSelection(roomSelectionDiv, UI_CONSTANTS);
this.show_(roomSelectionDiv);
this.roomSelection_.onRoomSelected = function(roomName) {
this.hide_(roomSelectionDiv);
this.createCall_();
this.finishCallSetup_(roomName);
this.roomSelection_.removeEventListeners();
this.roomSelection_ = null;
if (this.localStream_) {
this.attachLocalStream_();
}
}.bind(this);
};
AppController.prototype.setupUi_ = function() {
this.iconEventSetup_();
document.onkeypress = this.onKeyPress_.bind(this);
window.onmousemove = this.showIcons_.bind(this);
$(UI_CONSTANTS.muteAudioSvg).onclick = this.toggleAudioMute_.bind(this);
$(UI_CONSTANTS.muteVideoSvg).onclick = this.toggleVideoMute_.bind(this);
$(UI_CONSTANTS.fullscreenSvg).onclick = this.toggleFullScreen_.bind(this);
$(UI_CONSTANTS.hangupSvg).onclick = this.hangup_.bind(this);
setUpFullScreen();
};
AppController.prototype.finishCallSetup_ = function(roomId) {
this.call_.start(roomId);
this.setupUi_();
window.onbeforeunload = function() {
this.call_.hangup(false);
}.bind(this);
window.onpopstate = function(event) {
if (!event.state) {
trace('Reloading main page.');
location.href = location.origin;
} else {
if (event.state.roomLink) {
location.href = event.state.roomLink;
}
}
};
};
AppController.prototype.hangup_ = function() {
trace('Hanging up.');
this.hide_(this.icons_);
this.displayStatus_('Hanging up');
this.transitionToDone_();
this.call_.hangup(true);
document.onkeypress = null;
window.onmousemove = null;
};
AppController.prototype.onRemoteHangup_ = function() {
this.displayStatus_('The remote side hung up.');
this.transitionToWaiting_();
this.call_.onRemoteHangup();
};
AppController.prototype.onRemoteSdpSet_ = function(hasRemoteVideo) {
if (hasRemoteVideo) {
trace('Waiting for remote video.');
this.waitForRemoteVideo_();
} else {
trace('No remote video stream; not waiting for media to arrive.');
this.transitionToActive_();
}
};
AppController.prototype.waitForRemoteVideo_ = function() {
if (this.remoteVideo_.readyState >= 2) { trace('Remote video started; currentTime: ' +
this.remoteVideo_.currentTime);
this.transitionToActive_();
} else {
this.remoteVideo_.oncanplay = this.waitForRemoteVideo_.bind(this);
}
};
AppController.prototype.onRemoteStreamAdded_ = function(stream) {
this.deactivate_(this.sharingDiv_);
this.displayTurnStatus_('');
trace('Remote stream added.');
this.remoteVideo_.srcObject = stream;
this.infoBox_.getRemoteTrackIds(stream);
if (this.remoteVideoResetTimer_) {
clearTimeout(this.remoteVideoResetTimer_);
this.remoteVideoResetTimer_ = null;
}
};
AppController.prototype.onLocalStreamAdded_ = function(stream) {
trace('User has granted access to local media.');
this.localStream_ = stream;
this.infoBox_.getLocalTrackIds(this.localStream_);
if (!this.roomSelection_) {
this.attachLocalStream_();
}
};
AppController.prototype.attachLocalStream_ = function() {
trace('Attaching local stream.');
this.localVideo_.srcObject = this.localStream_;
this.displayStatus_('');
this.activate_(this.localVideo_);
this.show_(this.icons_);
if (this.localStream_.getVideoTracks().length === 0) {
this.hide_($(UI_CONSTANTS.muteVideoSvg));
}
if (this.localStream_.getAudioTracks().length === 0) {
this.hide_($(UI_CONSTANTS.muteAudioSvg));
}
};
AppController.prototype.transitionToActive_ = function() {
this.remoteVideo_.oncanplay = undefined;
var connectTime = window.performance.now();
this.infoBox_.setSetupTimes(this.call_.startTime, connectTime);
this.infoBox_.updateInfoDiv();
trace('Call setup time: ' + (connectTime - this.call_.startTime).toFixed(0) +
'ms.');
trace('reattachMediaStream: ' + this.localVideo_.srcObject);
this.miniVideo_.srcObject = this.localVideo_.srcObject;
this.activate_(this.remoteVideo_);
this.activate_(this.miniVideo_);
this.deactivate_(this.localVideo_);
this.localVideo_.srcObject = null;
this.activate_(this.videosDiv_);
this.show_(this.hangupSvg_);
this.displayStatus_('');
};
AppController.prototype.transitionToWaiting_ = function() {
this.remoteVideo_.oncanplay = undefined;
this.hide_(this.hangupSvg_);
this.deactivate_(this.videosDiv_);
if (!this.remoteVideoResetTimer_) {
this.remoteVideoResetTimer_ = setTimeout(function() {
this.remoteVideoResetTimer_ = null;
trace('Resetting remoteVideo src after transitioning to waiting.');
this.remoteVideo_.srcObject = null;
}.bind(this), 800);
}
this.localVideo_.srcObject = this.miniVideo_.srcObject;
this.activate_(this.localVideo_);
this.deactivate_(this.remoteVideo_);
this.deactivate_(this.miniVideo_);
};
AppController.prototype.transitionToDone_ = function() {
this.remoteVideo_.oncanplay = undefined;
this.deactivate_(this.localVideo_);
this.deactivate_(this.remoteVideo_);
this.deactivate_(this.miniVideo_);
this.hide_(this.hangupSvg_);
this.activate_(this.rejoinDiv_);
this.show_(this.rejoinDiv_);
this.displayStatus_('');
this.displayTurnStatus_('');
};
AppController.prototype.onRejoinClick_ = function() {
this.deactivate_(this.rejoinDiv_);
this.hide_(this.rejoinDiv_);
this.call_.restart();
this.setupUi_();
};
AppController.prototype.onNewRoomClick_ = function() {
this.deactivate_(this.rejoinDiv_);
this.hide_(this.rejoinDiv_);
this.showRoomSelection_();
};
AppController.prototype.onKeyPress_ = function(event) {
switch (String.fromCharCode(event.charCode)) {
case ' ':
case 'm':
if (this.call_) {
this.call_.toggleAudioMute();
this.muteAudioIconSet_.toggle();
}
return false;
case 'c':
if (this.call_) {
this.call_.toggleVideoMute();
this.muteVideoIconSet_.toggle();
}
return false;
case 'f':
this.toggleFullScreen_();
return false;
case 'i':
this.infoBox_.toggleInfoDiv();
return false;
case 'q':
this.hangup_();
return false;
case 'l':
this.toggleMiniVideo_();
return false;
default:
return;
}
};
AppController.prototype.pushCallNavigation_ = function(roomId, roomLink) {
window.history.pushState({'roomId': roomId, 'roomLink': roomLink}, roomId,
roomLink);
};
AppController.prototype.displaySharingInfo_ = function(roomId, roomLink) {
this.roomLinkHref_.href = roomLink;
this.roomLinkHref_.text = roomLink;
this.roomLink_ = roomLink;
this.pushCallNavigation_(roomId, roomLink);
this.activate_(this.sharingDiv_);
};
AppController.prototype.displayStatus_ = function(status) {
if (status === '') {
this.deactivate_(this.statusDiv_);
} else {
this.activate_(this.statusDiv_);
}
this.statusDiv_.innerHTML = status;
};
AppController.prototype.displayTurnStatus_ = function(status) {
if (status === '') {
this.deactivate_(this.turnInfoDiv_);
} else {
this.activate_(this.turnInfoDiv_);
}
this.turnInfoDiv_.innerHTML = status;
};
AppController.prototype.displayError_ = function(error) {
trace(error);
this.infoBox_.pushErrorMessage(error);
};
AppController.prototype.toggleAudioMute_ = function() {
this.call_.toggleAudioMute();
this.muteAudioIconSet_.toggle();
};
AppController.prototype.toggleVideoMute_ = function() {
this.call_.toggleVideoMute();
this.muteVideoIconSet_.toggle();
};
AppController.prototype.toggleFullScreen_ = function() {
if (isFullScreen()) {
trace('Exiting fullscreen.');
document.querySelector('svg#fullscreen title').textContent =
'Enter fullscreen';
document.cancelFullScreen();
} else {
trace('Entering fullscreen.');
document.querySelector('svg#fullscreen title').textContent =
'Exit fullscreen';
document.body.requestFullScreen();
}
this.fullscreenIconSet_.toggle();
};
AppController.prototype.toggleMiniVideo_ = function() {
if (this.miniVideo_.classList.contains('active')) {
this.deactivate_(this.miniVideo_);
} else {
this.activate_(this.miniVideo_);
}
};
AppController.prototype.hide_ = function(element) {
element.classList.add('hidden');
};
AppController.prototype.show_ = function(element) {
element.classList.remove('hidden');
};
AppController.prototype.activate_ = function(element) {
element.classList.add('active');
};
AppController.prototype.deactivate_ = function(element) {
element.classList.remove('active');
};
AppController.prototype.showIcons_ = function() {
if (!this.icons_.classList.contains('active')) {
this.activate_(this.icons_);
this.setIconTimeout_();
}
};
AppController.prototype.hideIcons_ = function() {
if (this.icons_.classList.contains('active')) {
this.deactivate_(this.icons_);
}
};
AppController.prototype.setIconTimeout_ = function() {
if (this.hideIconsAfterTimeout) {
window.clearTimeout.bind(this, this.hideIconsAfterTimeout);
}
this.hideIconsAfterTimeout = window.setTimeout(function() {
this.hideIcons_();
}.bind(this), 5000);
};
AppController.prototype.iconEventSetup_ = function() {
this.icons_.onmouseenter = function() {
window.clearTimeout(this.hideIconsAfterTimeout);
}.bind(this);
this.icons_.onmouseleave = function() {
this.setIconTimeout_();
}.bind(this);
};
AppController.prototype.loadUrlParams_ = function() {
var DEFAULT_VIDEO_CODEC = 'VP9';
var urlParams = queryStringToDictionary(window.location.search);
this.loadingParams_.audioSendBitrate = urlParams['asbr'];
this.loadingParams_.audioSendCodec = urlParams['asc'];
this.loadingParams_.audioRecvBitrate = urlParams['arbr'];
this.loadingParams_.audioRecvCodec = urlParams['arc'];
this.loadingParams_.opusMaxPbr = urlParams['opusmaxpbr'];
this.loadingParams_.opusFec = urlParams['opusfec'];
this.loadingParams_.opusDtx = urlParams['opusdtx'];
this.loadingParams_.opusStereo = urlParams['stereo'];
this.loadingParams_.videoSendBitrate = urlParams['vsbr'];
this.loadingParams_.videoSendInitialBitrate = urlParams['vsibr'];
this.loadingParams_.videoSendCodec = urlParams['vsc'];
this.loadingParams_.videoRecvBitrate = urlParams['vrbr'];
this.loadingParams_.videoRecvCodec = urlParams['vrc'] || DEFAULT_VIDEO_CODEC;
this.loadingParams_.videoFec = urlParams['videofec'];
};
AppController.IconSet_ = function(iconSelector) {
this.iconElement = document.querySelector(iconSelector);
};
AppController.IconSet_.prototype.toggle = function() {
if (this.iconElement.classList.contains('on')) {
this.iconElement.classList.remove('on');
} else {
this.iconElement.classList.add('on');
}
};