diff --git a/bigbluebutton-html5/imports/api/1.1/audio/client/bridge/sip.js b/bigbluebutton-html5/imports/api/1.1/audio/client/bridge/sip.js index ad3e42d9f47abb6fe9a93dddbc86909e61803389..c01d378aff7c1e2907e778b3e00d475382feca7c 100644 --- a/bigbluebutton-html5/imports/api/1.1/audio/client/bridge/sip.js +++ b/bigbluebutton-html5/imports/api/1.1/audio/client/bridge/sip.js @@ -13,18 +13,18 @@ export default class SIPBridge extends BaseAudioBridge { this.userData = userData; } - joinListenOnly() { + joinListenOnly(stunServers, turnServers) { makeCall('listenOnlyToggle', true); - this._joinVoiceCallSIP({ isListenOnly: true }); + this._joinVoiceCallSIP({ isListenOnly: true, stunServers, turnServers }); } - joinMicrophone() { - this._joinVoiceCallSIP({ isListenOnly: false }); + joinMicrophone(stunServers, turnServers) { + this._joinVoiceCallSIP({ isListenOnly: false, stunServers, turnServers }); } // Periodically check the status of the WebRTC call, when a call has been established attempt to // hangup, retry if a call is in progress, send the leave voice conference message to BBB - exitAudio(isListenOnly, afterExitCall = () => {}) { + exitAudio(isListenOnly, afterExitCall = () => { }) { // To be called when the hangup is confirmed const hangupCallback = function () { console.log(`Exited Voice Conference, listenOnly=${isListenOnly}`); @@ -40,7 +40,7 @@ export default class SIPBridge extends BaseAudioBridge { triedHangup = false; // function to initiate call - const checkToHangupCall = ((context, afterExitCall = () => {}) => { + const checkToHangupCall = ((context, afterExitCall = () => { }) => { // if an attempt to hang up the call is made when the current session is not yet finished, // the request has no effect keep track in the session if we haven't tried a hangup if (window.getCallStatus() != null && !triedHangup) { @@ -96,8 +96,8 @@ export default class SIPBridge extends BaseAudioBridge { }; const stunsAndTurns = { - stun: this.userData.stuns, - turn: this.userData.turns, + stun: options.stunServers, + turn: options.turnServers, }; callIntoConference(extension, (audio) => { diff --git a/bigbluebutton-html5/imports/api/1.1/audio/client/manager/index.js b/bigbluebutton-html5/imports/api/1.1/audio/client/manager/index.js index 8092a0931503676d1d658f988c937200984c602e..62033062abb93c795f872fbcb691a5d3521edd12 100644 --- a/bigbluebutton-html5/imports/api/1.1/audio/client/manager/index.js +++ b/bigbluebutton-html5/imports/api/1.1/audio/client/manager/index.js @@ -1,3 +1,4 @@ +import Auth from '/imports/ui/services/auth'; import BaseAudioBridge from '../bridge/base'; import VertoBridge from '../bridge/verto'; import SIPBridge from '../bridge/sip'; @@ -24,12 +25,42 @@ export default class AudioManager { } joinAudio(listenOnly) { - if (listenOnly || this.microphoneLockEnforced) { - this.isListenOnly = true; - this.bridge.joinListenOnly(); - } else { - this.bridge.joinMicrophone(); - } + AudioManager.fetchServers().then(({ error, stunServers, turnServers }) => { + if (error) { + //We need to alert the user about this problem by some gui message. + console.error("Couldn't fetch the stuns/turns servers!"); + return; + } + + if (listenOnly || this.microphoneLockEnforced) { + this.isListenOnly = true; + this.bridge.joinListenOnly(stunServers, turnServers); + } else { + this.bridge.joinMicrophone(stunServers, turnServers); + } + }); + } + + // We use on the SIP an String Array, while in the server, it comes as + // an Array of objects, we need to map from Array<Object> to Array<String> + static mapToArray({ response, stunServers, turnServers }) { + const promise = new Promise((resolve) => { + if (response) { + resolve({ error: 404, stunServers: [], turnServers: [] }); + } + resolve({ + stunServers: stunServers.map(server => server.url), + turnServers: turnServers.map(server => server.url), + }); + }); + return promise; } + static fetchServers() { + const url = `/bigbluebutton/api/stuns?sessionToken=${Auth.sessionToken}`; + + return fetch(url) + .then(response => response.json()) + .then(json => AudioManager.mapToArray(json)); + } } diff --git a/bigbluebutton-html5/imports/api/2.0/users/server/methods.js b/bigbluebutton-html5/imports/api/2.0/users/server/methods.js index 53eab01a42d79a810bc566edd303ba6e0e557e60..3eb0c72e7b52a16f0f6187877908c0da947536f9 100644 --- a/bigbluebutton-html5/imports/api/2.0/users/server/methods.js +++ b/bigbluebutton-html5/imports/api/2.0/users/server/methods.js @@ -3,11 +3,13 @@ import mapToAcl from '/imports/startup/mapToAcl'; import userLogout from './methods/userLogout'; import validateAuthToken from './methods/validateAuthToken'; import setEmojiStatus from './methods/setEmojiStatus'; +import listenOnlyToggle from './methods/listenOnlyToggle'; -Meteor.methods(mapToAcl(['methods.userLogout', 'methods.setEmojiStatus', +Meteor.methods(mapToAcl(['methods.userLogout', 'methods.setEmojiStatus', 'methods.listenOnlyToggle', ], { userLogout, setEmojiStatus, + listenOnlyToggle, })); Meteor.methods({ validateAuthToken2x: validateAuthToken }); diff --git a/bigbluebutton-html5/imports/api/2.0/users/server/methods/listenOnlyToggle.js b/bigbluebutton-html5/imports/api/2.0/users/server/methods/listenOnlyToggle.js index 6880569b72b5c4ad87abeac0e74099a3d3f8f35a..45e28835052db9765a571e8346cbc1b7877a9327 100755 --- a/bigbluebutton-html5/imports/api/2.0/users/server/methods/listenOnlyToggle.js +++ b/bigbluebutton-html5/imports/api/2.0/users/server/methods/listenOnlyToggle.js @@ -7,7 +7,7 @@ import Users from '/imports/api/2.0/users'; export default function listenOnlyToggle(credentials, isJoining = true) { const REDIS_CONFIG = Meteor.settings.redis; - const CHANNEL = REDIS_CONFIG.channels.toBBBApps.meeting; + const CHANNEL = REDIS_CONFIG.channels.toAkkaApps; const { meetingId, requesterUserId } = credentials; @@ -18,40 +18,36 @@ export default function listenOnlyToggle(credentials, isJoining = true) { let EVENT_NAME; if (isJoining) { - EVENT_NAME = 'user_connected_to_global_audio'; + EVENT_NAME = 'UserConnectedToGlobalAudioMsg'; } else { - EVENT_NAME = 'user_disconnected_from_global_audio'; + EVENT_NAME = 'UserDisconnectedFromGlobalAudioMsg'; } - const Meeting = Meetings.findOne({ meetingId }); - if (!Meeting) { - throw new Meteor.Error( - 'meeting-not-found', 'You need a valid meeting to be able to toggle audio'); - } - - check(Meeting.voiceConf, String); - const User = Users.findOne({ - meetingId, userId: requesterUserId, }); + const Meeting = Meetings.findOne({ meetingId }); + if (!User) { throw new Meteor.Error( 'user-not-found', 'You need a valid user to be able to toggle audio'); } - check(User.user.name, String); + // check(User.user.name, String); + + const header = { + name: EVENT_NAME, + voiceConf: Meeting.voiceProp.voiceConf, + }; const payload = { - userid: requesterUserId, - meeting_id: meetingId, - voice_conf: Meeting.voiceConf, + userId: requesterUserId, name: User.user.name, }; Logger.verbose(`User '${requesterUserId}' ${isJoining ? 'joined' : 'left'} global audio from meeting '${meetingId}'`); - return RedisPubSub.publish(CHANNEL, EVENT_NAME, payload); + return RedisPubSub.publish(CHANNEL, EVENT_NAME, meetingId, payload, header); } diff --git a/bigbluebutton-html5/imports/startup/client/auth.js b/bigbluebutton-html5/imports/startup/client/auth.js index 68d10187d55cb6eaa0dffdddbb0689509a66e430..5d6617aa9677e7b9ccf1493d7fa5729d1ceedc43 100755 --- a/bigbluebutton-html5/imports/startup/client/auth.js +++ b/bigbluebutton-html5/imports/startup/client/auth.js @@ -21,7 +21,7 @@ export function joinRouteHandler(nextState, replace, callback) { .then((data) => { const { meetingID, internalUserID, authToken, logoutUrl } = data.response; - Auth.set(meetingID, internalUserID, authToken, logoutUrl); + Auth.set(meetingID, internalUserID, authToken, logoutUrl, sessionToken); replace({ pathname: '/' }); callback(); }); diff --git a/bigbluebutton-html5/imports/startup/client/base.jsx b/bigbluebutton-html5/imports/startup/client/base.jsx index 096d407c46a158ecbd232cc497813e7f9f00df96..d4f6dec0b17e756c731fc19f36d04b901ba6771a 100644 --- a/bigbluebutton-html5/imports/startup/client/base.jsx +++ b/bigbluebutton-html5/imports/startup/client/base.jsx @@ -85,7 +85,7 @@ Base.defaultProps = defaultProps; const SUBSCRIPTIONS_NAME = [ 'users2x', 'users', 'chat', 'chat2x', 'cursor', 'cursor2x', 'deskshare', 'meetings', 'meetings2x', - 'polls', 'polls2x', 'presentations', 'presentations2x', 'shapes', 'shapes2x', 'slides', 'slides2x', 'captions', 'captions2x', 'breakouts', 'breakouts2x', + 'polls', 'polls2x', 'presentations', 'presentations2x', 'shapes', 'shapes2x', 'slides', 'slides2x', 'captions', 'captions2x', 'breakouts', 'breakouts2x', ]; const BaseContainer = createContainer(({ params }) => { diff --git a/bigbluebutton-html5/imports/ui/components/audio/service.js b/bigbluebutton-html5/imports/ui/components/audio/service.js index dc86d205b6135d9439487334072482f1384235f6..98e24b1755a1a109f1b25bd5b802cdcb31bf161a 100755 --- a/bigbluebutton-html5/imports/ui/components/audio/service.js +++ b/bigbluebutton-html5/imports/ui/components/audio/service.js @@ -2,25 +2,23 @@ import Users from '/imports/api/2.0/users'; import Auth from '/imports/ui/services/auth'; import AudioManager from '/imports/api/1.1/audio/client/manager'; +import Meetings from '/imports/api/2.0/meetings'; let audioManager; + const init = () => { const userId = Auth.userID; const User = Users.findOne({ userId }); const username = User.user.name; - - const turns = []; - const stuns = []; - // FIX ME - const voiceBridge = 'Meeting.voiceConf'; + const Meeting = Meetings.findOne({ meetingId: User.meetingId }); + const voiceBridge = Meeting.voiceProp.voiceConf; + // FIX ME - const microphoneLockEnforced = 'Meeting.roomLockSettings.disableMic'; + const microphoneLockEnforced = false; const userData = { userId, username, - turns, - stuns, voiceBridge, microphoneLockEnforced, }; diff --git a/bigbluebutton-html5/imports/ui/services/auth/index.js b/bigbluebutton-html5/imports/ui/services/auth/index.js index 2b63515fde11e05f706586cf0c31ae6a5cf9eaea..4b2c73f2f9c1d73815b792feaea7b66684da40f9 100644 --- a/bigbluebutton-html5/imports/ui/services/auth/index.js +++ b/bigbluebutton-html5/imports/ui/services/auth/index.js @@ -13,6 +13,7 @@ class Auth { this._meetingID = Storage.getItem('meetingID'); this._userID = Storage.getItem('userID'); this._authToken = Storage.getItem('authToken'); + this._sessionToken = Storage.getItem('sessionToken'); this._logoutURL = Storage.getItem('logoutURL'); this._loggedIn = { value: false, @@ -29,6 +30,15 @@ class Auth { Storage.setItem('meetingID', this._meetingID); } + set sessionToken(sessionToken) { + this._sessionToken = sessionToken; + Storage.setItem('sessionToken', this._sessionToken); + } + + get sessionToken() { + return this._sessionToken; + } + get userID() { return this._userID; } @@ -72,14 +82,16 @@ class Auth { requesterUserId: this.userID, requesterToken: this.token, logoutURL: this.logoutURL, + sessionToken: this.sessionToken, }; } - set(meetingId, requesterUserId, requesterToken, logoutURL) { + set(meetingId, requesterUserId, requesterToken, logoutURL, sessionToken) { this.meetingID = meetingId; this.userID = requesterUserId; this.token = requesterToken; this.logoutURL = logoutURL; + this.sessionToken = sessionToken; } clearCredentials(...args) { @@ -88,6 +100,7 @@ class Auth { this.token = null; this.loggedIn = false; this.logoutURL = null; + this.sessionToken = null; return Promise.resolve(...args); }