diff --git a/conference.js b/conference.js index be0e33947..95273f5b7 100644 --- a/conference.js +++ b/conference.js @@ -1205,12 +1205,16 @@ export default { _getConferenceOptions() { const options = config; + const { email, name: nick } = getLocalParticipant(APP.store.getState()); - const nick = APP.store.getState()['features/base/settings'].displayName; const { locationURL } = APP.store.getState()['features/base/connection']; - if (nick) { - options.displayName = nick; + if (options.enableDisplayNameInStats && nick) { + options.statisticsDisplayName = nick; + } + + if (options.enableEmailInStats && email) { + options.statisticsId = email; } options.applicationName = interfaceConfig.APP_NAME; diff --git a/config.js b/config.js index 33f70d04d..52dee5f70 100644 --- a/config.js +++ b/config.js @@ -292,13 +292,11 @@ var config = { // callStatsID: '', // callStatsSecret: '', - // enables callstatsUsername to be reported as statsId and used - // by callstats as repoted remote id - // enableStatsID: false - // enables sending participants display name to callstats // enableDisplayNameInStats: false + // enables sending participants email if available to callstats and other analytics + // enableEmailInStats: false // Privacy // diff --git a/doc/api.md b/doc/api.md index 06c36dce3..bea898d9a 100644 --- a/doc/api.md +++ b/doc/api.md @@ -30,6 +30,7 @@ Its constructor gets a number of options: * **onload**: (optional) handler for the iframe onload event. * **invitees**: (optional) Array of objects containing information about new participants that will be invited in the call. * **devices**: (optional) A map containing information about the initial devices that will be used in the call. + * **userInfo**: (optional) JS object containing information about the participant opening the meeting, such as `email`. Example: @@ -84,6 +85,19 @@ const options = { const api = new JitsiMeetExternalAPI(domain, options); ``` +You can set the userInfo(email) for the call: + +```javascript +var domain = "meet.jit.si"; +var options = { + ... + userInfo: { + email: 'email@jitsiexamplemail.com' + } +} +var api = new JitsiMeetExternalAPI(domain, options); +``` + ### Controlling the embedded Jitsi Meet Conference Device management `JitsiMeetExternalAPI` methods: diff --git a/modules/API/external/external_api.js b/modules/API/external/external_api.js index 67946ef04..aadf4ca74 100644 --- a/modules/API/external/external_api.js +++ b/modules/API/external/external_api.js @@ -232,6 +232,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter { * information about new participants that will be invited in the call. * @param {Array} [options.devices] - Array of objects containing * information about the initial devices that will be used in the call. + * @param {Object} [options.userInfo] - Object containing information about + * the participant opening the meeting. */ constructor(domain, ...args) { super(); @@ -246,7 +248,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter { jwt = undefined, onload = undefined, invitees, - devices + devices, + userInfo } = parseArguments(args); this._parentNode = parentNode; @@ -256,7 +259,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter { jwt, noSSL, roomName, - devices + devices, + userInfo }); this._createIFrame(height, width, onload); this._transport = new Transport({ diff --git a/package-lock.json b/package-lock.json index b01b1f451..726f055e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10931,8 +10931,8 @@ } }, "lib-jitsi-meet": { - "version": "github:jitsi/lib-jitsi-meet#1de69abe22aa632c9a4255ee9f6ae48dab9be756", - "from": "github:jitsi/lib-jitsi-meet#1de69abe22aa632c9a4255ee9f6ae48dab9be756", + "version": "github:jitsi/lib-jitsi-meet#dd31f0aff0a38b3cfd8e808e457a2e3a0f966514", + "from": "github:jitsi/lib-jitsi-meet#dd31f0aff0a38b3cfd8e808e457a2e3a0f966514", "requires": { "@jitsi/sdp-interop": "0.1.14", "@jitsi/sdp-simulcast": "0.2.2", diff --git a/package.json b/package.json index 536ce7f27..b91383e28 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "js-utils": "github:jitsi/js-utils#192b1c996e8c05530eb1f19e82a31069c3021e31", "jsrsasign": "8.0.12", "jwt-decode": "2.2.0", - "lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#1de69abe22aa632c9a4255ee9f6ae48dab9be756", + "lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#dd31f0aff0a38b3cfd8e808e457a2e3a0f966514", "libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d", "lodash": "4.17.13", "moment": "2.19.4", diff --git a/react/features/base/conference/actions.js b/react/features/base/conference/actions.js index c99c68944..9b809d89f 100644 --- a/react/features/base/conference/actions.js +++ b/react/features/base/conference/actions.js @@ -14,6 +14,7 @@ import { JitsiConferenceEvents } from '../lib-jitsi-meet'; import { setAudioMuted, setVideoMuted } from '../media'; import { dominantSpeakerChanged, + getLocalParticipant, getNormalizedDisplayName, participantConnectionStatusChanged, participantKicked, @@ -393,14 +394,18 @@ export function createConference() { throw new Error('Cannot join a conference without a room name!'); } + const config = state['features/base/config']; + const { email, name: nick } = getLocalParticipant(state); const conference = connection.initJitsiConference( getBackendSafeRoomName(room), { - ...state['features/base/config'], + ...config, applicationName: getName(), getWiFiStatsMethod: getJitsiMeetGlobalNS().getWiFiStats, - confID: `${locationURL.host}${locationURL.pathname}` + confID: `${locationURL.host}${locationURL.pathname}`, + statisticsDisplayName: config.enableDisplayNameInStats ? nick : undefined, + statisticsId: config.enableEmailInStats ? email : undefined }); connection[JITSI_CONNECTION_CONFERENCE_KEY] = conference; diff --git a/react/features/base/config/configWhitelist.js b/react/features/base/config/configWhitelist.js index 50b8cece4..94bd824f6 100644 --- a/react/features/base/config/configWhitelist.js +++ b/react/features/base/config/configWhitelist.js @@ -91,11 +91,11 @@ export default [ 'displayJids', 'e2eping', 'enableDisplayNameInStats', + 'enableEmailInStats', 'enableLayerSuspension', 'enableLipSync', 'disableLocalVideoFlip', 'enableRemb', - 'enableStatsID', 'enableTalkWhileMuted', 'enableTcc', 'etherpad_base', diff --git a/react/features/base/settings/middleware.js b/react/features/base/settings/middleware.js index dd2637bcb..890b77b92 100644 --- a/react/features/base/settings/middleware.js +++ b/react/features/base/settings/middleware.js @@ -1,7 +1,10 @@ // @flow +import _ from 'lodash'; import { APP_WILL_MOUNT } from '../app'; import { setAudioOnly } from '../audio-only'; +import parseURLParams from '../config/parseURLParams'; // minimize imports to avoid circular imports +import { SET_LOCATION_URL } from '../connection/actionTypes'; // minimize imports to avoid circular imports import { getLocalParticipant, participantUpdated } from '../participants'; import { MiddlewareRegistry } from '../redux'; @@ -28,6 +31,9 @@ MiddlewareRegistry.register(store => next => action => { _maybeSetAudioOnly(store, action); _updateLocalParticipant(store, action); break; + case SET_LOCATION_URL: + _updateLocalParticipantFromUrl(store); + break; } return result; @@ -118,3 +124,30 @@ function _updateLocalParticipant({ dispatch, getState }, action) { dispatch(participantUpdated(newLocalParticipant)); } + + +/** + * Returns the userInfo set in the URL. + * + * @param {Store} store - The redux store. + * @private + * @returns {void} + */ +function _updateLocalParticipantFromUrl({ dispatch, getState }) { + const urlParams + = parseURLParams(getState()['features/base/connection'].locationURL); + const urlEmail = urlParams['userInfo.email']; + + if (!urlEmail) { + return; + } + + const localParticipant = getLocalParticipant(getState()); + + if (localParticipant) { + dispatch(participantUpdated({ + ...localParticipant, + email: _.escape(urlEmail) + })); + } +} diff --git a/react/features/base/util/uri.js b/react/features/base/util/uri.js index e114adcb1..b7459a727 100644 --- a/react/features/base/util/uri.js +++ b/react/features/base/util/uri.js @@ -510,7 +510,7 @@ export function urlObjectToString(o: Object): ?string { let { hash } = url; - for (const urlPrefix of [ 'config', 'interfaceConfig', 'devices' ]) { + for (const urlPrefix of [ 'config', 'interfaceConfig', 'devices', 'userInfo' ]) { const urlParamsArray = _objectToURLParamsArray( o[`${urlPrefix}Overwrite`]