diff --git a/JitsiConference.js b/JitsiConference.js
index 143349448..fc93196e8 100644
--- a/JitsiConference.js
+++ b/JitsiConference.js
@@ -496,6 +496,84 @@ JitsiConference.prototype.sendTones = function (tones, duration, pause) {
this.dtmfManager.sendTones(tones, duration, pause);
};
+/**
+ * Returns true if the recording is supproted and false if not.
+ */
+JitsiConference.prototype.isRecordingSupported = function () {
+ if(this.room)
+ return this.room.isRecordingSupported();
+ return false;
+};
+
+/**
+ * Returns null if the recording is not supported, "on" if the recording started
+ * and "off" if the recording is not started.
+ */
+JitsiConference.prototype.getRecordingState = function () {
+ if(this.room)
+ return this.room.getRecordingState();
+ return "off";
+}
+
+/**
+ * Returns the url of the recorded video.
+ */
+JitsiConference.prototype.getRecordingURL = function () {
+ if(this.room)
+ return this.room.getRecordingURL();
+ return null;
+}
+
+/**
+ * Starts/stops the recording
+ * @param token a token for authentication.
+ */
+JitsiConference.prototype.toggleRecording = function (token, followEntity) {
+ if(this.room)
+ return this.room.toggleRecording(token, followEntity);
+ return new Promise(function(resolve, reject){
+ reject(new Error("The conference is not created yet!"))});
+}
+
+/**
+ * Dials a number.
+ * @param number the number
+ */
+JitsiConference.prototype.dial = function (number) {
+ if(this.room)
+ return this.room.dial(number);
+ return new Promise(function(resolve, reject){
+ reject(new Error("The conference is not created yet!"))});
+}
+
+/**
+ * Hangup an existing call
+ */
+JitsiConference.prototype.hangup = function () {
+ if(this.room)
+ return this.room.hangup();
+ return new Promise(function(resolve, reject){
+ reject(new Error("The conference is not created yet!"))});
+}
+
+/**
+ * Returns the phone number for joining the conference.
+ */
+JitsiConference.prototype.getPhoneNumber = function () {
+ if(this.room)
+ return this.room.getPhoneNumber();
+ return null;
+}
+
+/**
+ * Returns the pin for joining the conference with phone.
+ */
+JitsiConference.prototype.getPhonePin = function () {
+ if(this.room)
+ return this.room.getPhonePin();
+ return null;
+}
+
/**
* Returns the connection state for the current room. Its ice connection state
* for its session.
@@ -560,6 +638,17 @@ function setupListeners(conference) {
conference.eventEmitter.emit(JitsiConferenceEvents.CONNECTION_INTERRUPTED);
});
+ conference.room.addListener(XMPPEvents.RECORDING_STATE_CHANGED,
+ function () {
+ conference.eventEmitter.emit(
+ JitsiConferenceEvents.RECORDING_STATE_CHANGED);
+ });
+
+ conference.room.addListener(XMPPEvents.PHONE_NUMBER_CHANGED, function () {
+ conference.eventEmitter.emit(
+ JitsiConferenceEvents.PHONE_NUMBER_CHANGED);
+ });
+
conference.room.addListener(XMPPEvents.CONNECTION_RESTORED, function () {
conference.eventEmitter.emit(JitsiConferenceEvents.CONNECTION_RESTORED);
});
diff --git a/JitsiConferenceEvents.js b/JitsiConferenceEvents.js
index 57aa87ace..a597fc045 100644
--- a/JitsiConferenceEvents.js
+++ b/JitsiConferenceEvents.js
@@ -83,7 +83,15 @@ var JitsiConferenceEvents = {
/**
* Indicates that DTMF support changed.
*/
- DTMF_SUPPORT_CHANGED: "conference.dtmfSupportChanged"
+ DTMF_SUPPORT_CHANGED: "conference.dtmfSupportChanged",
+ /**
+ * Indicates that recording state changed.
+ */
+ RECORDING_STATE_CHANGED: "conference.recordingStateChanged",
+ /**
+ * Indicates that phone number changed.
+ */
+ PHONE_NUMBER_CHANGED: "conference.phoneNumberChanged"
};
module.exports = JitsiConferenceEvents;
diff --git a/JitsiConnection.js b/JitsiConnection.js
index 8ce737e36..ef1d749d2 100644
--- a/JitsiConnection.js
+++ b/JitsiConnection.js
@@ -8,9 +8,8 @@ var RandomUtil = require("./modules/util/RandomUtil");
* @returns {string}
*/
function generateUserName() {
- return RandomUtil.randomHexString(8) + "-" + RandomUtil.randomHexString(4) +
- "-" + RandomUtil.randomHexString(4) + "-" +
- RandomUtil.randomHexDigit(8);
+ return RandomUtil.random8digitsHex() + "-" + RandomUtil.random4digitsHex() + "-" +
+ RandomUtil.random4digitsHex() + "-" + RandomUtil.random8digitsHex();
}
/**
diff --git a/doc/example/example.js b/doc/example/example.js
index e5b4c76a4..181fc5910 100644
--- a/doc/example/example.js
+++ b/doc/example/example.js
@@ -1,10 +1,12 @@
var options = {
hosts: {
- domain: 'hristo.jitsi.net',
- muc: 'conference.hristo.jitsi.net', // FIXME: use XEP-0030
- bridge: 'jitsi-videobridge.hristo.jitsi.net', // FIXME: use XEP-0030
+ call_control: "callcontrol.chaos.hipchat.me",
+ focus: "focus.chaos.hipchat.me",
+ domain: 'chaos.hipchat.me',
+ muc: 'conference.chaos.hipchat.me', // FIXME: use XEP-0030
+ bridge: 'jitsi-videobridge.chaos.hipchat.me', // FIXME: use XEP-0030
},
- bosh: '//hristo.jitsi.net/http-bind', // FIXME: use xep-0156 for that
+ bosh: '//chaos.hipchat.me/http-bind', // FIXME: use xep-0156 for that
clientNode: 'http://jitsi.org/jitsimeet', // The name of client node advertised in XEP-0115 'c' stanza
}
@@ -40,7 +42,7 @@ function onLocalTracks(tracks)
$("body").append("");
localTracks[i].attach($("#localVideo" + i ));
} else {
- $("body").append("");
+ $("body").append("");
localTracks[i].attach($("#localAudio" + i ));
}
if(isJoined)
@@ -91,6 +93,7 @@ function onConferenceJoined () {
}
function onUserLeft(id) {
+ console.log("user left");
if(!remoteTracks[id])
return;
var tracks = remoteTracks[id];
@@ -102,13 +105,13 @@ function onUserLeft(id) {
* That function is called when connection is established successfully
*/
function onConnectionSuccess(){
- room = connection.initJitsiConference("conference2", confOptions);
+ room = connection.initJitsiConference("conference11", confOptions);
room.on(JitsiMeetJS.events.conference.TRACK_ADDED, onRemoteTrack);
room.on(JitsiMeetJS.events.conference.TRACK_REMOVED, function (track) {
console.log("track removed!!!" + track);
});
room.on(JitsiMeetJS.events.conference.CONFERENCE_JOINED, onConferenceJoined);
- room.on(JitsiMeetJS.events.conference.USER_JOINED, function(id){ remoteTracks[id] = [];});
+ room.on(JitsiMeetJS.events.conference.USER_JOINED, function(id){ console.log("user join");remoteTracks[id] = [];});
room.on(JitsiMeetJS.events.conference.USER_LEFT, onUserLeft);
room.on(JitsiMeetJS.events.conference.TRACK_MUTE_CHANGED, function (track) {
console.log(track.getType() + " - " + track.isMuted());
@@ -120,6 +123,16 @@ function onConnectionSuccess(){
function(userID, audioLevel){
console.log(userID + " - " + audioLevel);
});
+ room.on(JitsiMeetJS.events.conference.RECORDING_STATE_CHANGED, function () {
+ console.log(room.isRecordingSupported() + " - " +
+ room.getRecordingState() + " - " +
+ room.getRecordingURL());
+ });
+ room.on(JitsiMeetJS.events.conference.PHONE_NUMBER_CHANGED, function () {
+ console.log(
+ room.getPhoneNumber() + " - " +
+ room.getPhonePin());
+ });
room.join();
};
diff --git a/lib-jitsi-meet.js b/lib-jitsi-meet.js
index 57db95810..0d7ed22ba 100644
--- a/lib-jitsi-meet.js
+++ b/lib-jitsi-meet.js
@@ -498,6 +498,84 @@ JitsiConference.prototype.sendTones = function (tones, duration, pause) {
this.dtmfManager.sendTones(tones, duration, pause);
};
+/**
+ * Returns true if the recording is supproted and false if not.
+ */
+JitsiConference.prototype.isRecordingSupported = function () {
+ if(this.room)
+ return this.room.isRecordingSupported();
+ return false;
+};
+
+/**
+ * Returns null if the recording is not supported, "on" if the recording started
+ * and "off" if the recording is not started.
+ */
+JitsiConference.prototype.getRecordingState = function () {
+ if(this.room)
+ return this.room.getRecordingState();
+ return "off";
+}
+
+/**
+ * Returns the url of the recorded video.
+ */
+JitsiConference.prototype.getRecordingURL = function () {
+ if(this.room)
+ return this.room.getRecordingURL();
+ return null;
+}
+
+/**
+ * Starts/stops the recording
+ * @param token a token for authentication.
+ */
+JitsiConference.prototype.toggleRecording = function (token, followEntity) {
+ if(this.room)
+ return this.room.toggleRecording(token, followEntity);
+ return new Promise(function(resolve, reject){
+ reject(new Error("The conference is not created yet!"))});
+}
+
+/**
+ * Dials a number.
+ * @param number the number
+ */
+JitsiConference.prototype.dial = function (number) {
+ if(this.room)
+ return this.room.dial(number);
+ return new Promise(function(resolve, reject){
+ reject(new Error("The conference is not created yet!"))});
+}
+
+/**
+ * Hangup an existing call
+ */
+JitsiConference.prototype.hangup = function () {
+ if(this.room)
+ return this.room.hangup();
+ return new Promise(function(resolve, reject){
+ reject(new Error("The conference is not created yet!"))});
+}
+
+/**
+ * Returns the phone number for joining the conference.
+ */
+JitsiConference.prototype.getPhoneNumber = function () {
+ if(this.room)
+ return this.room.getPhoneNumber();
+ return null;
+}
+
+/**
+ * Returns the pin for joining the conference with phone.
+ */
+JitsiConference.prototype.getPhonePin = function () {
+ if(this.room)
+ return this.room.getPhonePin();
+ return null;
+}
+
/**
* Returns the connection state for the current room. Its ice connection state
* for its session.
@@ -562,6 +640,17 @@ function setupListeners(conference) {
conference.eventEmitter.emit(JitsiConferenceEvents.CONNECTION_INTERRUPTED);
});
+ conference.room.addListener(XMPPEvents.RECORDING_STATE_CHANGED,
+ function () {
+ conference.eventEmitter.emit(
+ JitsiConferenceEvents.RECORDING_STATE_CHANGED);
+ });
+
+ conference.room.addListener(XMPPEvents.PHONE_NUMBER_CHANGED, function () {
+ conference.eventEmitter.emit(
+ JitsiConferenceEvents.PHONE_NUMBER_CHANGED);
+ });
+
conference.room.addListener(XMPPEvents.CONNECTION_RESTORED, function () {
conference.eventEmitter.emit(JitsiConferenceEvents.CONNECTION_RESTORED);
});
@@ -619,7 +708,7 @@ function setupListeners(conference) {
module.exports = JitsiConference;
}).call(this,"/JitsiConference.js")
-},{"./JitsiConferenceErrors":2,"./JitsiConferenceEvents":3,"./JitsiParticipant":8,"./JitsiTrackEvents":10,"./modules/DTMF/JitsiDTMFManager":11,"./modules/RTC/RTC":16,"./modules/statistics/statistics":24,"./service/RTC/RTCEvents":79,"./service/xmpp/XMPPEvents":85,"events":43,"jitsi-meet-logger":47}],2:[function(require,module,exports){
+},{"./JitsiConferenceErrors":2,"./JitsiConferenceEvents":3,"./JitsiParticipant":8,"./JitsiTrackEvents":10,"./modules/DTMF/JitsiDTMFManager":11,"./modules/RTC/RTC":16,"./modules/statistics/statistics":24,"./service/RTC/RTCEvents":80,"./service/xmpp/XMPPEvents":87,"events":44,"jitsi-meet-logger":48}],2:[function(require,module,exports){
/**
* Enumeration with the errors for the conference.
* @type {{string: string}}
@@ -743,7 +832,15 @@ var JitsiConferenceEvents = {
/**
* Indicates that DTMF support changed.
*/
- DTMF_SUPPORT_CHANGED: "conference.dtmfSupportChanged"
+ DTMF_SUPPORT_CHANGED: "conference.dtmfSupportChanged",
+ /**
+ * Indicates that recording state changed.
+ */
+ RECORDING_STATE_CHANGED: "conference.recordingStateChanged",
+ /**
+ * Indicates that phone number changed.
+ */
+ PHONE_NUMBER_CHANGED: "conference.phoneNumberChanged"
};
module.exports = JitsiConferenceEvents;
@@ -759,9 +856,8 @@ var RandomUtil = require("./modules/util/RandomUtil");
* @returns {string}
*/
function generateUserName() {
- return RandomUtil.randomHexString(8) + "-" + RandomUtil.randomHexString(4) +
- "-" + RandomUtil.randomHexString(4) + "-" +
- RandomUtil.randomHexDigit(8);
+ return RandomUtil.random8digitsHex() + "-" + RandomUtil.random4digitsHex() + "-" +
+ RandomUtil.random4digitsHex() + "-" + RandomUtil.random8digitsHex();
}
/**
@@ -849,7 +945,7 @@ JitsiConnection.prototype.removeEventListener = function (event, listener) {
module.exports = JitsiConnection;
-},{"./JitsiConference":1,"./modules/util/RandomUtil":25,"./modules/xmpp/xmpp":41}],5:[function(require,module,exports){
+},{"./JitsiConference":1,"./modules/util/RandomUtil":25,"./modules/xmpp/xmpp":42}],5:[function(require,module,exports){
/**
* Enumeration with the errors for the connection.
* @type {{string: string}}
@@ -995,7 +1091,7 @@ window.Promise = window.Promise || require("es6-promise").Promise;
module.exports = LibJitsiMeet;
-},{"./JitsiConferenceErrors":2,"./JitsiConferenceEvents":3,"./JitsiConnection":4,"./JitsiConnectionErrors":5,"./JitsiConnectionEvents":6,"./JitsiTrackErrors":9,"./JitsiTrackEvents":10,"./modules/RTC/RTC":16,"./modules/statistics/statistics":24,"es6-promise":45,"jitsi-meet-logger":47}],8:[function(require,module,exports){
+},{"./JitsiConferenceErrors":2,"./JitsiConferenceEvents":3,"./JitsiConnection":4,"./JitsiConnectionErrors":5,"./JitsiConnectionEvents":6,"./JitsiTrackErrors":9,"./JitsiTrackEvents":10,"./modules/RTC/RTC":16,"./modules/statistics/statistics":24,"es6-promise":46,"jitsi-meet-logger":48}],8:[function(require,module,exports){
/**
* Represents a participant in (a member of) a conference.
*/
@@ -1201,7 +1297,7 @@ JitsiDTMFManager.prototype.sendTones = function (tones, duration, pause) {
};
}).call(this,"/modules/DTMF/JitsiDTMFManager.js")
-},{"jitsi-meet-logger":47}],12:[function(require,module,exports){
+},{"jitsi-meet-logger":48}],12:[function(require,module,exports){
(function (__filename){
/* global config, APP, Strophe */
@@ -1417,7 +1513,7 @@ module.exports = DataChannels;
}).call(this,"/modules/RTC/DataChannels.js")
-},{"../../service/RTC/RTCEvents":79,"jitsi-meet-logger":47}],13:[function(require,module,exports){
+},{"../../service/RTC/RTCEvents":80,"jitsi-meet-logger":48}],13:[function(require,module,exports){
var JitsiTrack = require("./JitsiTrack");
var RTCBrowserType = require("./RTCBrowserType");
var JitsiTrackEvents = require('../../JitsiTrackEvents');
@@ -1906,7 +2002,7 @@ JitsiTrack.prototype.setAudioLevel = function (audioLevel) {
module.exports = JitsiTrack;
-},{"../../JitsiTrackEvents":10,"./RTCBrowserType":17,"./RTCUtils":18,"events":43}],16:[function(require,module,exports){
+},{"../../JitsiTrackEvents":10,"./RTCBrowserType":17,"./RTCUtils":18,"events":44}],16:[function(require,module,exports){
/* global APP */
var EventEmitter = require("events");
var RTCBrowserType = require("./RTCBrowserType");
@@ -2128,7 +2224,7 @@ RTC.prototype.setAudioLevel = function (jid, audioLevel) {
}
module.exports = RTC;
-},{"../../service/RTC/MediaStreamTypes":78,"../../service/RTC/RTCEvents.js":79,"../../service/desktopsharing/DesktopSharingEventTypes":82,"./DataChannels":12,"./JitsiLocalTrack.js":13,"./JitsiRemoteTrack.js":14,"./JitsiTrack":15,"./RTCBrowserType":17,"./RTCUtils.js":18,"events":43}],17:[function(require,module,exports){
+},{"../../service/RTC/MediaStreamTypes":79,"../../service/RTC/RTCEvents.js":80,"../../service/desktopsharing/DesktopSharingEventTypes":84,"./DataChannels":12,"./JitsiLocalTrack.js":13,"./JitsiRemoteTrack.js":14,"./JitsiTrack":15,"./RTCBrowserType":17,"./RTCUtils.js":18,"events":44}],17:[function(require,module,exports){
var currentBrowser;
@@ -2292,8 +2388,9 @@ function detectBrowser() {
if (version)
return version;
}
- console.error("Failed to detect browser type");
- return undefined;
+ console.warn("Browser type defaults to Safari ver 1");
+ currentBrowser = RTCBrowserType.RTC_BROWSER_SAFARI;
+ return 1;
}
browserVersion = detectBrowser();
@@ -3074,7 +3171,7 @@ var RTCUtils = {
module.exports = RTCUtils;
}).call(this,"/modules/RTC/RTCUtils.js")
-},{"../../JitsiTrackErrors":9,"../../service/RTC/RTCEvents":79,"../../service/RTC/Resolutions":80,"../xmpp/SDPUtil":32,"./RTCBrowserType":17,"./ScreenObtainer":19,"./adapter.screenshare":20,"events":43,"jitsi-meet-logger":47}],19:[function(require,module,exports){
+},{"../../JitsiTrackErrors":9,"../../service/RTC/RTCEvents":80,"../../service/RTC/Resolutions":81,"../xmpp/SDPUtil":32,"./RTCBrowserType":17,"./ScreenObtainer":19,"./adapter.screenshare":20,"events":44,"jitsi-meet-logger":48}],19:[function(require,module,exports){
(function (__filename){
/* global chrome, $, alert */
/* jshint -W003 */
@@ -3496,7 +3593,7 @@ function initFirefoxExtensionDetection(options) {
module.exports = ScreenObtainer;
}).call(this,"/modules/RTC/ScreenObtainer.js")
-},{"../../service/desktopsharing/DesktopSharingEventTypes":82,"./RTCBrowserType":17,"./adapter.screenshare":20,"jitsi-meet-logger":47}],20:[function(require,module,exports){
+},{"../../service/desktopsharing/DesktopSharingEventTypes":84,"./RTCBrowserType":17,"./adapter.screenshare":20,"jitsi-meet-logger":48}],20:[function(require,module,exports){
(function (__filename){
/*! adapterjs - v0.12.3 - 2015-11-16 */
var console = require("jitsi-meet-logger").getLogger(__filename);
@@ -4680,7 +4777,7 @@ if (navigator.mozGetUserMedia) {
}
}).call(this,"/modules/RTC/adapter.screenshare.js")
-},{"jitsi-meet-logger":47}],21:[function(require,module,exports){
+},{"jitsi-meet-logger":48}],21:[function(require,module,exports){
(function (__filename){
var logger = require("jitsi-meet-logger").getLogger(__filename);
@@ -4766,7 +4863,7 @@ Settings.prototype.setLanguage = function (lang) {
module.exports = Settings;
}).call(this,"/modules/settings/Settings.js")
-},{"jitsi-meet-logger":47}],22:[function(require,module,exports){
+},{"jitsi-meet-logger":48}],22:[function(require,module,exports){
/* global config */
/**
* Provides statistics for the local stream.
@@ -5618,7 +5715,7 @@ StatsCollector.prototype.processAudioLevelReport = function () {
};
}).call(this,"/modules/statistics/RTPStatsCollector.js")
-},{"../../service/statistics/Events":83,"../RTC/RTCBrowserType":17,"jitsi-meet-logger":47}],24:[function(require,module,exports){
+},{"../../service/statistics/Events":85,"../RTC/RTCBrowserType":17,"jitsi-meet-logger":48}],24:[function(require,module,exports){
/* global require, APP */
var LocalStats = require("./LocalStatsCollector.js");
var RTPStats = require("./RTPStatsCollector.js");
@@ -5793,7 +5890,7 @@ Statistics.LOCAL_JID = require("../../service/statistics/constants").LOCAL_JID;
module.exports = Statistics;
-},{"../../service/statistics/Events":83,"../../service/statistics/constants":84,"./LocalStatsCollector.js":22,"./RTPStatsCollector.js":23,"events":43}],25:[function(require,module,exports){
+},{"../../service/statistics/Events":85,"../../service/statistics/constants":86,"./LocalStatsCollector.js":22,"./RTPStatsCollector.js":23,"events":44}],25:[function(require,module,exports){
/**
/**
* @const
@@ -5876,6 +5973,8 @@ var logger = require("jitsi-meet-logger").getLogger(__filename);
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
var Moderator = require("./moderator");
var EventEmitter = require("events");
+var Recorder = require("./recording");
+var JIBRI_XMLNS = 'http://jitsi.org/protocol/jibri';
var parser = {
packet2JSON: function (packet, nodes) {
@@ -5950,6 +6049,8 @@ function ChatRoom(connection, jid, password, XMPP, options) {
this.session = null;
var self = this;
this.lastPresences = {};
+ this.phoneNumber = null;
+ this.phonePin = null;
}
ChatRoom.prototype.initPresenceMap = function () {
@@ -6067,6 +6168,7 @@ ChatRoom.prototype.createNonAnonymousRoom = function () {
};
ChatRoom.prototype.onPresence = function (pres) {
+ console.log(pres);
var from = pres.getAttribute('from');
// Parse roles.
var member = {};
@@ -6088,6 +6190,7 @@ ChatRoom.prototype.onPresence = function (pres) {
var nodes = [];
parser.packet2JSON(pres, nodes);
this.lastPresences[from] = nodes;
+ var jibri = null;
for(var i = 0; i < nodes.length; i++)
{
var node = nodes[i];
@@ -6117,6 +6220,18 @@ ChatRoom.prototype.onPresence = function (pres) {
this.eventEmitter.emit(XMPPEvents.BRIDGE_DOWN);
}
break;
+ case "jibri-recording-status":
+ var jibri = node;
+ break;
+ case "call-control":
+ console.log(pres);
+ var att = node.attributes;
+ if(!att)
+ break;
+ this.phoneNumber = att.phone || null;
+ this.phonePin = att.pin || null;
+ this.eventEmitter.emit(XMPPEvents.PHONE_NUMBER_CHANGED);
+ break;
default :
this.processNode(node, from);
}
@@ -6142,6 +6257,12 @@ ChatRoom.prototype.onPresence = function (pres) {
logger.log('entered', from, member);
if (member.isFocus) {
this.focusMucJid = from;
+ if(!this.recording) {
+ this.recording = new Recorder(this.eventEmitter, this.connection,
+ this.focusMucJid);
+ if(this.lastJibri)
+ this.recording.handleJibriPresence(this.lastJibri);
+ }
logger.info("Ignore focus: " + from + ", real JID: " + member.jid);
}
else {
@@ -6170,6 +6291,13 @@ ChatRoom.prototype.onPresence = function (pres) {
this.eventEmitter.emit(XMPPEvents.PRESENCE_STATUS, from, member);
}
+ if(jibri)
+ {
+ this.lastJibri = jibri;
+ if(this.recording)
+ this.recording.handleJibriPresence(jibri);
+ }
+
};
ChatRoom.prototype.processNode = function (node, from) {
@@ -6511,6 +6639,77 @@ ChatRoom.prototype.getJidBySSRC = function (ssrc) {
return this.session.getSsrcOwner(ssrc);
};
+/**
+ * Returns true if the recording is supproted and false if not.
+ */
+ChatRoom.prototype.isRecordingSupported = function () {
+ if(this.recording)
+ return this.recording.isSupported();
+ return false;
+};
+
+/**
+ * Returns null if the recording is not supported, "on" if the recording started
+ * and "off" if the recording is not started.
+ */
+ChatRoom.prototype.getRecordingState = function () {
+ if(this.recording)
+ return this.recording.getState();
+ return "off";
+}
+
+/**
+ * Returns the url of the recorded video.
+ */
+ChatRoom.prototype.getRecordingURL = function () {
+ if(this.recording)
+ return this.recording.getURL();
+ return null;
+}
+
+/**
+ * Starts/stops the recording
+ * @param token token for authentication
+ */
+ChatRoom.prototype.toggleRecording = function (token, followEntity) {
+ if(this.recording)
+ return this.recording.toggleRecording(token, followEntity);
+
+ return new Promise(function(resolve, reject){
+ reject(new Error("The conference is not created yet!"))});
+}
+
+/**
+ * Dials a number.
+ * @param number the number
+ */
+ChatRoom.prototype.dial = function (number) {
+ return this.connection.rayo.dial(number, "fromnumber",
+ Strophe.getNodeFromJid(this.myroomjid), this.password,
+ this.focusMucJid);
+}
+
+/**
+ * Hangup an existing call
+ */
+ChatRoom.prototype.hangup = function () {
+ return this.connection.rayo.hangup();
+}
+
+/**
+ * Returns the phone number for joining the conference.
+ */
+ChatRoom.prototype.getPhoneNumber = function () {
+ return this.phoneNumber;
+}
+
+/**
+ * Returns the pin for joining the conference with phone.
+ */
+ChatRoom.prototype.getPhonePin = function () {
+ return this.phonePin;
+}
+
/**
* Returns the connection state for the current session.
*/
@@ -6523,7 +6722,7 @@ ChatRoom.prototype.getConnectionState = function () {
module.exports = ChatRoom;
}).call(this,"/modules/xmpp/ChatRoom.js")
-},{"../../service/xmpp/XMPPEvents":85,"./moderator":34,"events":43,"jitsi-meet-logger":47}],27:[function(require,module,exports){
+},{"../../service/xmpp/XMPPEvents":87,"./moderator":34,"./recording":35,"events":44,"jitsi-meet-logger":48}],27:[function(require,module,exports){
(function (__filename){
/*
* JingleSession provides an API to manage a single Jingle session. We will
@@ -6659,7 +6858,7 @@ JingleSession.prototype.setAnswer = function(jingle) {};
module.exports = JingleSession;
}).call(this,"/modules/xmpp/JingleSession.js")
-},{"jitsi-meet-logger":47}],28:[function(require,module,exports){
+},{"jitsi-meet-logger":48}],28:[function(require,module,exports){
(function (__filename){
/* jshint -W117 */
@@ -8300,7 +8499,7 @@ JingleSessionPC.prototype.getIceConnectionState = function () {
module.exports = JingleSessionPC;
}).call(this,"/modules/xmpp/JingleSessionPC.js")
-},{"../../service/xmpp/XMPPEvents":85,"../RTC/RTC":16,"../RTC/RTCBrowserType":17,"./JingleSession":27,"./LocalSSRCReplacement":29,"./SDP":30,"./SDPDiffer":31,"./SDPUtil":32,"./TraceablePeerConnection":33,"async":42,"jitsi-meet-logger":47,"sdp-transform":75}],29:[function(require,module,exports){
+},{"../../service/xmpp/XMPPEvents":87,"../RTC/RTC":16,"../RTC/RTCBrowserType":17,"./JingleSession":27,"./LocalSSRCReplacement":29,"./SDP":30,"./SDPDiffer":31,"./SDPUtil":32,"./TraceablePeerConnection":33,"async":43,"jitsi-meet-logger":48,"sdp-transform":76}],29:[function(require,module,exports){
(function (__filename){
/* global $ */
var logger = require("jitsi-meet-logger").getLogger(__filename);
@@ -8596,7 +8795,7 @@ var LocalSSRCReplacement = {
module.exports = LocalSSRCReplacement;
}).call(this,"/modules/xmpp/LocalSSRCReplacement.js")
-},{"../RTC/RTCBrowserType":17,"../util/RandomUtil":25,"./SDP":30,"jitsi-meet-logger":47}],30:[function(require,module,exports){
+},{"../RTC/RTCBrowserType":17,"../util/RandomUtil":25,"./SDP":30,"jitsi-meet-logger":48}],30:[function(require,module,exports){
(function (__filename){
/* jshint -W117 */
@@ -9248,7 +9447,7 @@ module.exports = SDP;
}).call(this,"/modules/xmpp/SDP.js")
-},{"./SDPUtil":32,"jitsi-meet-logger":47}],31:[function(require,module,exports){
+},{"./SDPUtil":32,"jitsi-meet-logger":48}],31:[function(require,module,exports){
var SDPUtil = require("./SDPUtil");
function SDPDiffer(mySDP, otherSDP)
@@ -9785,7 +9984,7 @@ SDPUtil = {
module.exports = SDPUtil;
}).call(this,"/modules/xmpp/SDPUtil.js")
-},{"../RTC/RTCBrowserType":17,"jitsi-meet-logger":47}],33:[function(require,module,exports){
+},{"../RTC/RTCBrowserType":17,"jitsi-meet-logger":48}],33:[function(require,module,exports){
(function (__filename){
/* global $ */
var RTC = require('../RTC/RTC');
@@ -10238,7 +10437,7 @@ TraceablePeerConnection.prototype.getStats = function(callback, errback) {
module.exports = TraceablePeerConnection;
}).call(this,"/modules/xmpp/TraceablePeerConnection.js")
-},{"../../service/xmpp/XMPPEvents":85,"../RTC/RTC":16,"../RTC/RTCBrowserType.js":17,"./LocalSSRCReplacement":29,"jitsi-meet-logger":47,"sdp-interop":65,"sdp-simulcast":72,"sdp-transform":75}],34:[function(require,module,exports){
+},{"../../service/xmpp/XMPPEvents":87,"../RTC/RTC":16,"../RTC/RTCBrowserType.js":17,"./LocalSSRCReplacement":29,"jitsi-meet-logger":48,"sdp-interop":66,"sdp-simulcast":73,"sdp-transform":76}],34:[function(require,module,exports){
(function (__filename){
/* global $, $iq, APP, config, messageHandler,
roomName, sessionTerminated, Strophe, Util */
@@ -10684,7 +10883,128 @@ Moderator.prototype.logout = function (callback) {
module.exports = Moderator;
}).call(this,"/modules/xmpp/moderator.js")
-},{"../../service/authentication/AuthenticationEvents":81,"../../service/xmpp/XMPPEvents":85,"../settings/Settings":21,"jitsi-meet-logger":47}],35:[function(require,module,exports){
+},{"../../service/authentication/AuthenticationEvents":83,"../../service/xmpp/XMPPEvents":87,"../settings/Settings":21,"jitsi-meet-logger":48}],35:[function(require,module,exports){
+(function (__filename){
+/* global $, $iq, config, connection, focusMucJid, messageHandler,
+ Toolbar, Util, Promise */
+var XMPPEvents = require("../../service/XMPP/XMPPEvents");
+var logger = require("jitsi-meet-logger").getLogger(__filename);
+
+function Recording(ee, connection, focusMucJid) {
+ this.eventEmitter = ee;
+ this.connection = connection;
+ this.state = "off";
+ this.focusMucJid = focusMucJid;
+ this.url = null;
+ this._isSupported = false;
+}
+
+Recording.prototype.handleJibriPresence = function (jibri) {
+ var attributes = jibri.attributes;
+ if(!attributes)
+ return;
+
+ this._isSupported =
+ (attributes.status && attributes.status !== "undefined");
+ if(this._isSupported) {
+ this.url = attributes.url || null;
+ this.state = attributes.status || "off";
+ }
+ this.eventEmitter.emit(XMPPEvents.RECORDING_STATE_CHANGED);
+};
+
+Recording.prototype.setRecording = function (state, streamId, followEntity,
+ callback, errCallback){
+ if (state == this.state){
+ return;
+ }
+
+ // FIXME jibri does not accept IQ without 'url' attribute set ?
+
+ var iq = $iq({to: this.focusMucJid, type: 'set'})
+ .c('jibri', {
+ "xmlns": 'http://jitsi.org/protocol/jibri',
+ "action": (state === 'on') ? 'start' : 'stop',
+ "streamid": streamId,
+ "follow-entity": followEntity
+ }).up();
+
+ logger.log('Set jibri recording: '+state, iq.nodeTree);
+ console.log(iq.nodeTree);
+ this.connection.sendIQ(
+ iq,
+ function (result) {
+ callback($(result).find('jibri').attr('state'),
+ $(result).find('jibri').attr('url'));
+ },
+ function (error) {
+ logger.log('Failed to start recording, error: ', error);
+ errCallback(error);
+ });
+};
+
+Recording.prototype.toggleRecording = function (token, followEntity) {
+ var self = this;
+ return new Promise(function(resolve, reject) {
+ if (!token) {
+ reject(new Error("No token passed!"));
+ logger.error("No token passed!");
+ return;
+ }
+ if(self.state === "on") {
+ reject(new Error("Recording is already started!"));
+ logger.error("Recording is already started!");
+ return;
+ }
+
+ var oldState = self.state;
+ var newState = (oldState === 'off' || !oldState) ? 'on' : 'off';
+
+ self.setRecording(newState,
+ token, followEntity,
+ function (state, url) {
+ logger.log("New recording state: ", state);
+ if (state && state !== oldState) {
+ self.state = state;
+ self.url = url;
+ resolve();
+ } else {
+ reject(new Error("State not changed!"));
+ }
+ },
+ function (error) {
+ reject(error);
+ }
+ );
+ });
+};
+
+/**
+ * Returns true if the recording is supproted and false if not.
+ */
+Recording.prototype.isSupported = function () {
+ return this._isSupported;
+};
+
+/**
+ * Returns null if the recording is not supported, "on" if the recording started
+ * and "off" if the recording is not started.
+ */
+Recording.prototype.getState = function () {
+ return this.state;
+};
+
+/**
+ * Returns the url of the recorded video.
+ */
+Recording.prototype.getURL = function () {
+ return this.url;
+};
+
+module.exports = Recording;
+
+}).call(this,"/modules/xmpp/recording.js")
+},{"../../service/XMPP/XMPPEvents":82,"jitsi-meet-logger":48}],36:[function(require,module,exports){
(function (__filename){
/* jshint -W117 */
/* a simple MUC connection plugin
@@ -10781,7 +11101,7 @@ module.exports = function(XMPP) {
}).call(this,"/modules/xmpp/strophe.emuc.js")
-},{"./ChatRoom":26,"jitsi-meet-logger":47}],36:[function(require,module,exports){
+},{"./ChatRoom":26,"jitsi-meet-logger":48}],37:[function(require,module,exports){
(function (__filename){
/* jshint -W117 */
@@ -11078,7 +11398,7 @@ module.exports = function(XMPP, eventEmitter) {
}).call(this,"/modules/xmpp/strophe.jingle.js")
-},{"../../service/xmpp/XMPPEvents":85,"../RTC/RTCBrowserType":17,"./JingleSessionPC":28,"jitsi-meet-logger":47}],37:[function(require,module,exports){
+},{"../../service/xmpp/XMPPEvents":87,"../RTC/RTCBrowserType":17,"./JingleSessionPC":28,"jitsi-meet-logger":48}],38:[function(require,module,exports){
/* global Strophe */
module.exports = function () {
@@ -11099,7 +11419,7 @@ module.exports = function () {
}
});
};
-},{}],38:[function(require,module,exports){
+},{}],39:[function(require,module,exports){
(function (__filename){
/* global $, $iq, Strophe */
@@ -11226,7 +11546,7 @@ module.exports = function (XMPP, eventEmitter) {
};
}).call(this,"/modules/xmpp/strophe.ping.js")
-},{"../../service/xmpp/XMPPEvents":85,"jitsi-meet-logger":47}],39:[function(require,module,exports){
+},{"../../service/xmpp/XMPPEvents":87,"jitsi-meet-logger":48}],40:[function(require,module,exports){
(function (__filename){
/* jshint -W117 */
var logger = require("jitsi-meet-logger").getLogger(__filename);
@@ -11243,92 +11563,107 @@ module.exports = function() {
}
this.connection.addHandler(
- this.onRayo.bind(this),
- this.RAYO_XMLNS, 'iq', 'set', null, null);
+ this.onRayo.bind(this), this.RAYO_XMLNS, 'iq', 'set',
+ null, null);
},
onRayo: function (iq) {
logger.info("Rayo IQ", iq);
},
- dial: function (to, from, roomName, roomPass) {
+ dial: function (to, from, roomName, roomPass, focusMucJid) {
var self = this;
- var req = $iq(
- {
- type: 'set',
- to: this.connection.emuc.focusMucJid
+ return new Promise(function (resolve, reject) {
+ if(!focusMucJid) {
+ reject(new Error("Internal error!"));
+ return;
}
- );
- req.c('dial',
- {
- xmlns: this.RAYO_XMLNS,
- to: to,
- from: from
- });
- req.c('header',
- {
- name: 'JvbRoomName',
- value: roomName
- }).up();
-
- if (roomPass !== null && roomPass.length) {
-
+ var req = $iq(
+ {
+ type: 'set',
+ to: focusMucJid
+ }
+ );
+ req.c('dial',
+ {
+ xmlns: self.RAYO_XMLNS,
+ to: to,
+ from: from
+ });
req.c('header',
{
- name: 'JvbRoomPassword',
- value: roomPass
+ name: 'JvbRoomName',
+ value: roomName
}).up();
- }
- this.connection.sendIQ(
- req,
- function (result) {
- logger.info('Dial result ', result);
+ if (roomPass !== null && roomPass.length) {
- var resource = $(result).find('ref').attr('uri');
- this.call_resource = resource.substr('xmpp:'.length);
- logger.info(
- "Received call resource: " + this.call_resource);
- },
- function (error) {
- logger.info('Dial error ', error);
+ req.c('header',
+ {
+ name: 'JvbRoomPassword',
+ value: roomPass
+ }).up();
}
- );
+
+ self.connection.sendIQ(
+ req,
+ function (result) {
+ logger.info('Dial result ', result);
+
+ var resource = $(result).find('ref').attr('uri');
+ self.call_resource =
+ resource.substr('xmpp:'.length);
+ logger.info(
+ "Received call resource: " +
+ self.call_resource);
+ resolve();
+ },
+ function (error) {
+ logger.info('Dial error ', error);
+ reject(error);
+ }
+ );
+ });
},
- hang_up: function () {
- if (!this.call_resource) {
- logger.warn("No call in progress");
- return;
- }
-
+ hangup: function () {
var self = this;
- var req = $iq(
- {
- type: 'set',
- to: this.call_resource
+ return new Promise(function (resolve, reject) {
+ if (!self.call_resource) {
+ reject(new Error("No call in progress"));
+ logger.warn("No call in progress");
+ return;
}
- );
- req.c('hangup',
- {
- xmlns: this.RAYO_XMLNS
- });
- this.connection.sendIQ(
- req,
- function (result) {
- logger.info('Hangup result ', result);
- self.call_resource = null;
- },
- function (error) {
- logger.info('Hangup error ', error);
- self.call_resource = null;
- }
- );
+ var req = $iq(
+ {
+ type: 'set',
+ to: self.call_resource
+ }
+ );
+ req.c('hangup',
+ {
+ xmlns: self.RAYO_XMLNS
+ });
+
+ self.connection.sendIQ(
+ req,
+ function (result) {
+ logger.info('Hangup result ', result);
+ self.call_resource = null;
+ resolve();
+ },
+ function (error) {
+ logger.info('Hangup error ', error);
+ self.call_resource = null;
+ reject(new Error('Hangup error '));
+ }
+ );
+ });
}
}
);
};
}).call(this,"/modules/xmpp/strophe.rayo.js")
-},{"jitsi-meet-logger":47}],40:[function(require,module,exports){
+},{"jitsi-meet-logger":48}],41:[function(require,module,exports){
(function (__filename){
/* global Strophe */
/**
@@ -11377,7 +11712,7 @@ module.exports = function () {
};
}).call(this,"/modules/xmpp/strophe.util.js")
-},{"jitsi-meet-logger":47}],41:[function(require,module,exports){
+},{"jitsi-meet-logger":48}],42:[function(require,module,exports){
(function (__filename){
/* global $, APP, config, Strophe*/
@@ -11699,7 +12034,7 @@ XMPP.prototype.getLocalSSRC = function (mediaType) {
module.exports = XMPP;
}).call(this,"/modules/xmpp/xmpp.js")
-},{"../../JitsiConnectionErrors":5,"../../JitsiConnectionEvents":6,"../../service/RTC/RTCEvents":79,"../../service/xmpp/XMPPEvents":85,"../RTC/RTC":16,"./strophe.emuc":35,"./strophe.jingle":36,"./strophe.logger":37,"./strophe.ping":38,"./strophe.rayo":39,"./strophe.util":40,"events":43,"jitsi-meet-logger":47,"pako":48}],42:[function(require,module,exports){
+},{"../../JitsiConnectionErrors":5,"../../JitsiConnectionEvents":6,"../../service/RTC/RTCEvents":80,"../../service/xmpp/XMPPEvents":87,"../RTC/RTC":16,"./strophe.emuc":36,"./strophe.jingle":37,"./strophe.logger":38,"./strophe.ping":39,"./strophe.rayo":40,"./strophe.util":41,"events":44,"jitsi-meet-logger":48,"pako":49}],43:[function(require,module,exports){
(function (process){
/*!
* async
@@ -12826,7 +13161,7 @@ module.exports = XMPP;
}());
}).call(this,require('_process'))
-},{"_process":44}],43:[function(require,module,exports){
+},{"_process":45}],44:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
@@ -13129,7 +13464,7 @@ function isUndefined(arg) {
return arg === void 0;
}
-},{}],44:[function(require,module,exports){
+},{}],45:[function(require,module,exports){
// shim for using process in browser
var process = module.exports = {};
@@ -13222,7 +13557,7 @@ process.chdir = function (dir) {
};
process.umask = function() { return 0; };
-},{}],45:[function(require,module,exports){
+},{}],46:[function(require,module,exports){
(function (process,global){
/*!
* @overview es6-promise - a tiny implementation of Promises/A+.
@@ -14193,7 +14528,7 @@ process.umask = function() { return 0; };
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"_process":44}],46:[function(require,module,exports){
+},{"_process":45}],47:[function(require,module,exports){
/* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14337,7 +14672,7 @@ Logger.levels = {
ERROR: "error"
};
-},{}],47:[function(require,module,exports){
+},{}],48:[function(require,module,exports){
/* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14422,7 +14757,7 @@ module.exports = {
levels: Logger.levels
};
-},{"./Logger":46}],48:[function(require,module,exports){
+},{"./Logger":47}],49:[function(require,module,exports){
// Top level file is just a mixin of submodules & constants
'use strict';
@@ -14438,7 +14773,7 @@ assign(pako, deflate, inflate, constants);
module.exports = pako;
-},{"./lib/deflate":49,"./lib/inflate":50,"./lib/utils/common":51,"./lib/zlib/constants":54}],49:[function(require,module,exports){
+},{"./lib/deflate":50,"./lib/inflate":51,"./lib/utils/common":52,"./lib/zlib/constants":55}],50:[function(require,module,exports){
'use strict';
@@ -14816,7 +15151,7 @@ exports.deflate = deflate;
exports.deflateRaw = deflateRaw;
exports.gzip = gzip;
-},{"./utils/common":51,"./utils/strings":52,"./zlib/deflate.js":56,"./zlib/messages":61,"./zlib/zstream":63}],50:[function(require,module,exports){
+},{"./utils/common":52,"./utils/strings":53,"./zlib/deflate.js":57,"./zlib/messages":62,"./zlib/zstream":64}],51:[function(require,module,exports){
'use strict';
@@ -15218,7 +15553,7 @@ exports.inflate = inflate;
exports.inflateRaw = inflateRaw;
exports.ungzip = inflate;
-},{"./utils/common":51,"./utils/strings":52,"./zlib/constants":54,"./zlib/gzheader":57,"./zlib/inflate.js":59,"./zlib/messages":61,"./zlib/zstream":63}],51:[function(require,module,exports){
+},{"./utils/common":52,"./utils/strings":53,"./zlib/constants":55,"./zlib/gzheader":58,"./zlib/inflate.js":60,"./zlib/messages":62,"./zlib/zstream":64}],52:[function(require,module,exports){
'use strict';
@@ -15322,7 +15657,7 @@ exports.setTyped = function (on) {
exports.setTyped(TYPED_OK);
-},{}],52:[function(require,module,exports){
+},{}],53:[function(require,module,exports){
// String encode/decode helpers
'use strict';
@@ -15509,7 +15844,7 @@ exports.utf8border = function(buf, max) {
return (pos + _utf8len[buf[pos]] > max) ? pos : max;
};
-},{"./common":51}],53:[function(require,module,exports){
+},{"./common":52}],54:[function(require,module,exports){
'use strict';
// Note: adler32 takes 12% for level 0 and 2% for level 6.
@@ -15543,7 +15878,7 @@ function adler32(adler, buf, len, pos) {
module.exports = adler32;
-},{}],54:[function(require,module,exports){
+},{}],55:[function(require,module,exports){
module.exports = {
/* Allowed flush values; see deflate() and inflate() below for details */
@@ -15592,7 +15927,7 @@ module.exports = {
//Z_NULL: null // Use -1 or null inline, depending on var type
};
-},{}],55:[function(require,module,exports){
+},{}],56:[function(require,module,exports){
'use strict';
// Note: we can't get significant speed boost here.
@@ -15635,7 +15970,7 @@ function crc32(crc, buf, len, pos) {
module.exports = crc32;
-},{}],56:[function(require,module,exports){
+},{}],57:[function(require,module,exports){
'use strict';
var utils = require('../utils/common');
@@ -17402,7 +17737,7 @@ exports.deflatePrime = deflatePrime;
exports.deflateTune = deflateTune;
*/
-},{"../utils/common":51,"./adler32":53,"./crc32":55,"./messages":61,"./trees":62}],57:[function(require,module,exports){
+},{"../utils/common":52,"./adler32":54,"./crc32":56,"./messages":62,"./trees":63}],58:[function(require,module,exports){
'use strict';
@@ -17444,7 +17779,7 @@ function GZheader() {
module.exports = GZheader;
-},{}],58:[function(require,module,exports){
+},{}],59:[function(require,module,exports){
'use strict';
// See state defs from inflate.js
@@ -17772,7 +18107,7 @@ module.exports = function inflate_fast(strm, start) {
return;
};
-},{}],59:[function(require,module,exports){
+},{}],60:[function(require,module,exports){
'use strict';
@@ -19277,7 +19612,7 @@ exports.inflateSyncPoint = inflateSyncPoint;
exports.inflateUndermine = inflateUndermine;
*/
-},{"../utils/common":51,"./adler32":53,"./crc32":55,"./inffast":58,"./inftrees":60}],60:[function(require,module,exports){
+},{"../utils/common":52,"./adler32":54,"./crc32":56,"./inffast":59,"./inftrees":61}],61:[function(require,module,exports){
'use strict';
@@ -19606,7 +19941,7 @@ module.exports = function inflate_table(type, lens, lens_index, codes, table, ta
return 0;
};
-},{"../utils/common":51}],61:[function(require,module,exports){
+},{"../utils/common":52}],62:[function(require,module,exports){
'use strict';
module.exports = {
@@ -19621,7 +19956,7 @@ module.exports = {
'-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */
};
-},{}],62:[function(require,module,exports){
+},{}],63:[function(require,module,exports){
'use strict';
@@ -20822,7 +21157,7 @@ exports._tr_flush_block = _tr_flush_block;
exports._tr_tally = _tr_tally;
exports._tr_align = _tr_align;
-},{"../utils/common":51}],63:[function(require,module,exports){
+},{"../utils/common":52}],64:[function(require,module,exports){
'use strict';
@@ -20853,7 +21188,7 @@ function ZStream() {
module.exports = ZStream;
-},{}],64:[function(require,module,exports){
+},{}],65:[function(require,module,exports){
/* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20894,7 +21229,7 @@ module.exports = function arrayEquals(array) {
};
-},{}],65:[function(require,module,exports){
+},{}],66:[function(require,module,exports){
/* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20912,7 +21247,7 @@ module.exports = function arrayEquals(array) {
exports.Interop = require('./interop');
-},{"./interop":66}],66:[function(require,module,exports){
+},{"./interop":67}],67:[function(require,module,exports){
/* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -21635,7 +21970,7 @@ Interop.prototype.toUnifiedPlan = function(desc) {
//#endregion
};
-},{"./array-equals":64,"./transform":67}],67:[function(require,module,exports){
+},{"./array-equals":65,"./transform":68}],68:[function(require,module,exports){
/* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -21749,7 +22084,7 @@ exports.parse = function(sdp) {
};
-},{"sdp-transform":69}],68:[function(require,module,exports){
+},{"sdp-transform":70}],69:[function(require,module,exports){
var grammar = module.exports = {
v: [{
name: 'version',
@@ -22008,7 +22343,7 @@ Object.keys(grammar).forEach(function (key) {
});
});
-},{}],69:[function(require,module,exports){
+},{}],70:[function(require,module,exports){
var parser = require('./parser');
var writer = require('./writer');
@@ -22018,7 +22353,7 @@ exports.parseFmtpConfig = parser.parseFmtpConfig;
exports.parsePayloads = parser.parsePayloads;
exports.parseRemoteCandidates = parser.parseRemoteCandidates;
-},{"./parser":70,"./writer":71}],70:[function(require,module,exports){
+},{"./parser":71,"./writer":72}],71:[function(require,module,exports){
var toIntIfInt = function (v) {
return String(Number(v)) === v ? Number(v) : v;
};
@@ -22113,7 +22448,7 @@ exports.parseRemoteCandidates = function (str) {
return candidates;
};
-},{"./grammar":68}],71:[function(require,module,exports){
+},{"./grammar":69}],72:[function(require,module,exports){
var grammar = require('./grammar');
// customized util.format - discards excess arguments and can void middle ones
@@ -22229,7 +22564,7 @@ module.exports = function (session, opts) {
return sdp.join('\r\n') + '\r\n';
};
-},{"./grammar":68}],72:[function(require,module,exports){
+},{"./grammar":69}],73:[function(require,module,exports){
/* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -22649,7 +22984,7 @@ Simulcast.prototype.mungeLocalDescription = function (desc) {
module.exports = Simulcast;
-},{"./transform-utils":73,"sdp-transform":75}],73:[function(require,module,exports){
+},{"./transform-utils":74,"sdp-transform":76}],74:[function(require,module,exports){
/* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -22715,22 +23050,22 @@ exports.parseSsrcs = function (mLine) {
};
-},{}],74:[function(require,module,exports){
-arguments[4][68][0].apply(exports,arguments)
-},{"dup":68}],75:[function(require,module,exports){
+},{}],75:[function(require,module,exports){
arguments[4][69][0].apply(exports,arguments)
-},{"./parser":76,"./writer":77,"dup":69}],76:[function(require,module,exports){
+},{"dup":69}],76:[function(require,module,exports){
arguments[4][70][0].apply(exports,arguments)
-},{"./grammar":74,"dup":70}],77:[function(require,module,exports){
+},{"./parser":77,"./writer":78,"dup":70}],77:[function(require,module,exports){
arguments[4][71][0].apply(exports,arguments)
-},{"./grammar":74,"dup":71}],78:[function(require,module,exports){
+},{"./grammar":75,"dup":71}],78:[function(require,module,exports){
+arguments[4][72][0].apply(exports,arguments)
+},{"./grammar":75,"dup":72}],79:[function(require,module,exports){
var MediaStreamType = {
VIDEO_TYPE: "Video",
AUDIO_TYPE: "Audio"
};
module.exports = MediaStreamType;
-},{}],79:[function(require,module,exports){
+},{}],80:[function(require,module,exports){
var RTCEvents = {
RTC_READY: "rtc.ready",
DATA_CHANNEL_OPEN: "rtc.data_channel_open",
@@ -22741,7 +23076,7 @@ var RTCEvents = {
};
module.exports = RTCEvents;
-},{}],80:[function(require,module,exports){
+},{}],81:[function(require,module,exports){
var Resolutions = {
"1080": {
width: 1920,
@@ -22795,58 +23130,7 @@ var Resolutions = {
}
};
module.exports = Resolutions;
-},{}],81:[function(require,module,exports){
-var AuthenticationEvents = {
- /**
- * Event callback arguments:
- * function(authenticationEnabled, userIdentity)
- * authenticationEnabled - indicates whether authentication has been enabled
- * in this session
- * userIdentity - if user has been logged in then it contains user name. If
- * contains 'null' or 'undefined' then user is not logged in.
- */
- IDENTITY_UPDATED: "authentication.identity_updated"
-};
-module.exports = AuthenticationEvents;
-
},{}],82:[function(require,module,exports){
-var DesktopSharingEventTypes = {
- INIT: "ds.init",
-
- SWITCHING_DONE: "ds.switching_done",
-
- NEW_STREAM_CREATED: "ds.new_stream_created",
- /**
- * An event which indicates that the jidesha extension for Firefox is
- * needed to proceed with screen sharing, and that it is not installed.
- */
- FIREFOX_EXTENSION_NEEDED: "ds.firefox_extension_needed"
-};
-
-module.exports = DesktopSharingEventTypes;
-
-},{}],83:[function(require,module,exports){
-module.exports = {
- /**
- * An event carrying connection statistics.
- */
- CONNECTION_STATS: "statistics.connectionstats",
- /**
- * FIXME: needs documentation.
- */
- AUDIO_LEVEL: "statistics.audioLevel",
- /**
- * FIXME: needs documentation.
- */
- STOP: "statistics.stop"
-};
-
-},{}],84:[function(require,module,exports){
-var Constants = {
- LOCAL_JID: 'local'
-};
-module.exports = Constants;
-},{}],85:[function(require,module,exports){
var XMPPEvents = {
// Designates an event indicating that the connection to the XMPP server
// failed.
@@ -22946,8 +23230,70 @@ var XMPPEvents = {
// xmpp is connected and obtained user media
READY_TO_JOIN: 'xmpp.ready_to_join',
FOCUS_LEFT: "xmpp.focus_left",
- REMOTE_STREAM_RECEIVED: "xmpp.remote_stream_received"
+ REMOTE_STREAM_RECEIVED: "xmpp.remote_stream_received",
+ /**
+ * Indicates that recording state changed.
+ */
+ RECORDING_STATE_CHANGED: "xmpp.recordingStateChanged",
+ /**
+ * Indicates that phone number changed.
+ */
+ PHONE_NUMBER_CHANGED: "conference.phoneNumberChanged"
};
module.exports = XMPPEvents;
-},{}]},{},[7])(7)
+
+},{}],83:[function(require,module,exports){
+var AuthenticationEvents = {
+ /**
+ * Event callback arguments:
+ * function(authenticationEnabled, userIdentity)
+ * authenticationEnabled - indicates whether authentication has been enabled
+ * in this session
+ * userIdentity - if user has been logged in then it contains user name. If
+ * contains 'null' or 'undefined' then user is not logged in.
+ */
+ IDENTITY_UPDATED: "authentication.identity_updated"
+};
+module.exports = AuthenticationEvents;
+
+},{}],84:[function(require,module,exports){
+var DesktopSharingEventTypes = {
+ INIT: "ds.init",
+
+ SWITCHING_DONE: "ds.switching_done",
+
+ NEW_STREAM_CREATED: "ds.new_stream_created",
+ /**
+ * An event which indicates that the jidesha extension for Firefox is
+ * needed to proceed with screen sharing, and that it is not installed.
+ */
+ FIREFOX_EXTENSION_NEEDED: "ds.firefox_extension_needed"
+};
+
+module.exports = DesktopSharingEventTypes;
+
+},{}],85:[function(require,module,exports){
+module.exports = {
+ /**
+ * An event carrying connection statistics.
+ */
+ CONNECTION_STATS: "statistics.connectionstats",
+ /**
+ * FIXME: needs documentation.
+ */
+ AUDIO_LEVEL: "statistics.audioLevel",
+ /**
+ * FIXME: needs documentation.
+ */
+ STOP: "statistics.stop"
+};
+
+},{}],86:[function(require,module,exports){
+var Constants = {
+ LOCAL_JID: 'local'
+};
+module.exports = Constants;
+},{}],87:[function(require,module,exports){
+arguments[4][82][0].apply(exports,arguments)
+},{"dup":82}]},{},[7])(7)
});
\ No newline at end of file
diff --git a/modules/RTC/RTCBrowserType.js b/modules/RTC/RTCBrowserType.js
index 2427fae17..e27099517 100644
--- a/modules/RTC/RTCBrowserType.js
+++ b/modules/RTC/RTCBrowserType.js
@@ -161,8 +161,9 @@ function detectBrowser() {
if (version)
return version;
}
- console.error("Failed to detect browser type");
- return undefined;
+ console.warn("Browser type defaults to Safari ver 1");
+ currentBrowser = RTCBrowserType.RTC_BROWSER_SAFARI;
+ return 1;
}
browserVersion = detectBrowser();
diff --git a/modules/xmpp/ChatRoom.js b/modules/xmpp/ChatRoom.js
index 97863ead7..495dc0691 100644
--- a/modules/xmpp/ChatRoom.js
+++ b/modules/xmpp/ChatRoom.js
@@ -4,6 +4,8 @@ var logger = require("jitsi-meet-logger").getLogger(__filename);
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
var Moderator = require("./moderator");
var EventEmitter = require("events");
+var Recorder = require("./recording");
+var JIBRI_XMLNS = 'http://jitsi.org/protocol/jibri';
var parser = {
packet2JSON: function (packet, nodes) {
@@ -78,6 +80,8 @@ function ChatRoom(connection, jid, password, XMPP, options) {
this.session = null;
var self = this;
this.lastPresences = {};
+ this.phoneNumber = null;
+ this.phonePin = null;
}
ChatRoom.prototype.initPresenceMap = function () {
@@ -195,6 +199,7 @@ ChatRoom.prototype.createNonAnonymousRoom = function () {
};
ChatRoom.prototype.onPresence = function (pres) {
+ console.log(pres);
var from = pres.getAttribute('from');
// Parse roles.
var member = {};
@@ -216,6 +221,7 @@ ChatRoom.prototype.onPresence = function (pres) {
var nodes = [];
parser.packet2JSON(pres, nodes);
this.lastPresences[from] = nodes;
+ var jibri = null;
for(var i = 0; i < nodes.length; i++)
{
var node = nodes[i];
@@ -245,6 +251,18 @@ ChatRoom.prototype.onPresence = function (pres) {
this.eventEmitter.emit(XMPPEvents.BRIDGE_DOWN);
}
break;
+ case "jibri-recording-status":
+ var jibri = node;
+ break;
+ case "call-control":
+ console.log(pres);
+ var att = node.attributes;
+ if(!att)
+ break;
+ this.phoneNumber = att.phone || null;
+ this.phonePin = att.pin || null;
+ this.eventEmitter.emit(XMPPEvents.PHONE_NUMBER_CHANGED);
+ break;
default :
this.processNode(node, from);
}
@@ -270,6 +288,12 @@ ChatRoom.prototype.onPresence = function (pres) {
logger.log('entered', from, member);
if (member.isFocus) {
this.focusMucJid = from;
+ if(!this.recording) {
+ this.recording = new Recorder(this.eventEmitter, this.connection,
+ this.focusMucJid);
+ if(this.lastJibri)
+ this.recording.handleJibriPresence(this.lastJibri);
+ }
logger.info("Ignore focus: " + from + ", real JID: " + member.jid);
}
else {
@@ -298,6 +322,13 @@ ChatRoom.prototype.onPresence = function (pres) {
this.eventEmitter.emit(XMPPEvents.PRESENCE_STATUS, from, member);
}
+ if(jibri)
+ {
+ this.lastJibri = jibri;
+ if(this.recording)
+ this.recording.handleJibriPresence(jibri);
+ }
+
};
ChatRoom.prototype.processNode = function (node, from) {
@@ -639,6 +670,77 @@ ChatRoom.prototype.getJidBySSRC = function (ssrc) {
return this.session.getSsrcOwner(ssrc);
};
+/**
+ * Returns true if the recording is supproted and false if not.
+ */
+ChatRoom.prototype.isRecordingSupported = function () {
+ if(this.recording)
+ return this.recording.isSupported();
+ return false;
+};
+
+/**
+ * Returns null if the recording is not supported, "on" if the recording started
+ * and "off" if the recording is not started.
+ */
+ChatRoom.prototype.getRecordingState = function () {
+ if(this.recording)
+ return this.recording.getState();
+ return "off";
+}
+
+/**
+ * Returns the url of the recorded video.
+ */
+ChatRoom.prototype.getRecordingURL = function () {
+ if(this.recording)
+ return this.recording.getURL();
+ return null;
+}
+
+/**
+ * Starts/stops the recording
+ * @param token token for authentication
+ */
+ChatRoom.prototype.toggleRecording = function (token, followEntity) {
+ if(this.recording)
+ return this.recording.toggleRecording(token, followEntity);
+
+ return new Promise(function(resolve, reject){
+ reject(new Error("The conference is not created yet!"))});
+}
+
+/**
+ * Dials a number.
+ * @param number the number
+ */
+ChatRoom.prototype.dial = function (number) {
+ return this.connection.rayo.dial(number, "fromnumber",
+ Strophe.getNodeFromJid(this.myroomjid), this.password,
+ this.focusMucJid);
+}
+
+/**
+ * Hangup an existing call
+ */
+ChatRoom.prototype.hangup = function () {
+ return this.connection.rayo.hangup();
+}
+
+/**
+ * Returns the phone number for joining the conference.
+ */
+ChatRoom.prototype.getPhoneNumber = function () {
+ return this.phoneNumber;
+}
+
+/**
+ * Returns the pin for joining the conference with phone.
+ */
+ChatRoom.prototype.getPhonePin = function () {
+ return this.phonePin;
+}
+
/**
* Returns the connection state for the current session.
*/
diff --git a/modules/xmpp/recording.js b/modules/xmpp/recording.js
new file mode 100644
index 000000000..61b728d1e
--- /dev/null
+++ b/modules/xmpp/recording.js
@@ -0,0 +1,117 @@
+/* global $, $iq, config, connection, focusMucJid, messageHandler,
+ Toolbar, Util, Promise */
+var XMPPEvents = require("../../service/XMPP/XMPPEvents");
+var logger = require("jitsi-meet-logger").getLogger(__filename);
+
+function Recording(ee, connection, focusMucJid) {
+ this.eventEmitter = ee;
+ this.connection = connection;
+ this.state = "off";
+ this.focusMucJid = focusMucJid;
+ this.url = null;
+ this._isSupported = false;
+}
+
+Recording.prototype.handleJibriPresence = function (jibri) {
+ var attributes = jibri.attributes;
+ if(!attributes)
+ return;
+
+ this._isSupported =
+ (attributes.status && attributes.status !== "undefined");
+ if(this._isSupported) {
+ this.url = attributes.url || null;
+ this.state = attributes.status || "off";
+ }
+ this.eventEmitter.emit(XMPPEvents.RECORDING_STATE_CHANGED);
+};
+
+Recording.prototype.setRecording = function (state, streamId, followEntity,
+ callback, errCallback){
+ if (state == this.state){
+ return;
+ }
+
+ // FIXME jibri does not accept IQ without 'url' attribute set ?
+
+ var iq = $iq({to: this.focusMucJid, type: 'set'})
+ .c('jibri', {
+ "xmlns": 'http://jitsi.org/protocol/jibri',
+ "action": (state === 'on') ? 'start' : 'stop',
+ "streamid": streamId,
+ "follow-entity": followEntity
+ }).up();
+
+ logger.log('Set jibri recording: '+state, iq.nodeTree);
+ console.log(iq.nodeTree);
+ this.connection.sendIQ(
+ iq,
+ function (result) {
+ callback($(result).find('jibri').attr('state'),
+ $(result).find('jibri').attr('url'));
+ },
+ function (error) {
+ logger.log('Failed to start recording, error: ', error);
+ errCallback(error);
+ });
+};
+
+Recording.prototype.toggleRecording = function (token, followEntity) {
+ var self = this;
+ return new Promise(function(resolve, reject) {
+ if (!token) {
+ reject(new Error("No token passed!"));
+ logger.error("No token passed!");
+ return;
+ }
+ if(self.state === "on") {
+ reject(new Error("Recording is already started!"));
+ logger.error("Recording is already started!");
+ return;
+ }
+
+ var oldState = self.state;
+ var newState = (oldState === 'off' || !oldState) ? 'on' : 'off';
+
+ self.setRecording(newState,
+ token, followEntity,
+ function (state, url) {
+ logger.log("New recording state: ", state);
+ if (state && state !== oldState) {
+ self.state = state;
+ self.url = url;
+ resolve();
+ } else {
+ reject(new Error("State not changed!"));
+ }
+ },
+ function (error) {
+ reject(error);
+ }
+ );
+ });
+};
+
+/**
+ * Returns true if the recording is supproted and false if not.
+ */
+Recording.prototype.isSupported = function () {
+ return this._isSupported;
+};
+
+/**
+ * Returns null if the recording is not supported, "on" if the recording started
+ * and "off" if the recording is not started.
+ */
+Recording.prototype.getState = function () {
+ return this.state;
+};
+
+/**
+ * Returns the url of the recorded video.
+ */
+Recording.prototype.getURL = function () {
+ return this.url;
+};
+
+module.exports = Recording;
diff --git a/modules/xmpp/strophe.rayo.js b/modules/xmpp/strophe.rayo.js
index 381fcb580..2e1b80796 100644
--- a/modules/xmpp/strophe.rayo.js
+++ b/modules/xmpp/strophe.rayo.js
@@ -13,85 +13,100 @@ module.exports = function() {
}
this.connection.addHandler(
- this.onRayo.bind(this),
- this.RAYO_XMLNS, 'iq', 'set', null, null);
+ this.onRayo.bind(this), this.RAYO_XMLNS, 'iq', 'set',
+ null, null);
},
onRayo: function (iq) {
logger.info("Rayo IQ", iq);
},
- dial: function (to, from, roomName, roomPass) {
+ dial: function (to, from, roomName, roomPass, focusMucJid) {
var self = this;
- var req = $iq(
- {
- type: 'set',
- to: this.connection.emuc.focusMucJid
+ return new Promise(function (resolve, reject) {
+ if(!focusMucJid) {
+ reject(new Error("Internal error!"));
+ return;
}
- );
- req.c('dial',
- {
- xmlns: this.RAYO_XMLNS,
- to: to,
- from: from
- });
- req.c('header',
- {
- name: 'JvbRoomName',
- value: roomName
- }).up();
-
- if (roomPass !== null && roomPass.length) {
-
+ var req = $iq(
+ {
+ type: 'set',
+ to: focusMucJid
+ }
+ );
+ req.c('dial',
+ {
+ xmlns: self.RAYO_XMLNS,
+ to: to,
+ from: from
+ });
req.c('header',
{
- name: 'JvbRoomPassword',
- value: roomPass
+ name: 'JvbRoomName',
+ value: roomName
}).up();
- }
- this.connection.sendIQ(
- req,
- function (result) {
- logger.info('Dial result ', result);
+ if (roomPass !== null && roomPass.length) {
- var resource = $(result).find('ref').attr('uri');
- this.call_resource = resource.substr('xmpp:'.length);
- logger.info(
- "Received call resource: " + this.call_resource);
- },
- function (error) {
- logger.info('Dial error ', error);
+ req.c('header',
+ {
+ name: 'JvbRoomPassword',
+ value: roomPass
+ }).up();
}
- );
+
+ self.connection.sendIQ(
+ req,
+ function (result) {
+ logger.info('Dial result ', result);
+
+ var resource = $(result).find('ref').attr('uri');
+ self.call_resource =
+ resource.substr('xmpp:'.length);
+ logger.info(
+ "Received call resource: " +
+ self.call_resource);
+ resolve();
+ },
+ function (error) {
+ logger.info('Dial error ', error);
+ reject(error);
+ }
+ );
+ });
},
- hang_up: function () {
- if (!this.call_resource) {
- logger.warn("No call in progress");
- return;
- }
-
+ hangup: function () {
var self = this;
- var req = $iq(
- {
- type: 'set',
- to: this.call_resource
+ return new Promise(function (resolve, reject) {
+ if (!self.call_resource) {
+ reject(new Error("No call in progress"));
+ logger.warn("No call in progress");
+ return;
}
- );
- req.c('hangup',
- {
- xmlns: this.RAYO_XMLNS
- });
- this.connection.sendIQ(
- req,
- function (result) {
- logger.info('Hangup result ', result);
- self.call_resource = null;
- },
- function (error) {
- logger.info('Hangup error ', error);
- self.call_resource = null;
- }
- );
+ var req = $iq(
+ {
+ type: 'set',
+ to: self.call_resource
+ }
+ );
+ req.c('hangup',
+ {
+ xmlns: self.RAYO_XMLNS
+ });
+
+ self.connection.sendIQ(
+ req,
+ function (result) {
+ logger.info('Hangup result ', result);
+ self.call_resource = null;
+ resolve();
+ },
+ function (error) {
+ logger.info('Hangup error ', error);
+ self.call_resource = null;
+ reject(new Error('Hangup error '));
+ }
+ );
+ });
}
}
);
diff --git a/service/xmpp/XMPPEvents.js b/service/xmpp/XMPPEvents.js
index 66db39364..6865afc37 100644
--- a/service/xmpp/XMPPEvents.js
+++ b/service/xmpp/XMPPEvents.js
@@ -97,6 +97,14 @@ var XMPPEvents = {
// xmpp is connected and obtained user media
READY_TO_JOIN: 'xmpp.ready_to_join',
FOCUS_LEFT: "xmpp.focus_left",
- REMOTE_STREAM_RECEIVED: "xmpp.remote_stream_received"
+ REMOTE_STREAM_RECEIVED: "xmpp.remote_stream_received",
+ /**
+ * Indicates that recording state changed.
+ */
+ RECORDING_STATE_CHANGED: "xmpp.recordingStateChanged",
+ /**
+ * Indicates that phone number changed.
+ */
+ PHONE_NUMBER_CHANGED: "conference.phoneNumberChanged"
};
-module.exports = XMPPEvents;
\ No newline at end of file
+module.exports = XMPPEvents;