Your IP : 52.15.140.180


Current Path : /home/bitrix/ext_www/crm.klimatlend.ua/bitrix/js/im/call/
Upload File :
Current File : /home/bitrix/ext_www/crm.klimatlend.ua/bitrix/js/im/call/floating_video.js

;(function () {
	BX.namespace('BX.Call');

	if (BX.Call.FloatingVideo)
	{
		return;
	}

	var Events = {
		setStream: "FloatingVideo::setStream",
		setAudioMuted: "FloatingVideo::setAudioMuted",
		setTitle: "FloatingVideo::setTitle",
		setAvatars: "FloatingVideo::setAvatars",
		setTalking: "FloatingVideo::setTalking",

		onMainAreaClick: "FloatingVideo::onMainAreaClick",
		onMicButtonClick: "FloatingVideo::onMicButtonClick",
		onHangupButtonClick: "FloatingVideo::onHangupButtonClick",

		connectionOffer: "FloatingVideo::connectionOffer",
		connectionAnswer: "FloatingVideo::connectionAnswer",
		connectionClose: "FloatingVideo::connectionClose",
		connectionIceCandidate: "FloatingVideo::connectionIceCandidate",
	};

	var VIDEO_WIDTH = 320;
	var VIDEO_HEIGHT = 180;
	var AUDIO_WIDTH = 320;
	var AUDIO_HEIGHT = 70;

	/**
	 *
	 * @param {object} config
	 * @param {MediaStream} [config.stream]
	 * @param {bool} [config.audioMuted]
	 * @param {function} [config.onMainAreaClick]
	 * @param {function} [config.onButtonClick]
	 * @constructor
	 */
	BX.Call.FloatingVideo = function (config)
	{
		if(typeof(config) !== "object")
		{
			config = {};
		}
		this.stream = config.stream && BX.Call.Util.containsVideoTrack(config.stream) ? config.stream : null;
		this.audioMuted = config.audioMuted || false;

		this.title = config.title || "";
		this.avatars = config.avatars || {};

		this.window = null;
		this.visible = false;
		this.peerConnection = null;

		this.callbacks = {
			onMainAreaClick: BX.type.isFunction(config.onMainAreaClick) ? config.onMainAreaClick : BX.DoNothing,
			onButtonClick: BX.type.isFunction(config.onButtonClick) ? config.onButtonClick : BX.DoNothing
		};

		this._onContentMainAreaClickHandler = this._onContentMainAreaClick.bind(this);
		this._onContentMicButtonClickHandler = this._onContentMicButtonClick.bind(this);
		this._onContentHangupButtonClickHandler = this._onContentHangupButtonClick.bind(this);

		this._onPCNegotiationNeededHandler = this._onPCNegotiationNeeded.bind(this);
		this._onPCIceCandidateHandler = this._onPCIceCandidate.bind(this);
		this._onConnectionAnswerHandler = this._onConnectionAnswer.bind(this);
		this._onConnectionIceCandidateHandler = this._onConnectionIceCandidate.bind(this);

		this.bindEventHandlers();
	};

	BX.Call.FloatingVideo.prototype =
	{
		bindEventHandlers: function ()
		{
			BX.desktop.addCustomEvent(Events.onMainAreaClick, this._onContentMainAreaClickHandler);
			BX.desktop.addCustomEvent(Events.onMicButtonClick, this._onContentMicButtonClickHandler);
			BX.desktop.addCustomEvent(Events.onHangupButtonClick, this._onContentHangupButtonClickHandler);

			BX.desktop.addCustomEvent(Events.connectionAnswer, this._onConnectionAnswerHandler);
			BX.desktop.addCustomEvent(Events.connectionIceCandidate, this._onConnectionIceCandidateHandler);
		},

		_onContentMainAreaClick: function()
		{
			this.callbacks.onMainAreaClick();
		},

		_onContentMicButtonClick: function()
		{
			this.callbacks.onButtonClick({
				buttonName: "toggleMute",
				muted: !this.audioMuted
			})
		},

		_onContentHangupButtonClick: function()
		{
			this.callbacks.onButtonClick({
				buttonName: "hangup"
			})
		},

		setStream: function(stream)
		{
			if(BX.Call.Util.containsVideoTrack(stream))
			{
				this.stream = stream;
			}
			else
			{
				this.stream = null;
			}

			if(this.window && this.visible)
			{
				if(this.stream)
				{
					this.sendVideo();
				}
				else
				{
					this.stopSendingVideo();
				}
			}
		},

		setTitle: function(title)
		{
			this.title = title;
			if(this.window)
			{
				BX.desktop.onCustomEvent(this.window, Events.setTitle, [this.title]);
			}
		},

		setAvatars: function(avatarList)
		{
			this.avatars = avatarList;
			if(this.window && this.visible)
			{
				BX.desktop.onCustomEvent(this.window, Events.setAvatars, [this.avatars]);
			}
		},

		setTalking: function(talking)
		{
			if(this.window)
			{
				BX.desktop.onCustomEvent(this.window, Events.setTalking, [talking]);
			}
		},

		sendVideo: function()
		{
			if(!this.peerConnection)
			{
				this.peerConnection = new RTCPeerConnection();
				this.peerConnection.addEventListener("negotiationneeded", this._onPCNegotiationNeededHandler);
				this.peerConnection.addEventListener("icecandidate", this._onPCIceCandidateHandler);
			}
			this.peerConnection.addTrack(this.stream.getVideoTracks()[0], this.stream);
		},

		_onPCNegotiationNeeded: function()
		{
			var connectionOffer;
			this.peerConnection.createOffer().then(function(offer)
			{
				connectionOffer = offer;
				return this.peerConnection.setLocalDescription(offer)
			}.bind(this)).then(function()
			{
				BX.desktop.onCustomEvent(this.window, Events.connectionOffer, [connectionOffer.sdp]);
			}.bind(this));
		},

		_onPCIceCandidate: function(e)
		{
			var candidate = e.candidate;
			if(candidate)
			{
				BX.desktop.onCustomEvent(this.window, Events.connectionIceCandidate, [candidate.toJSON()]);
			}
		},

		_onConnectionAnswer: function(sdp)
		{
			if(this.peerConnection)
			{
				var sessionDescription = new RTCSessionDescription({
					type: "answer",
					sdp: sdp
				});

				this.peerConnection.setRemoteDescription(sessionDescription);
			}
		},

		_onConnectionIceCandidate: function(candidate)
		{
			if(this.peerConnection)
			{
				this.peerConnection.addIceCandidate(candidate);
			}
		},

		stopSendingVideo: function()
		{
			if(this.peerConnection)
			{
				this.peerConnection.close();
				this.peerConnection.removeEventListener("negotiationneeded", this._onPCNegotiationNeededHandler);
				this.peerConnection.removeEventListener("icecandidate", this._onPCIceCandidateHandler);
				this.peerConnection = null;
			}

			BX.desktop.onCustomEvent(this.window, Events.connectionClose, []);
		},

		setAudioMuted: function(audioMuted)
		{
			if(this.audioMuted == audioMuted)
			{
				return;
			}

			this.audioMuted = audioMuted;

			if(this.window && this.visible)
			{
				BX.desktop.onCustomEvent(this.window, Events.setAudioMuted, [this.audioMuted]);
			}
		},

		show: function ()
		{
			if (!BX.desktop)
			{
				return;
			}

			if(this.window)
			{
				this.window.BXDesktopWindow.ExecuteCommand("show");
				BX.desktop.onCustomEvent(this.window, Events.setAudioMuted, [this.audioMuted]);
				BX.desktop.onCustomEvent(this.window, Events.setAvatars, [this.avatars]);
				if(this.stream)
				{
					this.sendVideo();
				}
			}
			else
			{
				var params = {
					audioMuted: this.audioMuted,
					title: this.title,
					avatars: this.avatars
				};

				this.window = BXDesktopSystem.ExecuteCommand('topmost.show.html', BX.desktop.getHtmlPage("", "window.FVC = new BX.Call.FloatingVideoContent(" + JSON.stringify(params) + ");"));
				setTimeout(function()
				{
					if(this.stream && this.visible)
					{
						this.sendVideo();
					}
				}.bind(this), 2000)
			}

			this.visible = true;
		},

		hide: function ()
		{
			if (!this.window || !this.window.document)
			{
				return false;
			}
			this.stopSendingVideo();
			this.window.BXDesktopWindow.ExecuteCommand("hide");
			this.visible = false;
		},

		close: function ()
		{
			if (!this.window || !this.window.document)
			{
				return false;
			}

			this.window.BXDesktopWindow.ExecuteCommand("close");
			this.window = null;
			this.visible = false;
		},

		destroy: function ()
		{
			if(this.window)
			{
				this.window.BXDesktopWindow.ExecuteCommand("close");
				this.window = null;
			}

			this.stream = null;

			BX.desktop.removeCustomEvents(Events.onMainAreaClick);
			BX.desktop.removeCustomEvents(Events.onMicButtonClick);
			BX.desktop.removeCustomEvents(Events.onHangupButtonClick);
		}
	};

	BX.Call.FloatingVideoContent = function (config)
	{
		this.stream = config.stream;
		this.audioMuted = config.audioMuted;

		this.avatars = config.avatars || {};
		this.title = config.title || "";
		this.talking = [];

		this.elements = {
			container: null,
			video: null,
			avatars: null,
			title: null,
			micButton: null,
			micButtonText: null,
			hangupButton: null
		};

		this.render();
		this.adjustWindow();
		this.bindEventHandlers();

		this.callAspectHorizontal = true;

		if (this.stream)
		{
			this.callAspectCheckInterval = setInterval(this.checkVideoAspect.bind(this), 500);
		}

		this.slavePeerConnection = null;
		this._onSlavePCIceCandidateHandler = this._onSlavePCIceCandidate.bind(this);
		this._onSlavePCIceConnectionStateChangeHandler = this._onSlavePCIceConnectionStateChange.bind(this);
	};

	BX.Call.FloatingVideoContent.prototype = {
		bindEventHandlers: function () {
			BX.desktop.addCustomEvent(Events.setStream, this.setStream.bind(this));
			BX.desktop.addCustomEvent(Events.setAudioMuted, this.setAudioMuted.bind(this));
			BX.desktop.addCustomEvent(Events.setTitle, this.setTitle.bind(this));
			BX.desktop.addCustomEvent(Events.setAvatars, this.setAvatars.bind(this));
			BX.desktop.addCustomEvent(Events.setTalking, this.setTalking.bind(this));

			BX.desktop.addCustomEvent(Events.connectionOffer, this._onConnectionOfferFromMain.bind(this));
			BX.desktop.addCustomEvent(Events.connectionIceCandidate, this._onIceCandidateFromMain.bind(this));
			BX.desktop.addCustomEvent(Events.connectionClose, this._onRTCconnectionClose.bind(this));

			window.addEventListener("beforeunload", this.destroy.bind(this));
		},

		render: function () {
			var minCallWidth = this.stream ? VIDEO_WIDTH : AUDIO_WIDTH;
			var minCallHeight = this.stream ? VIDEO_HEIGHT : AUDIO_HEIGHT;

			var callOverlayStyle = {
				width: minCallWidth + 'px',
				height: minCallHeight + 'px'
			};

			this.elements.container = BX.create("div", {
				props: {className: 'bx-messenger-call-float' + (this.stream ? '' : ' bx-messenger-call-float-audio')},
				style: callOverlayStyle,
				events: {
					click: this.onMainAreaClick.bind(this)
				},
				children: [
					BX.create("div", {
						props: {
							className: 'bx-messenger-call-float-audio-unfold'
						},
						children: [
							this.elements.avatars = BX.create("div", {
								props: {className: 'bx-messenger-call-float-avatars'},
							}),
							this.elements.title = BX.create("span", {
								props: {className: 'bx-messenger-call-float-button-text'},
								text: this.title
							})
						]
					}),
					BX.create("div", {
						props: {className: 'bx-messenger-call-float-buttons'},
						children: [
							this.elements.micButton = BX.create("div", {
								props: {className: 'bx-messenger-call-float-button bx-messenger-call-float-button-mic' + (this.audioMuted ? ' bx-messenger-call-float-button-mic-disabled' : '')},
								events: {
									click: this.onMicButtonClick.bind(this)
								},
								children: [
									BX.create("span", {props: {className: 'bx-messenger-call-float-button-icon'}}),
									this.elements.micButtonText = BX.create("span", {
										props: {className: 'bx-messenger-call-float-button-text'},
										text: BX.message('IM_M_CALL_BTN_MIC') + ' ' + BX.message('IM_M_CALL_BTN_MIC_' + (this.audioMuted ? 'OFF' : 'ON'))
									})
								]
							}),
							this.elements.hangupButton = BX.create("div", {
								props: {className: 'bx-messenger-call-float-button bx-messenger-call-float-button-decline'},
								events: {
									click: this.onHangupButtonClick.bind(this)
								},
								children: [
									BX.create("span", {props: {className: 'bx-messenger-call-float-button-icon'}}),
									BX.create("span", {
										props: {className: 'bx-messenger-call-float-button-text'},
										text: BX.message('IM_M_CALL_BTN_HANGUP')
									})
								]
							})
						]
					})
				]
			});

			this.elements.video = BX.create("video", {
				attrs: {
					autoplay: true,
					src: this.stream,

				},
				props: {className: 'bx-messenger-call-float-video', volume: 0},

			});

			if(this.stream)
			{
				BX.prepend(this.elements.video, this.elements.container);
			}

			this.setAvatars(this.avatars);

			document.body.appendChild(this.elements.container);
		},

		adjustWindow: function (width, height)
		{
			var minCallWidth = this.stream ? VIDEO_WIDTH : AUDIO_WIDTH;
			var minCallHeight = this.stream ? VIDEO_HEIGHT : AUDIO_HEIGHT;

			width = width || minCallWidth;
			height = height || minCallHeight;

			if(!this.stream)
			{
				var rows = Math.ceil(Object.keys(this.avatars).length / 4);
				height += rows * 74 + 10; // avatar height + top padding
			}

			this.elements.container.style.width = width +"px";
			this.elements.container.style.height = height +"px";

			BX.desktop.setWindowMinSize({Width: width, Height: height});
			BX.desktop.setWindowResizable(false);
			BX.desktop.setWindowClosable(false);
			BX.desktop.setWindowResizable(false);
			BX.desktop.setWindowTitle(this.title);

			if (BXDesktopSystem.QuerySettings('global_topmost_x', null))
			{
				BX.desktop.setWindowPosition({
					X: parseInt(BXDesktopSystem.QuerySettings('global_topmost_x', STP_RIGHT)),
					Y: parseInt(BXDesktopSystem.QuerySettings('global_topmost_y', STP_TOP)),
					Width: width,
					Height: height,
					Mode: STP_FRONT
				});
				if (!BX.browser.IsMac())
					BX.desktop.setWindowPosition({
						X: parseInt(BXDesktopSystem.QuerySettings('global_topmost_x', STP_RIGHT)),
						Y: parseInt(BXDesktopSystem.QuerySettings('global_topmost_y', STP_TOP)),
						Width: width,
						Height: height,
						Mode: STP_FRONT
					});
			}
			else
			{
				BX.desktop.setWindowPosition({
					X: STP_RIGHT,
					Y: STP_TOP,
					Width: width,
					Height: height,
					Mode: STP_FRONT
				});
				if (!BX.browser.IsMac())
					BX.desktop.setWindowPosition({
						X: STP_RIGHT,
						Y: STP_TOP,
						Width: width,
						Height: height,
						Mode: STP_FRONT
					});
			}
		},

		checkVideoAspect: function()
		{
			if (this.elements.video.videoWidth < this.elements.video.videoHeight)
			{
				if (this.callAspectHorizontal)
				{
					this.callAspectHorizontal = false;
					BX.addClass(this.elements.container, 'bx-messenger-call-overlay-aspect-vertical');
					BX.desktop.setWindowSize({
						Width: VIDEO_HEIGHT,
						Height: VIDEO_WIDTH
					});
				}
			}
			else
			{
				if (!this.callAspectHorizontal)
				{
					this.callAspectHorizontal = true;
					BX.removeClass(this.elements.container, 'bx-messenger-call-overlay-aspect-vertical');
					BX.desktop.setWindowSize({
						Width: VIDEO_WIDTH,
						Height: VIDEO_HEIGHT
					});
				}
			}
		},

		_onConnectionOfferFromMain: function(sdp)
		{
			if(this.slavePeerConnection)
			{
				//remove events
				this.slavePeerConnection.removeEventListener("icecandidate", this._onSlavePCIceCandidateHandler);
				this.slavePeerConnection.removeEventListener("iceconnectionstatechange", this._onSlavePCIceConnectionStateChangeHandler);

				this.slavePeerConnection.close();
			}

			this.slavePeerConnection = new RTCPeerConnection();
			this.slavePeerConnection.addEventListener("icecandidate", this._onSlavePCIceCandidateHandler);
			this.slavePeerConnection.addEventListener("iceconnectionstatechange", this._onSlavePCIceConnectionStateChangeHandler);

			var sessionDescription = new RTCSessionDescription({
				type: "offer",
				sdp: sdp
			});

			this.slavePeerConnection.setRemoteDescription(sessionDescription).then(
				function()
				{
					if(this.slavePeerConnection)
					{
						this.slavePeerConnection.createAnswer(/*{offerToReceiveVideo: true}*/).then(
							function(answer)
							{
								this.slavePeerConnection.setLocalDescription(answer);
								BX.desktop.onCustomEvent("main", Events.connectionAnswer, [answer.sdp]);
							}.bind(this)
						)
					}
				}.bind(this)
			)
		},

		_onIceCandidateFromMain: function(candidate)
		{
			setTimeout(function()
			{
				if(this.slavePeerConnection)
				{
					this.slavePeerConnection.addIceCandidate(candidate);
				}
			}.bind(this), 200);
		},

		_onRTCconnectionClose: function()
		{
			if(this.slavePeerConnection)
			{
				this.slavePeerConnection.removeEventListener("icecandidate", this._onSlavePCIceCandidateHandler);
				this.slavePeerConnection.removeEventListener("iceconnectionstatechange", this._onSlavePCIceConnectionStateChangeHandler);
				this.slavePeerConnection.close();
				this.slavePeerConnection = null;
			}
			this.setStream(null);
		},

		_onSlavePCIceCandidate: function(e)
		{
			var candidate = e.candidate;
			if (candidate)
			{
				BX.desktop.onCustomEvent("main", Events.connectionIceCandidate, [candidate.toJSON()]);
			}
		},

		_onSlavePCIceConnectionStateChange: function(e)
		{
			if(this.slavePeerConnection.iceConnectionState === "connected")
			{
				this.setStream(this.slavePeerConnection.getRemoteStreams()[0]);
			}
			else if(this.slavePeerConnection.iceConnectionState === "disconnected")
			{
				this.setStream(null);

				this.slavePeerConnection.removeEventListener("icecandidate", this._onSlavePCIceCandidateHandler);
				this.slavePeerConnection.removeEventListener("iceconnectionstatechange", this._onSlavePCIceConnectionStateChangeHandler);
			}
		},

		setStream: function(stream)
		{
			clearInterval(this.callAspectCheckInterval);
			this.stream = stream;

			var minCallWidth = this.stream ? VIDEO_WIDTH : AUDIO_WIDTH;
			var minCallHeight = this.stream ? VIDEO_HEIGHT : AUDIO_HEIGHT;

			var callOverlayStyle = {
				width: minCallWidth + 'px',
				height: minCallHeight + 'px'
			};

			if(this.elements.container)
			{
				if(this.stream)
				{
					if(!this.elements.video.parentNode)
					{
						BX.prepend(this.elements.video, this.elements.container);
						BX.removeClass(this.elements.container, "bx-messenger-call-float-audio");
					}
					this.elements.video.srcObject = this.stream;
				}
				else
				{
					BX.remove(this.elements.video);
					BX.addClass(this.elements.container, "bx-messenger-call-float-audio");
				}

				BX.adjust(this.elements.container, {style: callOverlayStyle});
			}

			if(this.stream)
			{
				this.callAspectCheckInterval = setInterval(this.checkVideoAspect.bind(this), 500);
			}

			this.adjustWindow();
		},

		setAudioMuted: function(audioMuted)
		{
			this.audioMuted = audioMuted;

			if(this.audioMuted)
			{
				BX.addClass(this.elements.micButton, "bx-messenger-call-float-button-mic-disabled");
				BX.adjust(this.elements.micButtonText, {text: BX.message('IM_M_CALL_BTN_MIC') + ' ' + BX.message('IM_M_CALL_BTN_MIC_OFF')});
			}
			else
			{
				BX.removeClass(this.elements.micButton, "bx-messenger-call-float-button-mic-disabled");
				BX.adjust(this.elements.micButtonText, {text: BX.message('IM_M_CALL_BTN_MIC') + ' ' + BX.message('IM_M_CALL_BTN_MIC_ON')});
			}
		},

		setTitle: function(title)
		{
			this.title = title;
			this.elements.title.innerText = title;
			BX.desktop.setWindowTitle(this.title);
		},

		setAvatars: function(avatars)
		{
			this.avatars = avatars;

			this.elements.avatars.innerHTML = "";

			for (var userId in this.avatars)
			{
				var avatar = this.avatars[userId];
				var a = BX.create("div", {
					props: {className: "bx-messenger-call-float-avatar"},
					dataset: {
						userId: userId
					}
				});

				if (avatar != '')
				{
					a.style.backgroundImage = "url('" + avatar + "')";
				}

				this.elements.avatars.appendChild(a);
			}

			this.adjustWindow();
		},

		setTalking: function(talking)
		{
			this.talking = talking;

			if(this.elements.avatars)
			{
				for(var i = 0; i < this.elements.avatars.children.length; i++)
				{
					var element = this.elements.avatars.children[i];
					var userId = Number(element.dataset.userId);
					if (this.talking.includes(userId))
					{
						element.classList.add("talking");
					}
					else
					{
						//element.classList.add("talking");
						element.classList.remove("talking");
					}
				}
			}
		},

		onMainAreaClick: function(e)
		{
			BX.desktop.onCustomEvent("main", Events.onMainAreaClick, []);
			e.stopPropagation();
		},

		onMicButtonClick: function(e)
		{
			BX.desktop.onCustomEvent("main", Events.onMicButtonClick, [this.audioMuted]);

			e.stopPropagation();
		},

		onHangupButtonClick: function(e)
		{
			BX.desktop.onCustomEvent("main", Events.onHangupButtonClick, []);

			e.stopPropagation();
		},

		destroy: function()
		{
			this.stream = null;
			BX.desktop.removeCustomEvents(Events.setStream);
			BX.desktop.removeCustomEvents(Events.setAudioMuted);
		}
	};

})();