Merge branch 'lib-jitsi-meet-shipit' into lib-jitsi-meet

This commit is contained in:
hristoterezov 2015-12-22 11:53:06 -06:00
commit 36f8c2fa13
10 changed files with 965 additions and 267 deletions

View File

@ -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);
});

View File

@ -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;

View File

@ -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();
}
/**

View File

@ -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("<video autoplay='1' id='localVideo" + i + "' />");
localTracks[i].attach($("#localVideo" + i ));
} else {
$("body").append("<audio autoplay='1' id='localAudio" + i + "' />");
$("body").append("<audio autoplay='1' muted='true' id='localAudio" + i + "' />");
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();
};

File diff suppressed because it is too large Load Diff

View File

@ -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();

View File

@ -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.
*/

117
modules/xmpp/recording.js Normal file
View File

@ -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;

View File

@ -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 '));
}
);
});
}
}
);

View File

@ -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;
module.exports = XMPPEvents;