diff --git a/config.js b/config.js
index 1152fe881..ebf7d2698 100644
--- a/config.js
+++ b/config.js
@@ -35,6 +35,9 @@ var config = {
// startAudioMuted: 10, //every participant after the Nth will start audio muted
// startVideoMuted: 10, //every participant after the Nth will start video muted
// defaultLanguage: "en",
+// To enable sending statistics to callstats.io you should provide Applicaiton ID and Secret.
+// callStatsID: "",//Application ID for callstats.io API
+// callStatsSecret: ""//Secret for callstats.io API
/*noticeMessage: 'Service update is scheduled for 16th March 2015. ' +
'During that time service will not be available. ' +
'Apologise for inconvenience.'*/
diff --git a/index.html b/index.html
index dfd54f6fe..3f8797030 100644
--- a/index.html
+++ b/index.html
@@ -9,8 +9,11 @@
+
-
+
+
+
@@ -19,7 +22,7 @@
-
+
diff --git a/libs/app.bundle.js b/libs/app.bundle.js
index 6fc48b6d3..75dcab45a 100644
--- a/libs/app.bundle.js
+++ b/libs/app.bundle.js
@@ -58,7 +58,7 @@ $(window).bind('beforeunload', function () {
module.exports = APP;
-},{"./modules/API/API":2,"./modules/DTMF/DTMF":3,"./modules/RTC/RTC":7,"./modules/UI/UI":9,"./modules/URLProcessor/URLProcessor":40,"./modules/connectionquality/connectionquality":41,"./modules/desktopsharing/desktopsharing":42,"./modules/keyboardshortcut/keyboardshortcut":43,"./modules/members/MemberList":44,"./modules/settings/Settings":45,"./modules/statistics/statistics":48,"./modules/translation/translation":49,"./modules/xmpp/xmpp":63}],2:[function(require,module,exports){
+},{"./modules/API/API":2,"./modules/DTMF/DTMF":3,"./modules/RTC/RTC":7,"./modules/UI/UI":9,"./modules/URLProcessor/URLProcessor":40,"./modules/connectionquality/connectionquality":41,"./modules/desktopsharing/desktopsharing":42,"./modules/keyboardshortcut/keyboardshortcut":43,"./modules/members/MemberList":44,"./modules/settings/Settings":45,"./modules/statistics/statistics":49,"./modules/translation/translation":50,"./modules/xmpp/xmpp":64}],2:[function(require,module,exports){
/**
* Implements API class that communicates with external api class
* and provides interface to access Jitsi Meet features by external
@@ -290,7 +290,7 @@ var API = {
};
module.exports = API;
-},{"../../service/xmpp/XMPPEvents":106}],3:[function(require,module,exports){
+},{"../../service/xmpp/XMPPEvents":111}],3:[function(require,module,exports){
/* global APP */
/**
@@ -557,8 +557,9 @@ function onPinnedEndpointChanged(userResource)
module.exports = DataChannels;
-},{"../../service/RTC/RTCEvents":97}],5:[function(require,module,exports){
+},{"../../service/RTC/RTCEvents":102}],5:[function(require,module,exports){
var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
+var RTCEvents = require("../../service/RTC/RTCEvents");
function LocalStream(stream, type, eventEmitter, videoType, isGUMStream)
@@ -614,12 +615,18 @@ LocalStream.prototype.setMute = function(mute)
for (var idx = 0; idx < tracks.length; idx++) {
tracks[idx].enabled = mute;
}
+ this.eventEmitter.emit(
+ (this.type == "audio"? RTCEvents.AUDIO_MUTE : RTCEvents.VIDEO_MUTE),
+ !mute);
}
else
{
if(mute === false) {
APP.xmpp.removeStream(this.stream);
this.stream.stop();
+ this.eventEmitter.emit(
+ (this.type == "audio"? RTCEvents.AUDIO_MUTE : RTCEvents.VIDEO_MUTE),
+ true);
}
else
{
@@ -629,11 +636,21 @@ LocalStream.prototype.setMute = function(mute)
function (stream) {
if(self.isAudioStream())
{
- APP.RTC.changeLocalAudio(stream, function () {});
+ APP.RTC.changeLocalAudio(stream,
+ function () {
+ self.eventEmitter.emit(
+ (self.type == "audio"? RTCEvents.AUDIO_MUTE : RTCEvents.VIDEO_MUTE),
+ true);
+ });
}
else
{
- APP.RTC.changeLocalVideo(stream, false, function () {});
+ APP.RTC.changeLocalVideo(stream, false,
+ function () {
+ self.eventEmitter.emit(
+ (self.type == "audio"? RTCEvents.AUDIO_MUTE : RTCEvents.VIDEO_MUTE),
+ true);
+ });
}
});
}
@@ -665,7 +682,7 @@ LocalStream.prototype.getId = function () {
module.exports = LocalStream;
-},{"../../service/RTC/StreamEventTypes.js":99}],6:[function(require,module,exports){
+},{"../../service/RTC/RTCEvents":102,"../../service/RTC/StreamEventTypes.js":104}],6:[function(require,module,exports){
////These lines should be uncommented when require works in app.js
var MediaStreamType = require("../../service/RTC/MediaStreamTypes");
var StreamEventType = require("../../service/RTC/StreamEventTypes");
@@ -727,7 +744,7 @@ MediaStream.prototype.setVideoType = function (value) {
module.exports = MediaStream;
-},{"../../service/RTC/MediaStreamTypes":95,"../../service/RTC/StreamEventTypes":99}],7:[function(require,module,exports){
+},{"../../service/RTC/MediaStreamTypes":100,"../../service/RTC/StreamEventTypes":104}],7:[function(require,module,exports){
var EventEmitter = require("events");
var RTCUtils = require("./RTCUtils.js");
var LocalStream = require("./LocalStream.js");
@@ -1013,7 +1030,7 @@ var RTC = {
module.exports = RTC;
-},{"../../service/RTC/MediaStreamTypes":95,"../../service/RTC/RTCEvents.js":97,"../../service/RTC/StreamEventTypes.js":99,"../../service/UI/UIEvents":100,"../../service/desktopsharing/DesktopSharingEventTypes":103,"../../service/xmpp/XMPPEvents":106,"./DataChannels":4,"./LocalStream.js":5,"./MediaStream.js":6,"./RTCUtils.js":8,"events":107}],8:[function(require,module,exports){
+},{"../../service/RTC/MediaStreamTypes":100,"../../service/RTC/RTCEvents.js":102,"../../service/RTC/StreamEventTypes.js":104,"../../service/UI/UIEvents":105,"../../service/desktopsharing/DesktopSharingEventTypes":108,"../../service/xmpp/XMPPEvents":111,"./DataChannels":4,"./LocalStream.js":5,"./MediaStream.js":6,"./RTCUtils.js":8,"events":112}],8:[function(require,module,exports){
var RTCBrowserType = require("../../service/RTC/RTCBrowserType.js");
var Resolutions = require("../../service/RTC/Resolutions");
@@ -1487,7 +1504,7 @@ RTCUtils.prototype.createStream = function(stream, isVideo)
module.exports = RTCUtils;
-},{"../../service/RTC/RTCBrowserType.js":96,"../../service/RTC/Resolutions":98}],9:[function(require,module,exports){
+},{"../../service/RTC/RTCBrowserType.js":101,"../../service/RTC/Resolutions":103}],9:[function(require,module,exports){
var UI = {};
var VideoLayout = require("./videolayout/VideoLayout.js");
@@ -2294,7 +2311,7 @@ UI.setVideoMute = setVideoMute;
module.exports = UI;
-},{"../../service/RTC/RTCEvents":97,"../../service/RTC/StreamEventTypes":99,"../../service/connectionquality/CQEvents":102,"../../service/desktopsharing/DesktopSharingEventTypes":103,"../../service/members/Events":104,"../../service/xmpp/XMPPEvents":106,"./../settings/Settings":45,"./audio_levels/AudioLevels.js":10,"./authentication/Authentication":12,"./avatar/Avatar":14,"./etherpad/Etherpad.js":15,"./prezi/Prezi.js":16,"./side_pannels/SidePanelToggler":18,"./side_pannels/chat/Chat.js":19,"./side_pannels/contactlist/ContactList":23,"./side_pannels/settings/SettingsMenu":24,"./toolbars/BottomToolbar":25,"./toolbars/Toolbar":26,"./toolbars/ToolbarToggler":27,"./util/MessageHandler":29,"./util/NicknameHandler":30,"./util/UIUtil":31,"./videolayout/VideoLayout.js":37,"./welcome_page/RoomnameGenerator":38,"./welcome_page/WelcomePage":39,"events":107}],10:[function(require,module,exports){
+},{"../../service/RTC/RTCEvents":102,"../../service/RTC/StreamEventTypes":104,"../../service/connectionquality/CQEvents":107,"../../service/desktopsharing/DesktopSharingEventTypes":108,"../../service/members/Events":109,"../../service/xmpp/XMPPEvents":111,"./../settings/Settings":45,"./audio_levels/AudioLevels.js":10,"./authentication/Authentication":12,"./avatar/Avatar":14,"./etherpad/Etherpad.js":15,"./prezi/Prezi.js":16,"./side_pannels/SidePanelToggler":18,"./side_pannels/chat/Chat.js":19,"./side_pannels/contactlist/ContactList":23,"./side_pannels/settings/SettingsMenu":24,"./toolbars/BottomToolbar":25,"./toolbars/Toolbar":26,"./toolbars/ToolbarToggler":27,"./util/MessageHandler":29,"./util/NicknameHandler":30,"./util/UIUtil":31,"./videolayout/VideoLayout.js":37,"./welcome_page/RoomnameGenerator":38,"./welcome_page/WelcomePage":39,"events":112}],10:[function(require,module,exports){
var CanvasUtil = require("./CanvasUtils");
var ASDrawContext = $('#activeSpeakerAudioLevel')[0].getContext('2d');
@@ -2797,7 +2814,7 @@ var Authentication = {
};
module.exports = Authentication;
-},{"../../xmpp/moderator":55,"./LoginDialog":13}],13:[function(require,module,exports){
+},{"../../xmpp/moderator":56,"./LoginDialog":13}],13:[function(require,module,exports){
/* global $, APP, config*/
var XMPP = require('../../xmpp/xmpp');
@@ -3026,7 +3043,7 @@ var LoginDialog = {
};
module.exports = LoginDialog;
-},{"../../xmpp/moderator":55,"../../xmpp/xmpp":63}],14:[function(require,module,exports){
+},{"../../xmpp/moderator":56,"../../xmpp/xmpp":64}],14:[function(require,module,exports){
var Settings = require("../../settings/Settings");
var MediaStreamType = require("../../../service/RTC/MediaStreamTypes");
@@ -3184,7 +3201,7 @@ var Avatar = {
module.exports = Avatar;
-},{"../../../service/RTC/MediaStreamTypes":95,"../../settings/Settings":45,"../videolayout/LargeVideo":33,"../videolayout/VideoLayout":37}],15:[function(require,module,exports){
+},{"../../../service/RTC/MediaStreamTypes":100,"../../settings/Settings":45,"../videolayout/LargeVideo":33,"../videolayout/VideoLayout":37}],15:[function(require,module,exports){
/* global $, config,
setLargeVideoVisible, Util */
@@ -4570,7 +4587,7 @@ var Chat = (function (my) {
return my;
}(Chat || {}));
module.exports = Chat;
-},{"../../../../service/UI/UIEvents":100,"../../toolbars/ToolbarToggler":27,"../../util/NicknameHandler":30,"../../util/UIUtil":31,"../SidePanelToggler":18,"./Commands":20,"./Replacement":21,"./smileys.json":22}],20:[function(require,module,exports){
+},{"../../../../service/UI/UIEvents":105,"../../toolbars/ToolbarToggler":27,"../../util/NicknameHandler":30,"../../util/UIUtil":31,"../SidePanelToggler":18,"./Commands":20,"./Replacement":21,"./smileys.json":22}],20:[function(require,module,exports){
var UIUtil = require("../../util/UIUtil");
/**
@@ -5078,7 +5095,7 @@ var SettingsMenu = {
module.exports = SettingsMenu;
-},{"../../../../service/translation/languages":105,"../../avatar/Avatar":14,"../../util/UIUtil":31,"./../../../settings/Settings":45}],25:[function(require,module,exports){
+},{"../../../../service/translation/languages":110,"../../avatar/Avatar":14,"../../util/UIUtil":31,"./../../../settings/Settings":45}],25:[function(require,module,exports){
var PanelToggler = require("../side_pannels/SidePanelToggler");
var buttonHandlers = {
@@ -5772,7 +5789,7 @@ var Toolbar = (function (my) {
}(Toolbar || {}));
module.exports = Toolbar;
-},{"../../../service/authentication/AuthenticationEvents":101,"../authentication/Authentication":12,"../etherpad/Etherpad":15,"../prezi/Prezi":16,"../side_pannels/SidePanelToggler":18,"../util/MessageHandler":29,"../util/UIUtil":31,"./BottomToolbar":25}],27:[function(require,module,exports){
+},{"../../../service/authentication/AuthenticationEvents":106,"../authentication/Authentication":12,"../etherpad/Etherpad":15,"../prezi/Prezi":16,"../side_pannels/SidePanelToggler":18,"../util/MessageHandler":29,"../util/UIUtil":31,"./BottomToolbar":25}],27:[function(require,module,exports){
/* global $, interfaceConfig, Moderator, DesktopStreaming.showDesktopSharingButton */
var toolbarTimeoutObject,
@@ -6253,7 +6270,7 @@ var NickanameHandler = {
};
module.exports = NickanameHandler;
-},{"../../../service/UI/UIEvents":100}],31:[function(require,module,exports){
+},{"../../../service/UI/UIEvents":105}],31:[function(require,module,exports){
/**
* Created by hristo on 12/22/14.
*/
@@ -7177,7 +7194,7 @@ var LargeVideo = {
module.exports = LargeVideo;
-},{"../../../service/UI/UIEvents":100,"../../xmpp/xmpp":63,"../avatar/Avatar":14,"../etherpad/Etherpad":15,"../prezi/Prezi":16,"../util/UIUtil":31}],34:[function(require,module,exports){
+},{"../../../service/UI/UIEvents":105,"../../xmpp/xmpp":64,"../avatar/Avatar":14,"../etherpad/Etherpad":15,"../prezi/Prezi":16,"../util/UIUtil":31}],34:[function(require,module,exports){
var SmallVideo = require("./SmallVideo");
var ConnectionIndicator = require("./ConnectionIndicator");
var NicknameHandler = require("../util/NicknameHandler");
@@ -8901,7 +8918,7 @@ var VideoLayout = (function (my) {
my.onStatsStop = function () {
for(var video in remoteVideos)
{
- video.hideIndicator();
+ remoteVideos[video].hideIndicator();
}
localVideoThumbnail.hideIndicator();
};
@@ -8977,7 +8994,7 @@ var VideoLayout = (function (my) {
}(VideoLayout || {}));
module.exports = VideoLayout;
-},{"../../../service/RTC/MediaStreamTypes":95,"../../../service/UI/UIEvents":100,"../audio_levels/AudioLevels":10,"../avatar/Avatar":14,"../prezi/Prezi":16,"../side_pannels/contactlist/ContactList":23,"./LargeVideo":33,"./LocalVideo":34,"./RemoteVideo":35}],38:[function(require,module,exports){
+},{"../../../service/RTC/MediaStreamTypes":100,"../../../service/UI/UIEvents":105,"../audio_levels/AudioLevels":10,"../avatar/Avatar":14,"../prezi/Prezi":16,"../side_pannels/contactlist/ContactList":23,"./LargeVideo":33,"./LocalVideo":34,"./RemoteVideo":35}],38:[function(require,module,exports){
//var nouns = [
//];
var pluralNouns = [
@@ -9436,7 +9453,7 @@ var ConnectionQuality = {
};
module.exports = ConnectionQuality;
-},{"../../service/connectionquality/CQEvents":102,"../../service/xmpp/XMPPEvents":106,"events":107}],42:[function(require,module,exports){
+},{"../../service/connectionquality/CQEvents":107,"../../service/xmpp/XMPPEvents":111,"events":112}],42:[function(require,module,exports){
/* global $, alert, APP, changeLocalVideo, chrome, config, getConferenceHandler,
getUserMediaWithConstraints */
/**
@@ -9806,7 +9823,7 @@ module.exports = {
};
-},{"../../service/desktopsharing/DesktopSharingEventTypes":103,"events":107}],43:[function(require,module,exports){
+},{"../../service/desktopsharing/DesktopSharingEventTypes":108,"events":112}],43:[function(require,module,exports){
//maps keycode to character, id of popover for given function and function
var shortcuts = {
67: {
@@ -10030,7 +10047,7 @@ var Members = {
module.exports = Members;
-},{"../../service/members/Events":104,"../../service/xmpp/XMPPEvents":106,"events":107}],45:[function(require,module,exports){
+},{"../../service/members/Events":109,"../../service/xmpp/XMPPEvents":111,"events":112}],45:[function(require,module,exports){
var email = '';
var displayName = '';
var userId;
@@ -10970,7 +10987,84 @@ StatsCollector.prototype.processAudioLevelReport = function ()
};
-},{"../../service/RTC/RTCBrowserType":96}],48:[function(require,module,exports){
+},{"../../service/RTC/RTCBrowserType":101}],48:[function(require,module,exports){
+var callStats = null;
+
+function initCallback (err, msg) {
+ console.log("Initializing Status: err="+err+" msg="+msg);
+}
+
+var CallStats = {
+ init: function (jingleSession) {
+
+ if(!config.callStatsID || !config.callStatsSecret || callStats !== null)
+ return;
+
+ callStats = new callstats($,io,jsSHA);
+
+ this.session = jingleSession;
+ this.peerconnection = jingleSession.peerconnection.peerconnection;
+
+ this.userID = APP.xmpp.myResource();
+
+ var roomJid = APP.UI.getRoomName();
+ this.confID = roomJid? Strophe.getNodeFromJid(roomJid) : null;
+
+ //userID is generated or given by the origin server
+ callStats.initialize(config.callStatsID,
+ config.callStatsSecret,
+ this.userID,
+ initCallback);
+
+ var usage = callStats.fabricUsage.unbundled;
+ if(config.useBundle)
+ usage = callStats.fabricUsage.multiplex;
+
+ callStats.addNewFabric(this.peerconnection,
+ Strophe.getResourceFromJid(jingleSession.peerjid),
+ usage,
+ this.confID,
+ this.pcCallback.bind(this));
+ },
+ pcCallback: function (err, msg) {
+ if(!callStats)
+ return;
+ console.log("Monitoring status: "+ err + " msg: " + msg);
+ callStats.sendFabricEvent(this.peerconnection,
+ callStats.fabricEvent.fabricSetup, this.confID);
+ },
+ sendMuteEvent: function (mute, type) {
+ if(!callStats)
+ return;
+ var event = null;
+ if(type === "video")
+ {
+ event = (mute? callStats.fabricEvent.videoPause :
+ callStats.fabricEvent.videoResume);
+ }
+ else
+ {
+ event = (mute? callStats.fabricEvent.audioMute :
+ callStats.fabricEvent.audioUnmute);
+ }
+ callStats.sendFabricEvent(this.peerconnection, event, this.confID);
+ },
+ sendTerminateEvent: function () {
+ if(!callStats)
+ return;
+ callStats.sendFabricEvent(this.peerconnection,
+ callStats.fabricEvent.fabricTerminated, this.confID);
+ },
+ sendSetupFailedEvent: function () {
+ if(!callStats)
+ return;
+ callStats.sendFabricEvent(this.peerconnection,
+ callStats.fabricEvent.fabricSetupFailed, this.confID);
+ }
+
+};
+module.exports = CallStats;
+},{}],49:[function(require,module,exports){
/**
* Created by hristo on 8/4/14.
*/
@@ -10979,6 +11073,8 @@ var RTPStats = require("./RTPStatsCollector.js");
var EventEmitter = require("events");
var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
+var CallStats = require("./callstats");
+var RTCEvents = require("../../service/RTC/RTCEvents");
var eventEmitter = new EventEmitter();
@@ -11027,6 +11123,7 @@ function onStreamCreated(stream)
}
function onDisposeConference(onUnload) {
+ CallStats.sendTerminateEvent();
stopRemote();
if(onUnload) {
stopLocal();
@@ -11092,8 +11189,22 @@ var statistics =
APP.RTC.addStreamListener(onStreamCreated,
StreamEventTypes.EVENT_TYPE_LOCAL_CREATED);
APP.xmpp.addListener(XMPPEvents.DISPOSE_CONFERENCE, onDisposeConference);
+ //FIXME: we may want to change CALL INCOMING event to onnegotiationneeded
APP.xmpp.addListener(XMPPEvents.CALL_INCOMING, function (event) {
startRemoteStats(event.peerconnection);
+// CallStats.init(event);
+ });
+ APP.xmpp.addListener(XMPPEvents.PEERCONNECTION_READY, function (session) {
+ CallStats.init(session);
+ })
+ APP.RTC.addListener(RTCEvents.AUDIO_MUTE, function (mute) {
+ CallStats.sendMuteEvent(mute, "audio");
+ });
+ APP.xmpp.addListener(XMPPEvents.CONFERENCE_SETUP_FAILED, function () {
+ CallStats.sendSetupFailedEvent();
+ })
+ APP.RTC.addListener(RTCEvents.VIDEO_MUTE, function (mute) {
+ CallStats.sendMuteEvent(mute, "video");
});
}
@@ -11103,7 +11214,7 @@ var statistics =
module.exports = statistics;
-},{"../../service/RTC/StreamEventTypes.js":99,"../../service/xmpp/XMPPEvents":106,"./LocalStatsCollector.js":46,"./RTPStatsCollector.js":47,"events":107}],49:[function(require,module,exports){
+},{"../../service/RTC/RTCEvents":102,"../../service/RTC/StreamEventTypes.js":104,"../../service/xmpp/XMPPEvents":111,"./LocalStatsCollector.js":46,"./RTPStatsCollector.js":47,"./callstats":48,"events":112}],50:[function(require,module,exports){
var i18n = require("i18next-client");
var languages = require("../../service/translation/languages");
var Settings = require("../settings/Settings");
@@ -11242,18 +11353,18 @@ module.exports = {
}
};
-},{"../../service/translation/languages":105,"../settings/Settings":45,"i18next-client":65}],50:[function(require,module,exports){
+},{"../../service/translation/languages":110,"../settings/Settings":45,"i18next-client":66}],51:[function(require,module,exports){
/* jshint -W117 */
var TraceablePeerConnection = require("./TraceablePeerConnection");
var SDPDiffer = require("./SDPDiffer");
var SDPUtil = require("./SDPUtil");
var SDP = require("./SDP");
-var RTCBrowserType = require("../../service/RTC/RTCBrowserType");
var async = require("async");
var transform = require("sdp-transform");
+var XMPPEvents = require("../../service/xmpp/XMPPEvents");
// Jingle stuff
-function JingleSession(me, sid, connection, service) {
+function JingleSession(me, sid, connection, service, eventEmitter) {
this.me = me;
this.sid = sid;
this.connection = connection;
@@ -11292,6 +11403,7 @@ function JingleSession(me, sid, connection, service) {
this.wait = true;
this.localStreamsSSRC = null;
+ this.eventEmitter = eventEmitter;
/**
* The indicator which determines whether the (local) video has been muted
@@ -11334,7 +11446,8 @@ JingleSession.prototype.initiate = function (peerjid, isInitiator) {
this.peerconnection
= new TraceablePeerConnection(
this.connection.jingle.ice_config,
- this.connection.jingle.pc_constraints );
+ this.connection.jingle.pc_constraints,
+ this);
this.peerconnection.onicecandidate = function (event) {
self.sendIceCandidate(event.candidate);
@@ -11370,9 +11483,15 @@ JingleSession.prototype.initiate = function (peerjid, isInitiator) {
case 'disconnected':
this.stopTime = new Date();
break;
+ case 'failed':
+ self.eventEmitter(XMPPEvents.CONFERENCE_SETUP_FAILED);
+ break;
}
onIceConnectionStateChange(self.sid, self);
};
+ this.peerconnection.onnegotiationneeded = function (event) {
+ self.eventEmitter.emit(XMPPEvents.PEERCONNECTION_READY, self);
+ };
// add any local and relayed stream
APP.RTC.localStreams.forEach(function(stream) {
self.peerconnection.addStream(stream.getOriginalStream());
@@ -11483,6 +11602,7 @@ JingleSession.prototype.accept = function () {
},
function (e) {
console.error('setLocalDescription failed', e);
+ self.eventEmitter.emit(XMPPEvents.CONFERENCE_SETUP_FAILED);
}
);
};
@@ -11693,6 +11813,7 @@ JingleSession.prototype.createdOffer = function (sdp) {
},
function (e) {
console.error('setLocalDescription failed', e);
+ self.eventEmitter.emit(XMPPEvents.CONFERENCE_SETUP_FAILED);
}
);
var cands = SDPUtil.find_lines(this.localSDP.raw, 'a=candidate:');
@@ -11867,6 +11988,7 @@ JingleSession.prototype.sendAnswer = function (provisional) {
},
function (e) {
console.error('createAnswer failed', e);
+ self.eventEmitter.emit(XMPPEvents.CONFERENCE_SETUP_FAILED);
},
this.media_constraints
);
@@ -11926,6 +12048,7 @@ JingleSession.prototype.createdAnswer = function (sdp, provisional) {
},
function (e) {
console.error('setLocalDescription failed', e);
+ self.eventEmitter.emit(XMPPEvents.CONFERENCE_SETUP_FAILED);
}
);
var cands = SDPUtil.find_lines(this.localSDP.raw, 'a=candidate:');
@@ -12477,6 +12600,7 @@ JingleSession.onJingleFatalError = function (session, error)
this.connection.emuc.doLeave();
APP.UI.messageHandler.showError("dialog.sorry",
"dialog.internalError");
+ this.eventEmitter.emit(XMPPEvents.CONFERENCE_SETUP_FAILED);
}
JingleSession.prototype.setLocalDescription = function () {
@@ -12532,6 +12656,7 @@ JingleSession.prototype.setLocalDescription = function () {
function sendKeyframe(pc) {
console.log('sendkeyframe', pc.iceConnectionState);
if (pc.iceConnectionState !== 'connected') return; // safe...
+ var self = this;
pc.setRemoteDescription(
pc.remoteDescription,
function () {
@@ -12636,7 +12761,7 @@ JingleSession.prototype.remoteStreamAdded = function (data, times) {
module.exports = JingleSession;
-},{"../../service/RTC/RTCBrowserType":96,"./SDP":51,"./SDPDiffer":52,"./SDPUtil":53,"./TraceablePeerConnection":54,"async":64,"sdp-transform":92}],51:[function(require,module,exports){
+},{"../../service/xmpp/XMPPEvents":111,"./SDP":52,"./SDPDiffer":53,"./SDPUtil":54,"./TraceablePeerConnection":55,"async":65,"sdp-transform":97}],52:[function(require,module,exports){
/* jshint -W117 */
var SDPUtil = require("./SDPUtil");
@@ -13258,7 +13383,7 @@ SDP.prototype.jingle2media = function (content) {
module.exports = SDP;
-},{"./SDPUtil":53}],52:[function(require,module,exports){
+},{"./SDPUtil":54}],53:[function(require,module,exports){
function SDPDiffer(mySDP, otherSDP) {
this.mySDP = mySDP;
this.otherSDP = otherSDP;
@@ -13424,7 +13549,7 @@ SDPDiffer.prototype.toJingle = function(modify) {
};
module.exports = SDPDiffer;
-},{}],53:[function(require,module,exports){
+},{}],54:[function(require,module,exports){
SDPUtil = {
iceparams: function (mediadesc, sessiondesc) {
var data = null;
@@ -13774,8 +13899,10 @@ SDPUtil = {
}
};
module.exports = SDPUtil;
-},{}],54:[function(require,module,exports){
-function TraceablePeerConnection(ice_config, constraints) {
+},{}],55:[function(require,module,exports){
+var XMPPEvents = require("../../service/xmpp/XMPPEvents");
+
+function TraceablePeerConnection(ice_config, constraints, session) {
var self = this;
var RTCPeerconnection = navigator.mozGetUserMedia ? mozRTCPeerConnection : webkitRTCPeerConnection;
this.peerconnection = new RTCPeerconnection(ice_config, constraints);
@@ -14101,7 +14228,7 @@ TraceablePeerConnection.prototype.getStats = function(callback, errback) {
module.exports = TraceablePeerConnection;
-},{"sdp-interop":86,"sdp-simulcast":89}],55:[function(require,module,exports){
+},{"../../service/xmpp/XMPPEvents":111,"sdp-interop":87,"sdp-simulcast":94}],56:[function(require,module,exports){
/* global $, $iq, APP, config, connection, UI, messageHandler,
roomName, sessionTerminated, Strophe, Util */
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
@@ -14537,7 +14664,7 @@ module.exports = Moderator;
-},{"../../service/authentication/AuthenticationEvents":101,"../../service/xmpp/XMPPEvents":106,"../settings/Settings":45}],56:[function(require,module,exports){
+},{"../../service/authentication/AuthenticationEvents":106,"../../service/xmpp/XMPPEvents":111,"../settings/Settings":45}],57:[function(require,module,exports){
/* global $, $iq, config, connection, focusMucJid, messageHandler, Moderator,
Toolbar, Util */
var Moderator = require("./moderator");
@@ -14693,7 +14820,7 @@ var Recording = {
}
module.exports = Recording;
-},{"./moderator":55}],57:[function(require,module,exports){
+},{"./moderator":56}],58:[function(require,module,exports){
/* jshint -W117 */
/* a simple MUC connection plugin
* can only handle a single MUC room
@@ -15390,7 +15517,7 @@ module.exports = function(XMPP, eventEmitter) {
};
-},{"../../service/xmpp/XMPPEvents":106,"./JingleSession":50,"./moderator":55}],58:[function(require,module,exports){
+},{"../../service/xmpp/XMPPEvents":111,"./JingleSession":51,"./moderator":56}],59:[function(require,module,exports){
/* jshint -W117 */
var JingleSession = require("./JingleSession");
@@ -15512,7 +15639,7 @@ module.exports = function(XMPP, eventEmitter)
}
sess = new JingleSession(
$(iq).attr('to'), $(iq).find('jingle').attr('sid'),
- this.connection, XMPP);
+ this.connection, XMPP, eventEmitter);
// configure session
sess.media_constraints = this.media_constraints;
@@ -15592,7 +15719,7 @@ module.exports = function(XMPP, eventEmitter)
initiate: function (peerjid, myjid) { // initiate a new jinglesession to peerjid
var sess = new JingleSession(myjid || this.connection.jid,
Math.random().toString(36).substr(2, 12), // random string
- this.connection, XMPP);
+ this.connection, XMPP, eventEmitter);
// configure session
sess.media_constraints = this.media_constraints;
@@ -15739,7 +15866,7 @@ module.exports = function(XMPP, eventEmitter)
};
-},{"../../service/xmpp/XMPPEvents":106,"./JingleSession":50}],59:[function(require,module,exports){
+},{"../../service/xmpp/XMPPEvents":111,"./JingleSession":51}],60:[function(require,module,exports){
/* global Strophe */
module.exports = function () {
@@ -15760,7 +15887,7 @@ module.exports = function () {
}
});
};
-},{}],60:[function(require,module,exports){
+},{}],61:[function(require,module,exports){
/* global $, $iq, config, connection, focusMucJid, forceMuted,
setAudioMuted, Strophe */
/**
@@ -15819,7 +15946,7 @@ module.exports = function (XMPP) {
}
});
}
-},{}],61:[function(require,module,exports){
+},{}],62:[function(require,module,exports){
/* jshint -W117 */
module.exports = function() {
Strophe.addConnectionPlugin('rayo',
@@ -15916,7 +16043,7 @@ module.exports = function() {
);
};
-},{}],62:[function(require,module,exports){
+},{}],63:[function(require,module,exports){
/**
* Strophe logger implementation. Logs from level WARN and above.
*/
@@ -15960,7 +16087,7 @@ module.exports = function () {
};
};
-},{}],63:[function(require,module,exports){
+},{}],64:[function(require,module,exports){
/* global $, APP, config, Strophe*/
var Moderator = require("./moderator");
var EventEmitter = require("events");
@@ -16278,7 +16405,6 @@ var XMPP = {
return Strophe.getResourceFromJid(connection.emuc.myroomjid);
},
disposeConference: function (onUnload) {
- eventEmitter.emit(XMPPEvents.DISPOSE_CONFERENCE, onUnload);
var handler = connection.jingle.activecall;
if (handler && handler.peerconnection) {
// FIXME: probably removing streams is not required and close() should
@@ -16293,6 +16419,7 @@ var XMPP = {
}
handler.peerconnection.close();
}
+ eventEmitter.emit(XMPPEvents.DISPOSE_CONFERENCE, onUnload);
connection.jingle.activecall = null;
if(!onUnload)
{
@@ -16573,7 +16700,7 @@ var XMPP = {
module.exports = XMPP;
-},{"../../service/RTC/RTCEvents":97,"../../service/RTC/StreamEventTypes":99,"../../service/UI/UIEvents":100,"../../service/xmpp/XMPPEvents":106,"../settings/Settings":45,"./SDP":51,"./moderator":55,"./recording":56,"./strophe.emuc":57,"./strophe.jingle":58,"./strophe.logger":59,"./strophe.moderate":60,"./strophe.rayo":61,"./strophe.util":62,"events":107,"pako":66,"retry":82}],64:[function(require,module,exports){
+},{"../../service/RTC/RTCEvents":102,"../../service/RTC/StreamEventTypes":104,"../../service/UI/UIEvents":105,"../../service/xmpp/XMPPEvents":111,"../settings/Settings":45,"./SDP":52,"./moderator":56,"./recording":57,"./strophe.emuc":58,"./strophe.jingle":59,"./strophe.logger":60,"./strophe.moderate":61,"./strophe.rayo":62,"./strophe.util":63,"events":112,"pako":67,"retry":83}],65:[function(require,module,exports){
(function (process){
/*!
* async
@@ -17700,7 +17827,7 @@ module.exports = XMPP;
}());
}).call(this,require('_process'))
-},{"_process":108}],65:[function(require,module,exports){
+},{"_process":113}],66:[function(require,module,exports){
// i18next, v1.7.7
// Copyright (c)2014 Jan Mühlemann (jamuhl).
// Distributed under MIT license
@@ -19823,7 +19950,7 @@ module.exports = XMPP;
i18n.options = o;
})();
-},{"jquery":"jquery"}],66:[function(require,module,exports){
+},{"jquery":"jquery"}],67:[function(require,module,exports){
// Top level file is just a mixin of submodules & constants
'use strict';
@@ -19839,7 +19966,7 @@ assign(pako, deflate, inflate, constants);
module.exports = pako;
-},{"./lib/deflate":67,"./lib/inflate":68,"./lib/utils/common":69,"./lib/zlib/constants":72}],67:[function(require,module,exports){
+},{"./lib/deflate":68,"./lib/inflate":69,"./lib/utils/common":70,"./lib/zlib/constants":73}],68:[function(require,module,exports){
'use strict';
@@ -20217,7 +20344,7 @@ exports.deflate = deflate;
exports.deflateRaw = deflateRaw;
exports.gzip = gzip;
-},{"./utils/common":69,"./utils/strings":70,"./zlib/deflate.js":74,"./zlib/messages":79,"./zlib/zstream":81}],68:[function(require,module,exports){
+},{"./utils/common":70,"./utils/strings":71,"./zlib/deflate.js":75,"./zlib/messages":80,"./zlib/zstream":82}],69:[function(require,module,exports){
'use strict';
@@ -20598,7 +20725,7 @@ exports.inflate = inflate;
exports.inflateRaw = inflateRaw;
exports.ungzip = inflate;
-},{"./utils/common":69,"./utils/strings":70,"./zlib/constants":72,"./zlib/gzheader":75,"./zlib/inflate.js":77,"./zlib/messages":79,"./zlib/zstream":81}],69:[function(require,module,exports){
+},{"./utils/common":70,"./utils/strings":71,"./zlib/constants":73,"./zlib/gzheader":76,"./zlib/inflate.js":78,"./zlib/messages":80,"./zlib/zstream":82}],70:[function(require,module,exports){
'use strict';
@@ -20702,7 +20829,7 @@ exports.setTyped = function (on) {
exports.setTyped(TYPED_OK);
-},{}],70:[function(require,module,exports){
+},{}],71:[function(require,module,exports){
// String encode/decode helpers
'use strict';
@@ -20889,7 +21016,7 @@ exports.utf8border = function(buf, max) {
return (pos + _utf8len[buf[pos]] > max) ? pos : max;
};
-},{"./common":69}],71:[function(require,module,exports){
+},{"./common":70}],72:[function(require,module,exports){
'use strict';
// Note: adler32 takes 12% for level 0 and 2% for level 6.
@@ -20923,7 +21050,7 @@ function adler32(adler, buf, len, pos) {
module.exports = adler32;
-},{}],72:[function(require,module,exports){
+},{}],73:[function(require,module,exports){
module.exports = {
/* Allowed flush values; see deflate() and inflate() below for details */
@@ -20972,7 +21099,7 @@ module.exports = {
//Z_NULL: null // Use -1 or null inline, depending on var type
};
-},{}],73:[function(require,module,exports){
+},{}],74:[function(require,module,exports){
'use strict';
// Note: we can't get significant speed boost here.
@@ -21015,7 +21142,7 @@ function crc32(crc, buf, len, pos) {
module.exports = crc32;
-},{}],74:[function(require,module,exports){
+},{}],75:[function(require,module,exports){
'use strict';
var utils = require('../utils/common');
@@ -22782,7 +22909,7 @@ exports.deflatePrime = deflatePrime;
exports.deflateTune = deflateTune;
*/
-},{"../utils/common":69,"./adler32":71,"./crc32":73,"./messages":79,"./trees":80}],75:[function(require,module,exports){
+},{"../utils/common":70,"./adler32":72,"./crc32":74,"./messages":80,"./trees":81}],76:[function(require,module,exports){
'use strict';
@@ -22824,7 +22951,7 @@ function GZheader() {
module.exports = GZheader;
-},{}],76:[function(require,module,exports){
+},{}],77:[function(require,module,exports){
'use strict';
// See state defs from inflate.js
@@ -23151,7 +23278,7 @@ module.exports = function inflate_fast(strm, start) {
return;
};
-},{}],77:[function(require,module,exports){
+},{}],78:[function(require,module,exports){
'use strict';
@@ -24656,7 +24783,7 @@ exports.inflateSyncPoint = inflateSyncPoint;
exports.inflateUndermine = inflateUndermine;
*/
-},{"../utils/common":69,"./adler32":71,"./crc32":73,"./inffast":76,"./inftrees":78}],78:[function(require,module,exports){
+},{"../utils/common":70,"./adler32":72,"./crc32":74,"./inffast":77,"./inftrees":79}],79:[function(require,module,exports){
'use strict';
@@ -24985,7 +25112,7 @@ module.exports = function inflate_table(type, lens, lens_index, codes, table, ta
return 0;
};
-},{"../utils/common":69}],79:[function(require,module,exports){
+},{"../utils/common":70}],80:[function(require,module,exports){
'use strict';
module.exports = {
@@ -25000,7 +25127,7 @@ module.exports = {
'-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */
};
-},{}],80:[function(require,module,exports){
+},{}],81:[function(require,module,exports){
'use strict';
@@ -26201,7 +26328,7 @@ exports._tr_flush_block = _tr_flush_block;
exports._tr_tally = _tr_tally;
exports._tr_align = _tr_align;
-},{"../utils/common":69}],81:[function(require,module,exports){
+},{"../utils/common":70}],82:[function(require,module,exports){
'use strict';
@@ -26232,9 +26359,9 @@ function ZStream() {
module.exports = ZStream;
-},{}],82:[function(require,module,exports){
+},{}],83:[function(require,module,exports){
module.exports = require('./lib/retry');
-},{"./lib/retry":83}],83:[function(require,module,exports){
+},{"./lib/retry":84}],84:[function(require,module,exports){
var RetryOperation = require('./retry_operation');
exports.operation = function(options) {
@@ -26285,7 +26412,7 @@ exports._createTimeout = function(attempt, opts) {
return timeout;
};
-},{"./retry_operation":84}],84:[function(require,module,exports){
+},{"./retry_operation":85}],85:[function(require,module,exports){
function RetryOperation(timeouts) {
this._timeouts = timeouts;
this._fn = null;
@@ -26395,7 +26522,7 @@ RetryOperation.prototype.mainError = function() {
return mainError;
};
-},{}],85:[function(require,module,exports){
+},{}],86:[function(require,module,exports){
module.exports = function arrayEquals(array) {
// if the other array is a falsy value, return
if (!array)
@@ -26421,10 +26548,10 @@ module.exports = function arrayEquals(array) {
}
-},{}],86:[function(require,module,exports){
+},{}],87:[function(require,module,exports){
exports.Interop = require('./interop');
-},{"./interop":87}],87:[function(require,module,exports){
+},{"./interop":88}],88:[function(require,module,exports){
"use strict";
var transform = require('./transform');
@@ -27006,7 +27133,7 @@ Interop.prototype.toUnifiedPlan = function(desc) {
//#endregion
};
-},{"./array-equals":85,"./transform":88}],88:[function(require,module,exports){
+},{"./array-equals":86,"./transform":89}],89:[function(require,module,exports){
var transform = require('sdp-transform');
exports.write = function(session, opts) {
@@ -27105,7 +27232,477 @@ exports.parse = function(sdp) {
};
-},{"sdp-transform":92}],89:[function(require,module,exports){
+},{"sdp-transform":91}],90:[function(require,module,exports){
+var grammar = module.exports = {
+ v: [{
+ name: 'version',
+ reg: /^(\d*)$/
+ }],
+ o: [{ //o=- 20518 0 IN IP4 203.0.113.1
+ // NB: sessionId will be a String in most cases because it is huge
+ name: 'origin',
+ reg: /^(\S*) (\d*) (\d*) (\S*) IP(\d) (\S*)/,
+ names: ['username', 'sessionId', 'sessionVersion', 'netType', 'ipVer', 'address'],
+ format: "%s %s %d %s IP%d %s"
+ }],
+ // default parsing of these only (though some of these feel outdated)
+ s: [{ name: 'name' }],
+ i: [{ name: 'description' }],
+ u: [{ name: 'uri' }],
+ e: [{ name: 'email' }],
+ p: [{ name: 'phone' }],
+ z: [{ name: 'timezones' }], // TODO: this one can actually be parsed properly..
+ r: [{ name: 'repeats' }], // TODO: this one can also be parsed properly
+ //k: [{}], // outdated thing ignored
+ t: [{ //t=0 0
+ name: 'timing',
+ reg: /^(\d*) (\d*)/,
+ names: ['start', 'stop'],
+ format: "%d %d"
+ }],
+ c: [{ //c=IN IP4 10.47.197.26
+ name: 'connection',
+ reg: /^IN IP(\d) (\S*)/,
+ names: ['version', 'ip'],
+ format: "IN IP%d %s"
+ }],
+ b: [{ //b=AS:4000
+ push: 'bandwidth',
+ reg: /^(TIAS|AS|CT|RR|RS):(\d*)/,
+ names: ['type', 'limit'],
+ format: "%s:%s"
+ }],
+ m: [{ //m=video 51744 RTP/AVP 126 97 98 34 31
+ // NB: special - pushes to session
+ // TODO: rtp/fmtp should be filtered by the payloads found here?
+ reg: /^(\w*) (\d*) ([\w\/]*)(?: (.*))?/,
+ names: ['type', 'port', 'protocol', 'payloads'],
+ format: "%s %d %s %s"
+ }],
+ a: [
+ { //a=rtpmap:110 opus/48000/2
+ push: 'rtp',
+ reg: /^rtpmap:(\d*) ([\w\-]*)\/(\d*)(?:\s*\/(\S*))?/,
+ names: ['payload', 'codec', 'rate', 'encoding'],
+ format: function (o) {
+ return (o.encoding) ?
+ "rtpmap:%d %s/%s/%s":
+ "rtpmap:%d %s/%s";
+ }
+ },
+ { //a=fmtp:108 profile-level-id=24;object=23;bitrate=64000
+ push: 'fmtp',
+ reg: /^fmtp:(\d*) (\S*)/,
+ names: ['payload', 'config'],
+ format: "fmtp:%d %s"
+ },
+ { //a=control:streamid=0
+ name: 'control',
+ reg: /^control:(.*)/,
+ format: "control:%s"
+ },
+ { //a=rtcp:65179 IN IP4 193.84.77.194
+ name: 'rtcp',
+ reg: /^rtcp:(\d*)(?: (\S*) IP(\d) (\S*))?/,
+ names: ['port', 'netType', 'ipVer', 'address'],
+ format: function (o) {
+ return (o.address != null) ?
+ "rtcp:%d %s IP%d %s":
+ "rtcp:%d";
+ }
+ },
+ { //a=rtcp-fb:98 trr-int 100
+ push: 'rtcpFbTrrInt',
+ reg: /^rtcp-fb:(\*|\d*) trr-int (\d*)/,
+ names: ['payload', 'value'],
+ format: "rtcp-fb:%d trr-int %d"
+ },
+ { //a=rtcp-fb:98 nack rpsi
+ push: 'rtcpFb',
+ reg: /^rtcp-fb:(\*|\d*) ([\w-_]*)(?: ([\w-_]*))?/,
+ names: ['payload', 'type', 'subtype'],
+ format: function (o) {
+ return (o.subtype != null) ?
+ "rtcp-fb:%s %s %s":
+ "rtcp-fb:%s %s";
+ }
+ },
+ { //a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
+ //a=extmap:1/recvonly URI-gps-string
+ push: 'ext',
+ reg: /^extmap:([\w_\/]*) (\S*)(?: (\S*))?/,
+ names: ['value', 'uri', 'config'], // value may include "/direction" suffix
+ format: function (o) {
+ return (o.config != null) ?
+ "extmap:%s %s %s":
+ "extmap:%s %s";
+ }
+ },
+ {
+ //a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32
+ push: 'crypto',
+ reg: /^crypto:(\d*) ([\w_]*) (\S*)(?: (\S*))?/,
+ names: ['id', 'suite', 'config', 'sessionConfig'],
+ format: function (o) {
+ return (o.sessionConfig != null) ?
+ "crypto:%d %s %s %s":
+ "crypto:%d %s %s";
+ }
+ },
+ { //a=setup:actpass
+ name: 'setup',
+ reg: /^setup:(\w*)/,
+ format: "setup:%s"
+ },
+ { //a=mid:1
+ name: 'mid',
+ reg: /^mid:([^\s]*)/,
+ format: "mid:%s"
+ },
+ { //a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a
+ name: 'msid',
+ reg: /^msid:(.*)/,
+ format: "msid:%s"
+ },
+ { //a=ptime:20
+ name: 'ptime',
+ reg: /^ptime:(\d*)/,
+ format: "ptime:%d"
+ },
+ { //a=maxptime:60
+ name: 'maxptime',
+ reg: /^maxptime:(\d*)/,
+ format: "maxptime:%d"
+ },
+ { //a=sendrecv
+ name: 'direction',
+ reg: /^(sendrecv|recvonly|sendonly|inactive)/
+ },
+ { //a=ice-lite
+ name: 'icelite',
+ reg: /^(ice-lite)/
+ },
+ { //a=ice-ufrag:F7gI
+ name: 'iceUfrag',
+ reg: /^ice-ufrag:(\S*)/,
+ format: "ice-ufrag:%s"
+ },
+ { //a=ice-pwd:x9cml/YzichV2+XlhiMu8g
+ name: 'icePwd',
+ reg: /^ice-pwd:(\S*)/,
+ format: "ice-pwd:%s"
+ },
+ { //a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33
+ name: 'fingerprint',
+ reg: /^fingerprint:(\S*) (\S*)/,
+ names: ['type', 'hash'],
+ format: "fingerprint:%s %s"
+ },
+ {
+ //a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
+ //a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0
+ //a=candidate:3289912957 2 udp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 generation 0
+ push:'candidates',
+ reg: /^candidate:(\S*) (\d*) (\S*) (\d*) (\S*) (\d*) typ (\S*)(?: raddr (\S*) rport (\d*))?(?: generation (\d*))?/,
+ names: ['foundation', 'component', 'transport', 'priority', 'ip', 'port', 'type', 'raddr', 'rport', 'generation'],
+ format: function (o) {
+ var str = "candidate:%s %d %s %d %s %d typ %s";
+ // NB: candidate has two optional chunks, so %void middle one if it's missing
+ str += (o.raddr != null) ? " raddr %s rport %d" : "%v%v";
+ if (o.generation != null) {
+ str += " generation %d";
+ }
+ return str;
+ }
+ },
+ { //a=end-of-candidates (keep after the candidates line for readability)
+ name: 'endOfCandidates',
+ reg: /^(end-of-candidates)/
+ },
+ { //a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ...
+ name: 'remoteCandidates',
+ reg: /^remote-candidates:(.*)/,
+ format: "remote-candidates:%s"
+ },
+ { //a=ice-options:google-ice
+ name: 'iceOptions',
+ reg: /^ice-options:(\S*)/,
+ format: "ice-options:%s"
+ },
+ { //a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1
+ push: "ssrcs",
+ reg: /^ssrc:(\d*) ([\w_]*):(.*)/,
+ names: ['id', 'attribute', 'value'],
+ format: "ssrc:%d %s:%s"
+ },
+ { //a=ssrc-group:FEC 1 2
+ push: "ssrcGroups",
+ reg: /^ssrc-group:(\w*) (.*)/,
+ names: ['semantics', 'ssrcs'],
+ format: "ssrc-group:%s %s"
+ },
+ { //a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV
+ name: "msidSemantic",
+ reg: /^msid-semantic:\s?(\w*) (\S*)/,
+ names: ['semantic', 'token'],
+ format: "msid-semantic: %s %s" // space after ":" is not accidental
+ },
+ { //a=group:BUNDLE audio video
+ push: 'groups',
+ reg: /^group:(\w*) (.*)/,
+ names: ['type', 'mids'],
+ format: "group:%s %s"
+ },
+ { //a=rtcp-mux
+ name: 'rtcpMux',
+ reg: /^(rtcp-mux)/
+ },
+ { //a=rtcp-rsize
+ name: 'rtcpRsize',
+ reg: /^(rtcp-rsize)/
+ },
+ { // any a= that we don't understand is kepts verbatim on media.invalid
+ push: 'invalid',
+ names: ["value"]
+ }
+ ]
+};
+
+// set sensible defaults to avoid polluting the grammar with boring details
+Object.keys(grammar).forEach(function (key) {
+ var objs = grammar[key];
+ objs.forEach(function (obj) {
+ if (!obj.reg) {
+ obj.reg = /(.*)/;
+ }
+ if (!obj.format) {
+ obj.format = "%s";
+ }
+ });
+});
+
+},{}],91:[function(require,module,exports){
+var parser = require('./parser');
+var writer = require('./writer');
+
+exports.write = writer;
+exports.parse = parser.parse;
+exports.parseFmtpConfig = parser.parseFmtpConfig;
+exports.parsePayloads = parser.parsePayloads;
+exports.parseRemoteCandidates = parser.parseRemoteCandidates;
+
+},{"./parser":92,"./writer":93}],92:[function(require,module,exports){
+var toIntIfInt = function (v) {
+ return String(Number(v)) === v ? Number(v) : v;
+};
+
+var attachProperties = function (match, location, names, rawName) {
+ if (rawName && !names) {
+ location[rawName] = toIntIfInt(match[1]);
+ }
+ else {
+ for (var i = 0; i < names.length; i += 1) {
+ if (match[i+1] != null) {
+ location[names[i]] = toIntIfInt(match[i+1]);
+ }
+ }
+ }
+};
+
+var parseReg = function (obj, location, content) {
+ var needsBlank = obj.name && obj.names;
+ if (obj.push && !location[obj.push]) {
+ location[obj.push] = [];
+ }
+ else if (needsBlank && !location[obj.name]) {
+ location[obj.name] = {};
+ }
+ var keyLocation = obj.push ?
+ {} : // blank object that will be pushed
+ needsBlank ? location[obj.name] : location; // otherwise, named location or root
+
+ attachProperties(content.match(obj.reg), keyLocation, obj.names, obj.name);
+
+ if (obj.push) {
+ location[obj.push].push(keyLocation);
+ }
+};
+
+var grammar = require('./grammar');
+var validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/);
+
+exports.parse = function (sdp) {
+ var session = {}
+ , media = []
+ , location = session; // points at where properties go under (one of the above)
+
+ // parse lines we understand
+ sdp.split(/(\r\n|\r|\n)/).filter(validLine).forEach(function (l) {
+ var type = l[0];
+ var content = l.slice(2);
+ if (type === 'm') {
+ media.push({rtp: [], fmtp: []});
+ location = media[media.length-1]; // point at latest media line
+ }
+
+ for (var j = 0; j < (grammar[type] || []).length; j += 1) {
+ var obj = grammar[type][j];
+ if (obj.reg.test(content)) {
+ return parseReg(obj, location, content);
+ }
+ }
+ });
+
+ session.media = media; // link it up
+ return session;
+};
+
+var fmtpReducer = function (acc, expr) {
+ var s = expr.split('=');
+ if (s.length === 2) {
+ acc[s[0]] = toIntIfInt(s[1]);
+ }
+ return acc;
+};
+
+exports.parseFmtpConfig = function (str) {
+ return str.split(';').reduce(fmtpReducer, {});
+};
+
+exports.parsePayloads = function (str) {
+ return str.split(' ').map(Number);
+};
+
+exports.parseRemoteCandidates = function (str) {
+ var candidates = [];
+ var parts = str.split(' ').map(toIntIfInt);
+ for (var i = 0; i < parts.length; i += 3) {
+ candidates.push({
+ component: parts[i],
+ ip: parts[i + 1],
+ port: parts[i + 2]
+ });
+ }
+ return candidates;
+};
+
+},{"./grammar":90}],93:[function(require,module,exports){
+var grammar = require('./grammar');
+
+// customized util.format - discards excess arguments and can void middle ones
+var formatRegExp = /%[sdv%]/g;
+var format = function (formatStr) {
+ var i = 1;
+ var args = arguments;
+ var len = args.length;
+ return formatStr.replace(formatRegExp, function (x) {
+ if (i >= len) {
+ return x; // missing argument
+ }
+ var arg = args[i];
+ i += 1;
+ switch (x) {
+ case '%%':
+ return '%';
+ case '%s':
+ return String(arg);
+ case '%d':
+ return Number(arg);
+ case '%v':
+ return '';
+ }
+ });
+ // NB: we discard excess arguments - they are typically undefined from makeLine
+};
+
+var makeLine = function (type, obj, location) {
+ var str = obj.format instanceof Function ?
+ (obj.format(obj.push ? location : location[obj.name])) :
+ obj.format;
+
+ var args = [type + '=' + str];
+ if (obj.names) {
+ for (var i = 0; i < obj.names.length; i += 1) {
+ var n = obj.names[i];
+ if (obj.name) {
+ args.push(location[obj.name][n]);
+ }
+ else { // for mLine and push attributes
+ args.push(location[obj.names[i]]);
+ }
+ }
+ }
+ else {
+ args.push(location[obj.name]);
+ }
+ return format.apply(null, args);
+};
+
+// RFC specified order
+// TODO: extend this with all the rest
+var defaultOuterOrder = [
+ 'v', 'o', 's', 'i',
+ 'u', 'e', 'p', 'c',
+ 'b', 't', 'r', 'z', 'a'
+];
+var defaultInnerOrder = ['i', 'c', 'b', 'a'];
+
+
+module.exports = function (session, opts) {
+ opts = opts || {};
+ // ensure certain properties exist
+ if (session.version == null) {
+ session.version = 0; // "v=0" must be there (only defined version atm)
+ }
+ if (session.name == null) {
+ session.name = " "; // "s= " must be there if no meaningful name set
+ }
+ session.media.forEach(function (mLine) {
+ if (mLine.payloads == null) {
+ mLine.payloads = "";
+ }
+ });
+
+ var outerOrder = opts.outerOrder || defaultOuterOrder;
+ var innerOrder = opts.innerOrder || defaultInnerOrder;
+ var sdp = [];
+
+ // loop through outerOrder for matching properties on session
+ outerOrder.forEach(function (type) {
+ grammar[type].forEach(function (obj) {
+ if (obj.name in session && session[obj.name] != null) {
+ sdp.push(makeLine(type, obj, session));
+ }
+ else if (obj.push in session && session[obj.push] != null) {
+ session[obj.push].forEach(function (el) {
+ sdp.push(makeLine(type, obj, el));
+ });
+ }
+ });
+ });
+
+ // then for each media line, follow the innerOrder
+ session.media.forEach(function (mLine) {
+ sdp.push(makeLine('m', grammar.m[0], mLine));
+
+ innerOrder.forEach(function (type) {
+ grammar[type].forEach(function (obj) {
+ if (obj.name in mLine && mLine[obj.name] != null) {
+ sdp.push(makeLine(type, obj, mLine));
+ }
+ else if (obj.push in mLine && mLine[obj.push] != null) {
+ mLine[obj.push].forEach(function (el) {
+ sdp.push(makeLine(type, obj, el));
+ });
+ }
+ });
+ });
+ });
+
+ return sdp.join('\r\n') + '\r\n';
+};
+
+},{"./grammar":90}],94:[function(require,module,exports){
var transform = require('sdp-transform');
var transformUtils = require('./transform-utils');
var parseSsrcs = transformUtils.parseSsrcs;
@@ -27507,7 +28104,7 @@ Simulcast.prototype.mungeLocalDescription = function (desc) {
module.exports = Simulcast;
-},{"./transform-utils":90,"sdp-transform":92}],90:[function(require,module,exports){
+},{"./transform-utils":95,"sdp-transform":97}],95:[function(require,module,exports){
exports.writeSsrcs = function(sources, order) {
var ssrcs = [];
@@ -27558,484 +28155,22 @@ exports.parseSsrcs = function (mLine) {
};
-},{}],91:[function(require,module,exports){
-var grammar = module.exports = {
- v: [{
- name: 'version',
- reg: /^(\d*)$/
- }],
- o: [{ //o=- 20518 0 IN IP4 203.0.113.1
- // NB: sessionId will be a String in most cases because it is huge
- name: 'origin',
- reg: /^(\S*) (\d*) (\d*) (\S*) IP(\d) (\S*)/,
- names: ['username', 'sessionId', 'sessionVersion', 'netType', 'ipVer', 'address'],
- format: "%s %s %d %s IP%d %s"
- }],
- // default parsing of these only (though some of these feel outdated)
- s: [{ name: 'name' }],
- i: [{ name: 'description' }],
- u: [{ name: 'uri' }],
- e: [{ name: 'email' }],
- p: [{ name: 'phone' }],
- z: [{ name: 'timezones' }], // TODO: this one can actually be parsed properly..
- r: [{ name: 'repeats' }], // TODO: this one can also be parsed properly
- //k: [{}], // outdated thing ignored
- t: [{ //t=0 0
- name: 'timing',
- reg: /^(\d*) (\d*)/,
- names: ['start', 'stop'],
- format: "%d %d"
- }],
- c: [{ //c=IN IP4 10.47.197.26
- name: 'connection',
- reg: /^IN IP(\d) (\S*)/,
- names: ['version', 'ip'],
- format: "IN IP%d %s"
- }],
- b: [{ //b=AS:4000
- push: 'bandwidth',
- reg: /^(TIAS|AS|CT|RR|RS):(\d*)/,
- names: ['type', 'limit'],
- format: "%s:%s"
- }],
- m: [{ //m=video 51744 RTP/AVP 126 97 98 34 31
- // NB: special - pushes to session
- // TODO: rtp/fmtp should be filtered by the payloads found here?
- reg: /^(\w*) (\d*) ([\w\/]*)(?: (.*))?/,
- names: ['type', 'port', 'protocol', 'payloads'],
- format: "%s %d %s %s"
- }],
- a: [
- { //a=rtpmap:110 opus/48000/2
- push: 'rtp',
- reg: /^rtpmap:(\d*) ([\w\-]*)\/(\d*)(?:\s*\/(\S*))?/,
- names: ['payload', 'codec', 'rate', 'encoding'],
- format: function (o) {
- return (o.encoding) ?
- "rtpmap:%d %s/%s/%s":
- "rtpmap:%d %s/%s";
- }
- },
- { //a=fmtp:108 profile-level-id=24;object=23;bitrate=64000
- push: 'fmtp',
- reg: /^fmtp:(\d*) (\S*)/,
- names: ['payload', 'config'],
- format: "fmtp:%d %s"
- },
- { //a=control:streamid=0
- name: 'control',
- reg: /^control:(.*)/,
- format: "control:%s"
- },
- { //a=rtcp:65179 IN IP4 193.84.77.194
- name: 'rtcp',
- reg: /^rtcp:(\d*)(?: (\S*) IP(\d) (\S*))?/,
- names: ['port', 'netType', 'ipVer', 'address'],
- format: function (o) {
- return (o.address != null) ?
- "rtcp:%d %s IP%d %s":
- "rtcp:%d";
- }
- },
- { //a=rtcp-fb:98 trr-int 100
- push: 'rtcpFbTrrInt',
- reg: /^rtcp-fb:(\*|\d*) trr-int (\d*)/,
- names: ['payload', 'value'],
- format: "rtcp-fb:%d trr-int %d"
- },
- { //a=rtcp-fb:98 nack rpsi
- push: 'rtcpFb',
- reg: /^rtcp-fb:(\*|\d*) ([\w-_]*)(?: ([\w-_]*))?/,
- names: ['payload', 'type', 'subtype'],
- format: function (o) {
- return (o.subtype != null) ?
- "rtcp-fb:%s %s %s":
- "rtcp-fb:%s %s";
- }
- },
- { //a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
- //a=extmap:1/recvonly URI-gps-string
- push: 'ext',
- reg: /^extmap:([\w_\/]*) (\S*)(?: (\S*))?/,
- names: ['value', 'uri', 'config'], // value may include "/direction" suffix
- format: function (o) {
- return (o.config != null) ?
- "extmap:%s %s %s":
- "extmap:%s %s";
- }
- },
- {
- //a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32
- push: 'crypto',
- reg: /^crypto:(\d*) ([\w_]*) (\S*)(?: (\S*))?/,
- names: ['id', 'suite', 'config', 'sessionConfig'],
- format: function (o) {
- return (o.sessionConfig != null) ?
- "crypto:%d %s %s %s":
- "crypto:%d %s %s";
- }
- },
- { //a=setup:actpass
- name: 'setup',
- reg: /^setup:(\w*)/,
- format: "setup:%s"
- },
- { //a=mid:1
- name: 'mid',
- reg: /^mid:([^\s]*)/,
- format: "mid:%s"
- },
- { //a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a
- name: 'msid',
- reg: /^msid:(.*)/,
- format: "msid:%s"
- },
- { //a=ptime:20
- name: 'ptime',
- reg: /^ptime:(\d*)/,
- format: "ptime:%d"
- },
- { //a=maxptime:60
- name: 'maxptime',
- reg: /^maxptime:(\d*)/,
- format: "maxptime:%d"
- },
- { //a=sendrecv
- name: 'direction',
- reg: /^(sendrecv|recvonly|sendonly|inactive)/
- },
- { //a=ice-lite
- name: 'icelite',
- reg: /^(ice-lite)/
- },
- { //a=ice-ufrag:F7gI
- name: 'iceUfrag',
- reg: /^ice-ufrag:(\S*)/,
- format: "ice-ufrag:%s"
- },
- { //a=ice-pwd:x9cml/YzichV2+XlhiMu8g
- name: 'icePwd',
- reg: /^ice-pwd:(\S*)/,
- format: "ice-pwd:%s"
- },
- { //a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33
- name: 'fingerprint',
- reg: /^fingerprint:(\S*) (\S*)/,
- names: ['type', 'hash'],
- format: "fingerprint:%s %s"
- },
- {
- //a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
- //a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0
- //a=candidate:3289912957 2 udp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 generation 0
- push:'candidates',
- reg: /^candidate:(\S*) (\d*) (\S*) (\d*) (\S*) (\d*) typ (\S*)(?: raddr (\S*) rport (\d*))?(?: generation (\d*))?/,
- names: ['foundation', 'component', 'transport', 'priority', 'ip', 'port', 'type', 'raddr', 'rport', 'generation'],
- format: function (o) {
- var str = "candidate:%s %d %s %d %s %d typ %s";
- // NB: candidate has two optional chunks, so %void middle one if it's missing
- str += (o.raddr != null) ? " raddr %s rport %d" : "%v%v";
- if (o.generation != null) {
- str += " generation %d";
- }
- return str;
- }
- },
- { //a=end-of-candidates (keep after the candidates line for readability)
- name: 'endOfCandidates',
- reg: /^(end-of-candidates)/
- },
- { //a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ...
- name: 'remoteCandidates',
- reg: /^remote-candidates:(.*)/,
- format: "remote-candidates:%s"
- },
- { //a=ice-options:google-ice
- name: 'iceOptions',
- reg: /^ice-options:(\S*)/,
- format: "ice-options:%s"
- },
- { //a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1
- push: "ssrcs",
- reg: /^ssrc:(\d*) ([\w_]*):(.*)/,
- names: ['id', 'attribute', 'value'],
- format: "ssrc:%d %s:%s"
- },
- { //a=ssrc-group:FEC 1 2
- push: "ssrcGroups",
- reg: /^ssrc-group:(\w*) (.*)/,
- names: ['semantics', 'ssrcs'],
- format: "ssrc-group:%s %s"
- },
- { //a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV
- name: "msidSemantic",
- reg: /^msid-semantic:\s?(\w*) (\S*)/,
- names: ['semantic', 'token'],
- format: "msid-semantic: %s %s" // space after ":" is not accidental
- },
- { //a=group:BUNDLE audio video
- push: 'groups',
- reg: /^group:(\w*) (.*)/,
- names: ['type', 'mids'],
- format: "group:%s %s"
- },
- { //a=rtcp-mux
- name: 'rtcpMux',
- reg: /^(rtcp-mux)/
- },
- { //a=rtcp-rsize
- name: 'rtcpRsize',
- reg: /^(rtcp-rsize)/
- },
- { // any a= that we don't understand is kepts verbatim on media.invalid
- push: 'invalid',
- names: ["value"]
- }
- ]
-};
-
-// set sensible defaults to avoid polluting the grammar with boring details
-Object.keys(grammar).forEach(function (key) {
- var objs = grammar[key];
- objs.forEach(function (obj) {
- if (!obj.reg) {
- obj.reg = /(.*)/;
- }
- if (!obj.format) {
- obj.format = "%s";
- }
- });
-});
-
-},{}],92:[function(require,module,exports){
-var parser = require('./parser');
-var writer = require('./writer');
-
-exports.write = writer;
-exports.parse = parser.parse;
-exports.parseFmtpConfig = parser.parseFmtpConfig;
-exports.parsePayloads = parser.parsePayloads;
-exports.parseRemoteCandidates = parser.parseRemoteCandidates;
-
-},{"./parser":93,"./writer":94}],93:[function(require,module,exports){
-var toIntIfInt = function (v) {
- return String(Number(v)) === v ? Number(v) : v;
-};
-
-var attachProperties = function (match, location, names, rawName) {
- if (rawName && !names) {
- location[rawName] = toIntIfInt(match[1]);
- }
- else {
- for (var i = 0; i < names.length; i += 1) {
- if (match[i+1] != null) {
- location[names[i]] = toIntIfInt(match[i+1]);
- }
- }
- }
-};
-
-var parseReg = function (obj, location, content) {
- var needsBlank = obj.name && obj.names;
- if (obj.push && !location[obj.push]) {
- location[obj.push] = [];
- }
- else if (needsBlank && !location[obj.name]) {
- location[obj.name] = {};
- }
- var keyLocation = obj.push ?
- {} : // blank object that will be pushed
- needsBlank ? location[obj.name] : location; // otherwise, named location or root
-
- attachProperties(content.match(obj.reg), keyLocation, obj.names, obj.name);
-
- if (obj.push) {
- location[obj.push].push(keyLocation);
- }
-};
-
-var grammar = require('./grammar');
-var validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/);
-
-exports.parse = function (sdp) {
- var session = {}
- , media = []
- , location = session; // points at where properties go under (one of the above)
-
- // parse lines we understand
- sdp.split(/(\r\n|\r|\n)/).filter(validLine).forEach(function (l) {
- var type = l[0];
- var content = l.slice(2);
- if (type === 'm') {
- media.push({rtp: [], fmtp: []});
- location = media[media.length-1]; // point at latest media line
- }
-
- for (var j = 0; j < (grammar[type] || []).length; j += 1) {
- var obj = grammar[type][j];
- if (obj.reg.test(content)) {
- return parseReg(obj, location, content);
- }
- }
- });
-
- session.media = media; // link it up
- return session;
-};
-
-var fmtpReducer = function (acc, expr) {
- var s = expr.split('=');
- if (s.length === 2) {
- acc[s[0]] = toIntIfInt(s[1]);
- }
- return acc;
-};
-
-exports.parseFmtpConfig = function (str) {
- return str.split(';').reduce(fmtpReducer, {});
-};
-
-exports.parsePayloads = function (str) {
- return str.split(' ').map(Number);
-};
-
-exports.parseRemoteCandidates = function (str) {
- var candidates = [];
- var parts = str.split(' ').map(toIntIfInt);
- for (var i = 0; i < parts.length; i += 3) {
- candidates.push({
- component: parts[i],
- ip: parts[i + 1],
- port: parts[i + 2]
- });
- }
- return candidates;
-};
-
-},{"./grammar":91}],94:[function(require,module,exports){
-var grammar = require('./grammar');
-
-// customized util.format - discards excess arguments and can void middle ones
-var formatRegExp = /%[sdv%]/g;
-var format = function (formatStr) {
- var i = 1;
- var args = arguments;
- var len = args.length;
- return formatStr.replace(formatRegExp, function (x) {
- if (i >= len) {
- return x; // missing argument
- }
- var arg = args[i];
- i += 1;
- switch (x) {
- case '%%':
- return '%';
- case '%s':
- return String(arg);
- case '%d':
- return Number(arg);
- case '%v':
- return '';
- }
- });
- // NB: we discard excess arguments - they are typically undefined from makeLine
-};
-
-var makeLine = function (type, obj, location) {
- var str = obj.format instanceof Function ?
- (obj.format(obj.push ? location : location[obj.name])) :
- obj.format;
-
- var args = [type + '=' + str];
- if (obj.names) {
- for (var i = 0; i < obj.names.length; i += 1) {
- var n = obj.names[i];
- if (obj.name) {
- args.push(location[obj.name][n]);
- }
- else { // for mLine and push attributes
- args.push(location[obj.names[i]]);
- }
- }
- }
- else {
- args.push(location[obj.name]);
- }
- return format.apply(null, args);
-};
-
-// RFC specified order
-// TODO: extend this with all the rest
-var defaultOuterOrder = [
- 'v', 'o', 's', 'i',
- 'u', 'e', 'p', 'c',
- 'b', 't', 'r', 'z', 'a'
-];
-var defaultInnerOrder = ['i', 'c', 'b', 'a'];
-
-
-module.exports = function (session, opts) {
- opts = opts || {};
- // ensure certain properties exist
- if (session.version == null) {
- session.version = 0; // "v=0" must be there (only defined version atm)
- }
- if (session.name == null) {
- session.name = " "; // "s= " must be there if no meaningful name set
- }
- session.media.forEach(function (mLine) {
- if (mLine.payloads == null) {
- mLine.payloads = "";
- }
- });
-
- var outerOrder = opts.outerOrder || defaultOuterOrder;
- var innerOrder = opts.innerOrder || defaultInnerOrder;
- var sdp = [];
-
- // loop through outerOrder for matching properties on session
- outerOrder.forEach(function (type) {
- grammar[type].forEach(function (obj) {
- if (obj.name in session && session[obj.name] != null) {
- sdp.push(makeLine(type, obj, session));
- }
- else if (obj.push in session && session[obj.push] != null) {
- session[obj.push].forEach(function (el) {
- sdp.push(makeLine(type, obj, el));
- });
- }
- });
- });
-
- // then for each media line, follow the innerOrder
- session.media.forEach(function (mLine) {
- sdp.push(makeLine('m', grammar.m[0], mLine));
-
- innerOrder.forEach(function (type) {
- grammar[type].forEach(function (obj) {
- if (obj.name in mLine && mLine[obj.name] != null) {
- sdp.push(makeLine(type, obj, mLine));
- }
- else if (obj.push in mLine && mLine[obj.push] != null) {
- mLine[obj.push].forEach(function (el) {
- sdp.push(makeLine(type, obj, el));
- });
- }
- });
- });
- });
-
- return sdp.join('\r\n') + '\r\n';
-};
-
-},{"./grammar":91}],95:[function(require,module,exports){
+},{}],96:[function(require,module,exports){
+arguments[4][90][0].apply(exports,arguments)
+},{"dup":90}],97:[function(require,module,exports){
+arguments[4][91][0].apply(exports,arguments)
+},{"./parser":98,"./writer":99,"dup":91}],98:[function(require,module,exports){
+arguments[4][92][0].apply(exports,arguments)
+},{"./grammar":96,"dup":92}],99:[function(require,module,exports){
+arguments[4][93][0].apply(exports,arguments)
+},{"./grammar":96,"dup":93}],100:[function(require,module,exports){
var MediaStreamType = {
VIDEO_TYPE: "Video",
AUDIO_TYPE: "Audio"
};
module.exports = MediaStreamType;
-},{}],96:[function(require,module,exports){
+},{}],101:[function(require,module,exports){
var RTCBrowserType = {
RTC_BROWSER_CHROME: "rtc_browser.chrome",
@@ -28043,16 +28178,18 @@ var RTCBrowserType = {
};
module.exports = RTCBrowserType;
-},{}],97:[function(require,module,exports){
+},{}],102:[function(require,module,exports){
var RTCEvents = {
LASTN_CHANGED: "rtc.lastn_changed",
DOMINANTSPEAKER_CHANGED: "rtc.dominantspeaker_changed",
LASTN_ENDPOINT_CHANGED: "rtc.lastn_endpoint_changed",
- AVAILABLE_DEVICES_CHANGED: "rtc.available_devices_changed"
+ AVAILABLE_DEVICES_CHANGED: "rtc.available_devices_changed",
+ AUDIO_MUTE: "rtc.audio_mute",
+ VIDEO_MUTE: "rtc.video_mute"
};
module.exports = RTCEvents;
-},{}],98:[function(require,module,exports){
+},{}],103:[function(require,module,exports){
var Resolutions = {
"1080": {
width: 1920,
@@ -28106,7 +28243,7 @@ var Resolutions = {
}
};
module.exports = Resolutions;
-},{}],99:[function(require,module,exports){
+},{}],104:[function(require,module,exports){
var StreamEventTypes = {
EVENT_TYPE_LOCAL_CREATED: "stream.local_created",
@@ -28122,14 +28259,14 @@ var StreamEventTypes = {
};
module.exports = StreamEventTypes;
-},{}],100:[function(require,module,exports){
+},{}],105:[function(require,module,exports){
var UIEvents = {
NICKNAME_CHANGED: "UI.nickname_changed",
SELECTED_ENDPOINT: "UI.selected_endpoint",
PINNED_ENDPOINT: "UI.pinned_endpoint"
};
module.exports = UIEvents;
-},{}],101:[function(require,module,exports){
+},{}],106:[function(require,module,exports){
var AuthenticationEvents = {
/**
* Event callback arguments:
@@ -28143,7 +28280,7 @@ var AuthenticationEvents = {
};
module.exports = AuthenticationEvents;
-},{}],102:[function(require,module,exports){
+},{}],107:[function(require,module,exports){
var CQEvents = {
LOCALSTATS_UPDATED: "cq.localstats_updated",
REMOTESTATS_UPDATED: "cq.remotestats_updated",
@@ -28151,7 +28288,7 @@ var CQEvents = {
};
module.exports = CQEvents;
-},{}],103:[function(require,module,exports){
+},{}],108:[function(require,module,exports){
var DesktopSharingEventTypes = {
INIT: "ds.init",
@@ -28161,14 +28298,14 @@ var DesktopSharingEventTypes = {
};
module.exports = DesktopSharingEventTypes;
-},{}],104:[function(require,module,exports){
+},{}],109:[function(require,module,exports){
var Events = {
DTMF_SUPPORT_CHANGED: "members.dtmf_support_changed"
};
module.exports = Events;
-},{}],105:[function(require,module,exports){
+},{}],110:[function(require,module,exports){
module.exports = {
getLanguages : function () {
var languages = [];
@@ -28185,11 +28322,10 @@ module.exports = {
TR: "tr",
FR: "fr"
}
-},{}],106:[function(require,module,exports){
+},{}],111:[function(require,module,exports){
var XMPPEvents = {
CONNECTION_FAILED: "xmpp.connection.failed",
CONFERENCE_CREATED: "xmpp.conferenceCreated.jingle",
- CALL_TERMINATED: "xmpp.callterminated.jingle",
CALL_INCOMING: "xmpp.callincoming.jingle",
DISPOSE_CONFERENCE: "xmpp.dispose_conference",
GRACEFUL_SHUTDOWN: "xmpp.graceful_shutdown",
@@ -28218,10 +28354,12 @@ var XMPPEvents = {
CHAT_ERROR_RECEIVED: "xmpp.chat_error_received",
ETHERPAD: "xmpp.etherpad",
DEVICE_AVAILABLE: "xmpp.device_available",
- START_MUTED: "xmpp.start_muted"
+ START_MUTED: "xmpp.start_muted",
+ PEERCONNECTION_READY: "xmpp.peerconnection_ready",
+ CONFERENCE_SETUP_FAILED: "xmpp.conference_setup_failed"
};
module.exports = XMPPEvents;
-},{}],107:[function(require,module,exports){
+},{}],112:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
@@ -28524,73 +28662,43 @@ function isUndefined(arg) {
return arg === void 0;
}
-},{}],108:[function(require,module,exports){
+},{}],113:[function(require,module,exports){
// shim for using process in browser
var process = module.exports = {};
+var queue = [];
+var draining = false;
-process.nextTick = (function () {
- var canSetImmediate = typeof window !== 'undefined'
- && window.setImmediate;
- var canMutationObserver = typeof window !== 'undefined'
- && window.MutationObserver;
- var canPost = typeof window !== 'undefined'
- && window.postMessage && window.addEventListener
- ;
-
- if (canSetImmediate) {
- return function (f) { return window.setImmediate(f) };
+function drainQueue() {
+ if (draining) {
+ return;
}
-
- var queue = [];
-
- if (canMutationObserver) {
- var hiddenDiv = document.createElement("div");
- var observer = new MutationObserver(function () {
- var queueList = queue.slice();
- queue.length = 0;
- queueList.forEach(function (fn) {
- fn();
- });
- });
-
- observer.observe(hiddenDiv, { attributes: true });
-
- return function nextTick(fn) {
- if (!queue.length) {
- hiddenDiv.setAttribute('yes', 'no');
- }
- queue.push(fn);
- };
+ draining = true;
+ var currentQueue;
+ var len = queue.length;
+ while(len) {
+ currentQueue = queue;
+ queue = [];
+ var i = -1;
+ while (++i < len) {
+ currentQueue[i]();
+ }
+ len = queue.length;
}
-
- if (canPost) {
- window.addEventListener('message', function (ev) {
- var source = ev.source;
- if ((source === window || source === null) && ev.data === 'process-tick') {
- ev.stopPropagation();
- if (queue.length > 0) {
- var fn = queue.shift();
- fn();
- }
- }
- }, true);
-
- return function nextTick(fn) {
- queue.push(fn);
- window.postMessage('process-tick', '*');
- };
+ draining = false;
+}
+process.nextTick = function (fun) {
+ queue.push(fun);
+ if (!draining) {
+ setTimeout(drainQueue, 0);
}
-
- return function nextTick(fn) {
- setTimeout(fn, 0);
- };
-})();
+};
process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];
+process.version = ''; // empty string to avoid regexp issues
function noop() {}
@@ -28611,6 +28719,7 @@ process.cwd = function () { return '/' };
process.chdir = function (dir) {
throw new Error('process.chdir is not supported');
};
+process.umask = function() { return 0; };
},{}]},{},[1])(1)
});
\ No newline at end of file
diff --git a/modules/RTC/LocalStream.js b/modules/RTC/LocalStream.js
index 69d8efb6f..342fbb57c 100644
--- a/modules/RTC/LocalStream.js
+++ b/modules/RTC/LocalStream.js
@@ -1,4 +1,5 @@
var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
+var RTCEvents = require("../../service/RTC/RTCEvents");
function LocalStream(stream, type, eventEmitter, videoType, isGUMStream)
@@ -54,12 +55,18 @@ LocalStream.prototype.setMute = function(mute)
for (var idx = 0; idx < tracks.length; idx++) {
tracks[idx].enabled = mute;
}
+ this.eventEmitter.emit(
+ (this.type == "audio"? RTCEvents.AUDIO_MUTE : RTCEvents.VIDEO_MUTE),
+ !mute);
}
else
{
if(mute === false) {
APP.xmpp.removeStream(this.stream);
this.stream.stop();
+ this.eventEmitter.emit(
+ (this.type == "audio"? RTCEvents.AUDIO_MUTE : RTCEvents.VIDEO_MUTE),
+ true);
}
else
{
@@ -69,11 +76,21 @@ LocalStream.prototype.setMute = function(mute)
function (stream) {
if(self.isAudioStream())
{
- APP.RTC.changeLocalAudio(stream, function () {});
+ APP.RTC.changeLocalAudio(stream,
+ function () {
+ self.eventEmitter.emit(
+ (self.type == "audio"? RTCEvents.AUDIO_MUTE : RTCEvents.VIDEO_MUTE),
+ true);
+ });
}
else
{
- APP.RTC.changeLocalVideo(stream, false, function () {});
+ APP.RTC.changeLocalVideo(stream, false,
+ function () {
+ self.eventEmitter.emit(
+ (self.type == "audio"? RTCEvents.AUDIO_MUTE : RTCEvents.VIDEO_MUTE),
+ true);
+ });
}
});
}
diff --git a/modules/UI/videolayout/VideoLayout.js b/modules/UI/videolayout/VideoLayout.js
index 85d5ce1a3..a7bcdda56 100644
--- a/modules/UI/videolayout/VideoLayout.js
+++ b/modules/UI/videolayout/VideoLayout.js
@@ -808,7 +808,7 @@ var VideoLayout = (function (my) {
my.onStatsStop = function () {
for(var video in remoteVideos)
{
- video.hideIndicator();
+ remoteVideos[video].hideIndicator();
}
localVideoThumbnail.hideIndicator();
};
diff --git a/modules/statistics/CallStats.js b/modules/statistics/CallStats.js
new file mode 100644
index 000000000..7453d2aa7
--- /dev/null
+++ b/modules/statistics/CallStats.js
@@ -0,0 +1,76 @@
+var callStats = null;
+
+function initCallback (err, msg) {
+ console.log("Initializing Status: err="+err+" msg="+msg);
+}
+
+var CallStats = {
+ init: function (jingleSession) {
+
+ if(!config.callStatsID || !config.callStatsSecret || callStats !== null)
+ return;
+
+ callStats = new callstats($,io,jsSHA);
+
+ this.session = jingleSession;
+ this.peerconnection = jingleSession.peerconnection.peerconnection;
+
+ this.userID = APP.xmpp.myResource();
+
+ var roomJid = APP.UI.getRoomName();
+ this.confID = roomJid? Strophe.getNodeFromJid(roomJid) : null;
+
+ //userID is generated or given by the origin server
+ callStats.initialize(config.callStatsID,
+ config.callStatsSecret,
+ this.userID,
+ initCallback);
+
+ var usage = callStats.fabricUsage.unbundled;
+ if(config.useBundle)
+ usage = callStats.fabricUsage.multiplex;
+
+ callStats.addNewFabric(this.peerconnection,
+ Strophe.getResourceFromJid(jingleSession.peerjid),
+ usage,
+ this.confID,
+ this.pcCallback.bind(this));
+ },
+ pcCallback: function (err, msg) {
+ if(!callStats)
+ return;
+ console.log("Monitoring status: "+ err + " msg: " + msg);
+ callStats.sendFabricEvent(this.peerconnection,
+ callStats.fabricEvent.fabricSetup, this.confID);
+ },
+ sendMuteEvent: function (mute, type) {
+ if(!callStats)
+ return;
+ var event = null;
+ if(type === "video")
+ {
+ event = (mute? callStats.fabricEvent.videoPause :
+ callStats.fabricEvent.videoResume);
+ }
+ else
+ {
+ event = (mute? callStats.fabricEvent.audioMute :
+ callStats.fabricEvent.audioUnmute);
+ }
+ callStats.sendFabricEvent(this.peerconnection, event, this.confID);
+ },
+ sendTerminateEvent: function () {
+ if(!callStats)
+ return;
+ callStats.sendFabricEvent(this.peerconnection,
+ callStats.fabricEvent.fabricTerminated, this.confID);
+ },
+ sendSetupFailedEvent: function () {
+ if(!callStats)
+ return;
+ callStats.sendFabricEvent(this.peerconnection,
+ callStats.fabricEvent.fabricSetupFailed, this.confID);
+ }
+
+};
+module.exports = CallStats;
\ No newline at end of file
diff --git a/modules/statistics/statistics.js b/modules/statistics/statistics.js
index 1031ec5ed..9889cc69a 100644
--- a/modules/statistics/statistics.js
+++ b/modules/statistics/statistics.js
@@ -6,6 +6,8 @@ var RTPStats = require("./RTPStatsCollector.js");
var EventEmitter = require("events");
var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
+var CallStats = require("./callstats");
+var RTCEvents = require("../../service/RTC/RTCEvents");
var eventEmitter = new EventEmitter();
@@ -54,6 +56,7 @@ function onStreamCreated(stream)
}
function onDisposeConference(onUnload) {
+ CallStats.sendTerminateEvent();
stopRemote();
if(onUnload) {
stopLocal();
@@ -119,8 +122,22 @@ var statistics =
APP.RTC.addStreamListener(onStreamCreated,
StreamEventTypes.EVENT_TYPE_LOCAL_CREATED);
APP.xmpp.addListener(XMPPEvents.DISPOSE_CONFERENCE, onDisposeConference);
+ //FIXME: we may want to change CALL INCOMING event to onnegotiationneeded
APP.xmpp.addListener(XMPPEvents.CALL_INCOMING, function (event) {
startRemoteStats(event.peerconnection);
+// CallStats.init(event);
+ });
+ APP.xmpp.addListener(XMPPEvents.PEERCONNECTION_READY, function (session) {
+ CallStats.init(session);
+ })
+ APP.RTC.addListener(RTCEvents.AUDIO_MUTE, function (mute) {
+ CallStats.sendMuteEvent(mute, "audio");
+ });
+ APP.xmpp.addListener(XMPPEvents.CONFERENCE_SETUP_FAILED, function () {
+ CallStats.sendSetupFailedEvent();
+ })
+ APP.RTC.addListener(RTCEvents.VIDEO_MUTE, function (mute) {
+ CallStats.sendMuteEvent(mute, "video");
});
}
diff --git a/modules/xmpp/JingleSession.js b/modules/xmpp/JingleSession.js
index 8a91706ef..99253cf37 100644
--- a/modules/xmpp/JingleSession.js
+++ b/modules/xmpp/JingleSession.js
@@ -3,12 +3,12 @@ var TraceablePeerConnection = require("./TraceablePeerConnection");
var SDPDiffer = require("./SDPDiffer");
var SDPUtil = require("./SDPUtil");
var SDP = require("./SDP");
-var RTCBrowserType = require("../../service/RTC/RTCBrowserType");
var async = require("async");
var transform = require("sdp-transform");
+var XMPPEvents = require("../../service/xmpp/XMPPEvents");
// Jingle stuff
-function JingleSession(me, sid, connection, service) {
+function JingleSession(me, sid, connection, service, eventEmitter) {
this.me = me;
this.sid = sid;
this.connection = connection;
@@ -47,6 +47,7 @@ function JingleSession(me, sid, connection, service) {
this.wait = true;
this.localStreamsSSRC = null;
+ this.eventEmitter = eventEmitter;
/**
* The indicator which determines whether the (local) video has been muted
@@ -89,7 +90,8 @@ JingleSession.prototype.initiate = function (peerjid, isInitiator) {
this.peerconnection
= new TraceablePeerConnection(
this.connection.jingle.ice_config,
- this.connection.jingle.pc_constraints );
+ this.connection.jingle.pc_constraints,
+ this);
this.peerconnection.onicecandidate = function (event) {
self.sendIceCandidate(event.candidate);
@@ -125,9 +127,15 @@ JingleSession.prototype.initiate = function (peerjid, isInitiator) {
case 'disconnected':
this.stopTime = new Date();
break;
+ case 'failed':
+ self.eventEmitter(XMPPEvents.CONFERENCE_SETUP_FAILED);
+ break;
}
onIceConnectionStateChange(self.sid, self);
};
+ this.peerconnection.onnegotiationneeded = function (event) {
+ self.eventEmitter.emit(XMPPEvents.PEERCONNECTION_READY, self);
+ };
// add any local and relayed stream
APP.RTC.localStreams.forEach(function(stream) {
self.peerconnection.addStream(stream.getOriginalStream());
@@ -238,6 +246,7 @@ JingleSession.prototype.accept = function () {
},
function (e) {
console.error('setLocalDescription failed', e);
+ self.eventEmitter.emit(XMPPEvents.CONFERENCE_SETUP_FAILED);
}
);
};
@@ -448,6 +457,7 @@ JingleSession.prototype.createdOffer = function (sdp) {
},
function (e) {
console.error('setLocalDescription failed', e);
+ self.eventEmitter.emit(XMPPEvents.CONFERENCE_SETUP_FAILED);
}
);
var cands = SDPUtil.find_lines(this.localSDP.raw, 'a=candidate:');
@@ -622,6 +632,7 @@ JingleSession.prototype.sendAnswer = function (provisional) {
},
function (e) {
console.error('createAnswer failed', e);
+ self.eventEmitter.emit(XMPPEvents.CONFERENCE_SETUP_FAILED);
},
this.media_constraints
);
@@ -681,6 +692,7 @@ JingleSession.prototype.createdAnswer = function (sdp, provisional) {
},
function (e) {
console.error('setLocalDescription failed', e);
+ self.eventEmitter.emit(XMPPEvents.CONFERENCE_SETUP_FAILED);
}
);
var cands = SDPUtil.find_lines(this.localSDP.raw, 'a=candidate:');
@@ -1232,6 +1244,7 @@ JingleSession.onJingleFatalError = function (session, error)
this.connection.emuc.doLeave();
APP.UI.messageHandler.showError("dialog.sorry",
"dialog.internalError");
+ this.eventEmitter.emit(XMPPEvents.CONFERENCE_SETUP_FAILED);
}
JingleSession.prototype.setLocalDescription = function () {
@@ -1287,6 +1300,7 @@ JingleSession.prototype.setLocalDescription = function () {
function sendKeyframe(pc) {
console.log('sendkeyframe', pc.iceConnectionState);
if (pc.iceConnectionState !== 'connected') return; // safe...
+ var self = this;
pc.setRemoteDescription(
pc.remoteDescription,
function () {
diff --git a/modules/xmpp/TraceablePeerConnection.js b/modules/xmpp/TraceablePeerConnection.js
index 50d2e4a18..519097438 100644
--- a/modules/xmpp/TraceablePeerConnection.js
+++ b/modules/xmpp/TraceablePeerConnection.js
@@ -1,4 +1,6 @@
-function TraceablePeerConnection(ice_config, constraints) {
+var XMPPEvents = require("../../service/xmpp/XMPPEvents");
+
+function TraceablePeerConnection(ice_config, constraints, session) {
var self = this;
var RTCPeerconnection = navigator.mozGetUserMedia ? mozRTCPeerConnection : webkitRTCPeerConnection;
this.peerconnection = new RTCPeerconnection(ice_config, constraints);
diff --git a/modules/xmpp/strophe.jingle.js b/modules/xmpp/strophe.jingle.js
index 491c54c19..e72fba575 100644
--- a/modules/xmpp/strophe.jingle.js
+++ b/modules/xmpp/strophe.jingle.js
@@ -119,7 +119,7 @@ module.exports = function(XMPP, eventEmitter)
}
sess = new JingleSession(
$(iq).attr('to'), $(iq).find('jingle').attr('sid'),
- this.connection, XMPP);
+ this.connection, XMPP, eventEmitter);
// configure session
sess.media_constraints = this.media_constraints;
@@ -199,7 +199,7 @@ module.exports = function(XMPP, eventEmitter)
initiate: function (peerjid, myjid) { // initiate a new jinglesession to peerjid
var sess = new JingleSession(myjid || this.connection.jid,
Math.random().toString(36).substr(2, 12), // random string
- this.connection, XMPP);
+ this.connection, XMPP, eventEmitter);
// configure session
sess.media_constraints = this.media_constraints;
diff --git a/modules/xmpp/xmpp.js b/modules/xmpp/xmpp.js
index c9f29d01e..6587bf524 100644
--- a/modules/xmpp/xmpp.js
+++ b/modules/xmpp/xmpp.js
@@ -315,7 +315,6 @@ var XMPP = {
return Strophe.getResourceFromJid(connection.emuc.myroomjid);
},
disposeConference: function (onUnload) {
- eventEmitter.emit(XMPPEvents.DISPOSE_CONFERENCE, onUnload);
var handler = connection.jingle.activecall;
if (handler && handler.peerconnection) {
// FIXME: probably removing streams is not required and close() should
@@ -330,6 +329,7 @@ var XMPP = {
}
handler.peerconnection.close();
}
+ eventEmitter.emit(XMPPEvents.DISPOSE_CONFERENCE, onUnload);
connection.jingle.activecall = null;
if(!onUnload)
{
diff --git a/service/RTC/RTCEvents.js b/service/RTC/RTCEvents.js
index a53115712..3944c706f 100644
--- a/service/RTC/RTCEvents.js
+++ b/service/RTC/RTCEvents.js
@@ -2,7 +2,9 @@ var RTCEvents = {
LASTN_CHANGED: "rtc.lastn_changed",
DOMINANTSPEAKER_CHANGED: "rtc.dominantspeaker_changed",
LASTN_ENDPOINT_CHANGED: "rtc.lastn_endpoint_changed",
- AVAILABLE_DEVICES_CHANGED: "rtc.available_devices_changed"
+ AVAILABLE_DEVICES_CHANGED: "rtc.available_devices_changed",
+ AUDIO_MUTE: "rtc.audio_mute",
+ VIDEO_MUTE: "rtc.video_mute"
};
module.exports = RTCEvents;
\ No newline at end of file
diff --git a/service/xmpp/XMPPEvents.js b/service/xmpp/XMPPEvents.js
index 66047ff1c..68b6ed8a7 100644
--- a/service/xmpp/XMPPEvents.js
+++ b/service/xmpp/XMPPEvents.js
@@ -1,7 +1,6 @@
var XMPPEvents = {
CONNECTION_FAILED: "xmpp.connection.failed",
CONFERENCE_CREATED: "xmpp.conferenceCreated.jingle",
- CALL_TERMINATED: "xmpp.callterminated.jingle",
CALL_INCOMING: "xmpp.callincoming.jingle",
DISPOSE_CONFERENCE: "xmpp.dispose_conference",
GRACEFUL_SHUTDOWN: "xmpp.graceful_shutdown",
@@ -30,6 +29,8 @@ var XMPPEvents = {
CHAT_ERROR_RECEIVED: "xmpp.chat_error_received",
ETHERPAD: "xmpp.etherpad",
DEVICE_AVAILABLE: "xmpp.device_available",
- START_MUTED: "xmpp.start_muted"
+ START_MUTED: "xmpp.start_muted",
+ PEERCONNECTION_READY: "xmpp.peerconnection_ready",
+ CONFERENCE_SETUP_FAILED: "xmpp.conference_setup_failed"
};
module.exports = XMPPEvents;
\ No newline at end of file