UNPKG

kurento-group-call

Version:

Simple javascript library used to initiate a group call (many to many video and audio call) using Kurento Media Server

267 lines (226 loc) 7.95 kB
'use strict'; var logger = require('./logger'); function UserSession(userName, call, sendMessageCallback, sessionId, mediaPipeline) { this.userName = userName; this.call = call; this.sendMessageCallback = sendMessageCallback; this.sessionId = sessionId; this.mediaPipeline = mediaPipeline; this.outgoingMedia = null; this.incomingMedia = {}; } UserSession.prototype.createWebRtcEndpoint = function (callback) { var self = this; if (this.mediaPipeline) { this.mediaPipeline.create('WebRtcEndpoint', function (error, webRtc) { logger.info('create WebRtcEndpoint for ' + self.userName); if (error) { logger.error('failed to create WebRtcEndpoint for user ' + self.userName + ', call ' + self.call.callId); return; } self.outgoingMedia = webRtc; logger.info('WebRtcEndpoint for user ' + self.userName + ', call ' + self.call.callId + ' created.'); callback(); }); } }; UserSession.prototype.getOutgoingWebRtcPeer = function () { return this.outgoingMedia; }; UserSession.prototype.getUserName = function () { return this.userName; }; UserSession.prototype.getCallId = function () { return this.call.callId; }; UserSession.prototype.getSessionId = function () { return this.sessionId; }; function addMidsForFirefox(sdpOffer, sdpAnswer) { var sdpOfferLines = sdpOffer.split('\r\n'); var bundleLine = ''; var audioMid = ''; var videoMid = ''; var nextMid = ''; for (var i = 0; i < sdpOfferLines.length; ++i) { if (sdpOfferLines[i].indexOf('a=group:BUNDLE') === 0) { bundleLine = sdpOfferLines[i]; } else if (sdpOfferLines[i].indexOf('m=') === 0) { nextMid = sdpOfferLines[i].split(' ')[0]; } else if (sdpOfferLines[i].indexOf('a=mid') === 0) { if (nextMid === 'm=audio') { audioMid = sdpOfferLines[i]; } else if (nextMid === 'm=video') { videoMid = sdpOfferLines[i]; } } } return sdpAnswer.replace(/a=group:BUNDLE.*/, bundleLine) .replace(/a=mid:audio/, audioMid) .replace(/a=mid:video/, videoMid); } UserSession.prototype.receiveVideoFrom = function (sender, sdpOffer) { var senderName = sender.getUserName(); logger.info('USER ' + this.userName + ': connecting with ' + senderName + ' in call ' + this.call.callId); logger.info('USER ' + this.userName + ': SdpOffer for ' + senderName + ' is ..'); // + sdpOffer ); var self = this; this.getEndpointForUser(sender, function (webRtc, error) { if (error) { logger.error('ERROR: ' + error); return; } //console.log(webRtc); webRtc.processOffer(sdpOffer, function (error, sdpAnswer) { logger.info('processOffer'); if (error) { logger.error('ERROR: ' + error); return; } //console.log(sdpAnswer) var params = { id: 'receiveVideoAnswer', name: sender.getUserName(), sdpAnswer: addMidsForFirefox(sdpOffer, sdpAnswer), callerId: self.call.callerId }; //logger.info('USER ' + self.userName + ': SdpAnswer for ' + senderName + ' is ' + sdpAnswer ); logger.info('USER ' + self.userName + ': SdpAnswer for ' + senderName + '...'); self.sendMessage(params); }); }); }; UserSession.prototype.getEndpointForUser = function (senderSession, callback) { var senderName = senderSession.getUserName(); if (senderName === this.userName) { logger.info('PARTICIPANT ' + this.userName + ': configuring loopback'); callback(this.outgoingMedia); return; } logger.info('PARTICIPANT ' + this.userName + ': receiving video from ' + senderName); var incoming = this.incomingMedia[senderName]; if (incoming === undefined) { this.createNewEndpointForUser(senderSession, callback); } else { logger.info('PARTICIPANT ' + this.userName + ': using existing endpoint for ' + senderName); //console.log(incoming); callback(incoming); } }; UserSession.prototype.createNewEndpointForUser = function (senderSession, callback) { var senderName = senderSession.getUserName(); logger.info('PARTICIPANT ' + this.userName + ': creating new endpoint for ' + senderName); var self = this; this.mediaPipeline.create('WebRtcEndpoint', function (error, webRtc) { logger.info('create WebRtcEndpoint'); if (error) { logger.error('failed to create WebRtcEndpoint for user ' + self.userName + ', call ' + self.call.callId); return; } self.incomingMedia[senderName] = webRtc; logger.info('PARTICIPANT ' + self.userName + ': obtained endpoint for ' + senderName); senderSession.getOutgoingWebRtcPeer().connect(webRtc, function ( error) { if (error) { //TODO pipeline.release(); logger.info( 'createPipeline: MediaPipeline: WebRtcEndpoint: WebRtcEndpoint: connect: error=' + error); //return callback(error); callback(null, error); return; } callback(webRtc); return; }); }); }; UserSession.prototype.cancelVideoFrom = function (senderName) { logger.info('PARTICIPANT ' + this.userName + ': canceling video reception from ' + senderName); var incoming = this.incomingMedia[senderName]; if (incoming) { delete this.incomingMedia[senderName]; } logger.info('PARTICIPANT ' + this.userName + ': removing endpoint for ' + senderName); // console.log(incoming); var self = this; incoming.release(function (error) { self.logEndpointRelease(error, senderName); }); }; /** * Function does logging if release of one endpoint is successfull or not. */ UserSession.prototype.logEndpointRelease = function (error, participantName) { if (error !== null) { if (participantName) { logger.error('PARTICIPANT ' + this.userName + ': Could not release incoming EndPoint for ' + participantName + ':' + error); } else { logger.error('PARTICIPANT ' + this.userName + ': Could not release outgoing EndPoint: ' + error); } } else { if (participantName) { logger.info('PARTICIPANT ' + this.userName + ': Released successfully incoming endpoint for ' + participantName); } else { logger.error('PARTICIPANT ' + this.userName + ': Released successfully outgoing EndPoint.'); } } }; UserSession.prototype.close = function () { logger.info('PARTICIPANT ' + this.userName + ': Releasing resources'); var self = this; for (var remoteParticipantName in this.incomingMedia) { logger.info('PARTICIPANT ' + remoteParticipantName + ': Released incoming EP for ' + this.userName); var ep = this.incomingMedia[remoteParticipantName]; ep.release(function (error) { self.logEndpointRelease(error, remoteParticipantName); }); } if (this.outgoingMedia !== null) { this.outgoingMedia.release(function (error) { self.logEndpointRelease(error); self.outgoingMedia = null; }); } }; UserSession.prototype.sendMessage = function () { var messageName = 'message'; var message; if (arguments.length == 1) { message = arguments[0]; } else if (arguments.length == 2) { messageName = arguments[0]; message = arguments[1]; } else { console.log('ERROR: invalid number of arguments.'); return; } logger.info('USER ' + this.userName + ': Sending message ' + messageName); this.sendMessageCallback(messageName, message); // TODO errorhandling send failed // logger.info( // 'TODO -----------------ROOM {}: The users {} could not be notified that {} left the room' // ); }; module.exports = UserSession;