diff --git a/bigbluebutton-html5/imports/api/2.0/audio/client/bridge/sip.js b/bigbluebutton-html5/imports/api/2.0/audio/client/bridge/sip.js index 81b9825f44a6aed5eb0630cf706a18859af35e41..3401d72dbabd4adac3a6b2b947a5ccc3c2d1aab0 100755 --- a/bigbluebutton-html5/imports/api/2.0/audio/client/bridge/sip.js +++ b/bigbluebutton-html5/imports/api/2.0/audio/client/bridge/sip.js @@ -14,12 +14,14 @@ export default class SIPBridge extends BaseAudioBridge { } joinListenOnly(stunServers, turnServers, callbackFromManager) { + console.log('Join listen only from sip'); makeCall('listenOnlyToggle', true); - this._joinVoiceCallSIP({ isListenOnly: true }, stunServers, turnServers, callbackFromManager); + return this._joinVoiceCallSIP({ isListenOnly: true }, stunServers, turnServers, callbackFromManager); } joinMicrophone(stunServers, turnServers, callbackFromManager) { - this._joinVoiceCallSIP({ isListenOnly: false }, stunServers, turnServers, callbackFromManager); + console.log('Join microphone from sip'); + return this._joinVoiceCallSIP({ isListenOnly: false }, stunServers, turnServers, callbackFromManager); } // Periodically check the status of the WebRTC call, when a call has been established attempt to @@ -67,19 +69,27 @@ export default class SIPBridge extends BaseAudioBridge { // join the conference. If listen only send the request to the server _joinVoiceCallSIP(options, stunServers, turnServers, callbackFromManager) { - const extension = this.userData.voiceBridge; - console.log(options); - - // create voice call params - const joinCallback = function (message) { - console.log('Beginning WebRTC Conference Call'); - }; - - const stunsAndTurns = { - stun: stunServers, - turn: turnServers, - }; + return new Promise((resolve, reject) => { + const extension = this.userData.voiceBridge; + console.log(options); + + // create voice call params + const joinCallback = function (message) { + console.log('Beginning WebRTC Conference Call', this.userData); + }; + + const stunsAndTurns = { + stun: stunServers, + turn: turnServers, + }; + + const callback = (message) => { + console.log('CALLBACK FROM SIP BRIDGE'); + return callbackFromManager(message).then(response => resolve(response)) + .catch(reason => reject(reason)); + } - callIntoConference(extension, callbackFromManager, options.isListenOnly, stunsAndTurns); + callIntoConference(extension, callback, options.isListenOnly, stunsAndTurns); + }) } } diff --git a/bigbluebutton-html5/imports/api/2.0/audio/client/manager/index.js b/bigbluebutton-html5/imports/api/2.0/audio/client/manager/index.js index 81e9d19ea6ed5d01793291918005fe92e91973ed..02a4193c5fec4d41b97473b3dd3d2a81141c531c 100755 --- a/bigbluebutton-html5/imports/api/2.0/audio/client/manager/index.js +++ b/bigbluebutton-html5/imports/api/2.0/audio/client/manager/index.js @@ -77,45 +77,59 @@ class AudioManager { throw 'Audio Bridge not compatible'; } + console.log('INIT AUDIO MANAGER', audioBridge); + this.bridge = audioBridge; this.isListenOnly = false; this.microphoneLockEnforced = userData.microphoneLockEnforced; this.callStates = CallStates; this.currentState = this.callStates.init; - callbackToAudioBridge = function (message) { - switch (message.status) { - case 'failed': { - this.currentState = this.callStates.init; - const audioFailed = new CustomEvent('bbb.webrtc.failed', { - detail: { - status: 'Failed', - errorCode: message.errorcode, - }, - }); - window.dispatchEvent(audioFailed); - break; - } - case 'mediafail': { - const mediaFailed = new CustomEvent('bbb.webrtc.mediaFailed', { - detail: { - status: 'MediaFailed', - }, - }); - window.dispatchEvent(mediaFailed); - break; - } - case 'mediasuccess': - case 'started': { - const connected = new CustomEvent('bbb.webrtc.connected', { - detail: { - status: 'started', - }, - }); - window.dispatchEvent(connected); - break; + callbackToAudioBridge = (message) => { + return new Promise((resolve, reject) => { + console.log('MESSAGE', message); + if(message.status === 'failed' || message.status === 'mediafail') { + console.log('REJECT FROM MANAGER CALLBACK'); + reject(message.status); + } else if (message.status === 'started'){ + console.log('RESOLVE FROM MANAGER CALLBACK'); + resolve(message.status) } - } + }) + + // switch (message.status) { + // case 'failed': { + // this.currentState = this.callStates.init; + // const audioFailed = new CustomEvent('bbb.webrtc.failed', { + // detail: { + // status: 'Failed', + // errorCode: message.errorcode, + // }, + // }); + // window.dispatchEvent(audioFailed); + // break; + // } + // case 'mediafail': { + // const mediaFailed = new CustomEvent('bbb.webrtc.mediaFailed', { + // detail: { + // status: 'MediaFailed', + // }, + // }); + // window.dispatchEvent(mediaFailed); + // break; + // } + // case 'mediasuccess': + // case 'started': { + // const connected = new CustomEvent('bbb.webrtc.connected', { + // detail: { + // status: 'started', + // }, + // }); + // window.dispatchEvent(connected); + // + // break; + // } + // } }; } @@ -129,25 +143,28 @@ class AudioManager { } joinAudio(listenOnly) { - AudioManager.fetchServers().then(({ error, stunServers, turnServers }) => { - if (error || error !== undefined) { - // We need to alert the user about this problem by some gui message. - console.error("Couldn't fetch the stuns/turns servers!"); + return new Promise((resolve, reject) => { + AudioManager.fetchServers().then(({ stunServers, turnServers }) => { + const shouldJoinListenOnly = listenOnly || this.microphoneLockEnforced; + + if (shouldJoinListenOnly) { + this.bridge.joinListenOnly(stunServers, turnServers, callbackToAudioBridge.bind(this)).then((response) => { + this.isListenOnly = true; + this.currentState = this.callStates.inListenOnly; + resolve(response); + }).catch(reason => reject(reason)); + } else { + this.bridge.joinMicrophone(stunServers, turnServers, callbackToAudioBridge.bind(this)).then((response) => { + this.currentState = this.callStates.inConference; + resolve(response); + }).catch(reason => reject(reason)); + } + }).catch(error => { AudioManager.stunTurnServerFail(); - return; - } - - if (listenOnly || this.microphoneLockEnforced) { - this.isListenOnly = true; - this.bridge.joinListenOnly(stunServers, turnServers, callbackToAudioBridge.bind(this)); - // TODO: remove line below after echo test implemented, use webRTCCallStarted instead - this.currentState = this.callStates.inListenOnly; - } else { - this.bridge.joinMicrophone(stunServers, turnServers, callbackToAudioBridge.bind(this)); - // TODO: remove line below after echo test implemented, use webRTCCallStarted instead - this.currentState = this.callStates.inConference; - } - }); + console.error(error); + reject(error); + }); + }) } transferToConference() { @@ -207,7 +224,7 @@ class AudioManager { // 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) => { + return new Promise((resolve) => { if (response) { resolve({ error: 404, stunServers: [], turnServers: [] }); } @@ -216,15 +233,19 @@ class AudioManager { turnServers: turnServers.map(server => server.url), }); }); - return promise; } static fetchServers() { - const url = `/bigbluebutton/api/stuns?sessionToken=${Auth.sessionToken}`; + return new Promise(async (resolve, reject) => { + const url = `/bigbluebutton/api/stuns?sessionToken=${Auth.sessionToken}`; + + let response = await fetch(url) + .then(response => response.json()) + .then(json => AudioManager.mapToArray(json)); - return fetch(url) - .then(response => response.json()) - .then(json => AudioManager.mapToArray(json)); + if(response.error) return reject(`Could not fetch the stuns/turns servers!`); + resolve(response); + }) } } diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/component.jsx b/bigbluebutton-html5/imports/ui/components/actions-bar/component.jsx index 31b73bb67719318aa38f1cfe07141de3a6a87a77..33b7fda1696edec096fcb5ef5fa7daf419893ba9 100644 --- a/bigbluebutton-html5/imports/ui/components/actions-bar/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/actions-bar/component.jsx @@ -2,8 +2,9 @@ import React, { Component } from 'react'; import styles from './styles.scss'; import EmojiContainer from './emoji-menu/container'; import ActionsDropdown from './actions-dropdown/component'; + +import AudioControlsContainer from '../audio/audio-controls/container'; import JoinAudioOptionsContainer from '../audio/audio-menu/container'; -import MuteAudioContainer from './mute-button/container'; export default class ActionsBar extends Component { constructor(props) { @@ -19,12 +20,13 @@ export default class ActionsBar extends Component { <ActionsDropdown {...{ isUserPresenter }} /> </div> <div className={styles.center}> - <MuteAudioContainer /> + <AudioControlsContainer/> + {/* <JoinAudioOptionsContainer handleJoinAudio={this.props.handleOpenJoinAudio} handleCloseAudio={this.props.handleExitAudio} /> - {/* <JoinVideo />*/} + <JoinVideo />*/} <EmojiContainer /> </div> </div> diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/container.jsx b/bigbluebutton-html5/imports/ui/components/actions-bar/container.jsx index 9a19d36810b2a0c4098dca4581a42f0356cbbbaa..881981d9bdb154982cbc3968f6f13b97069c83b0 100755 --- a/bigbluebutton-html5/imports/ui/components/actions-bar/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/actions-bar/container.jsx @@ -8,10 +8,6 @@ import AudioService from '../audio/service'; import AudioModal from '../audio/audio-modal/component'; class ActionsBarContainer extends Component { - constructor(props) { - super(props); - } - render() { return ( <ActionsBar diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/styles.scss b/bigbluebutton-html5/imports/ui/components/actions-bar/styles.scss index b74ee7dfa20d98d04c4c65c2cabcd73f2cd340e3..dbea4fdf5f5e29ee97d4a60e1b58ce12d6a4e679 100755 --- a/bigbluebutton-html5/imports/ui/components/actions-bar/styles.scss +++ b/bigbluebutton-html5/imports/ui/components/actions-bar/styles.scss @@ -24,7 +24,3 @@ .center { align-items: center; } - -.circleGlow > :first-child{ - box-shadow: 0 0 .15rem #FFF !important; -} diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/component.jsx b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/component.jsx new file mode 100644 index 0000000000000000000000000000000000000000..f9d05dfe50968c6bd408f20873e82b3fc61e0b05 --- /dev/null +++ b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/component.jsx @@ -0,0 +1,34 @@ +import React, { Component } from 'react'; +import MuteAudioContainer from '../mute-button/container'; +import OpenAudioModalButton from '../open-audio-modal-button/container'; +import styles from './styles.scss'; +import Button from '/imports/ui/components/button/component'; + + +export default ({ + handleToggleMuteMicrophone, + handleJoinAudio, + handleLeaveAudio, + mute, + unmute, + join, + }) => ( + <span className={styles.container}> + {mute ? + <Button + onClick={handleToggleMuteMicrophone} + label={unmute ? 'Unmute' : 'Mute'} + color={'primary'} + icon={unmute ? 'mute' : 'unmute'} + size={'lg'} + circle + /> : null} + <Button + onClick={ join ? handleLeaveAudio : handleJoinAudio } + label={ join ? 'Leave Audio' : 'Join Audio'} + color={ join ? 'danger' : 'primary' } + icon={ join ? 'audio_off' : 'audio_on' } + size={'lg'} + circle + /> + </span>); diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx new file mode 100644 index 0000000000000000000000000000000000000000..05d9135731d740022b28e323e96711f1e65b48f4 --- /dev/null +++ b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { createContainer } from 'meteor/react-meteor-data'; +import PropTypes from 'prop-types'; +import AudioControls from './component'; +import Service from '../service'; + +// const propTypes = { +// children: PropTypes.element, +// }; +// +// const defaultProps = { +// children: null, +// }; + +const AudioControlsContainer = props => <AudioControls {...props} /> + +let didMountAutoJoin = false; + +export default createContainer(() => { + // const APP_CONFIG = Meteor.settings.public.app; + // + // const { autoJoinAudio } = APP_CONFIG; + // const { isConnected, isConnecting, isListenOnly } = Service.getStats(); + // let shouldShowMute = isConnected && !isListenOnly; + // let shouldShowUnmute = isConnected && !isListenOnly && isMuted; + // let shouldShowJoin = !isConnected; + + return { + mute: Service.isConnected() && !Service.isListenOnly(), + unmute: Service.isConnected() && !Service.isListenOnly() && Service.isMuted(), + join: Service.isConnected(), + + handleToggleMuteMicrophone: () => Service.toggleMuteMicrophone(), + handleJoinAudio: () => console.log('handleJoinAudio'), + handleLeaveAudio: () => console.log('handleLeaveAudio'), + }; +}, AudioControlsContainer); + +// AudioControlsContainer.propTypes = propTypes; +// AudioControlsContainer.defaultProps = defaultProps; diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/styles.scss b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/styles.scss new file mode 100644 index 0000000000000000000000000000000000000000..dd9268be76be8e1fc4c16c4183ea6df600544bdf --- /dev/null +++ b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/styles.scss @@ -0,0 +1,12 @@ +.container { + display: flex; + flex-flow: row; + + > * { + margin: 0 1rem; + } + + > :last-child { + margin-right: 0; + } +} diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-menu/component.jsx b/bigbluebutton-html5/imports/ui/components/audio/audio-menu/component.jsx index 71d7814aa36a4344b87431c2b3aa79c3205e9fcd..04bdb816c8c928bca84a16b8a7003351839a39d6 100755 --- a/bigbluebutton-html5/imports/ui/components/audio/audio-menu/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/audio/audio-menu/component.jsx @@ -22,32 +22,29 @@ class JoinAudioOptions extends React.Component { intl, isInAudio, isInListenOnly, + isConnecting, handleJoinAudio, handleCloseAudio, } = this.props; + let onClick = handleJoinAudio; + let label = intl.formatMessage(intlMessages.joinAudio); + let color = 'primary'; + let icon = 'audio_on'; + if (isInAudio || isInListenOnly) { - if (AudioManager.currentState == AudioManager.callStates.inConference || - AudioManager.currentState == AudioManager.callStates.inListenOnly) { - return ( - <Button - onClick={handleCloseAudio} - label={intl.formatMessage(intlMessages.leaveAudio)} - color={'danger'} - icon={'audio_off'} - size={'lg'} - circle - /> - ); - } + onClick = handleCloseAudio; + label = intl.formatMessage(intlMessages.leaveAudio); + color = 'danger'; + icon = 'audio_off'; } return ( <Button - onClick={handleJoinAudio} - label={intl.formatMessage(intlMessages.joinAudio)} - color={'primary'} - icon={'audio_on'} + onClick={onClick} + label={label} + color={color} + icon={icon} size={'lg'} circle /> diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-menu/container.jsx b/bigbluebutton-html5/imports/ui/components/audio/audio-menu/container.jsx index fad6b8d9ef230091c866cb5531673e12c5ac4a28..f838b868bad7291a6fc304a95c4e217f11663195 100755 --- a/bigbluebutton-html5/imports/ui/components/audio/audio-menu/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/audio/audio-menu/container.jsx @@ -1,20 +1,18 @@ import React from 'react'; import { createContainer } from 'meteor/react-meteor-data'; -import VoiceUsers from '/imports/api/2.0/voice-users'; -import Auth from '/imports/ui/services/auth/index'; import JoinAudioOptions from './component'; +import AudioManager from '/imports/ui/services/audio-manager'; const JoinAudioOptionsContainer = props => (<JoinAudioOptions {...props} />); export default createContainer((params) => { - const userId = Auth.userID; - const voiceUser = VoiceUsers.findOne({ intId: userId }); - - const { joined, listenOnly } = voiceUser; + console.log(AudioManager); + const { connected, isListenOnly, connecting } = AudioManager; return { - isInAudio: joined, - isInListenOnly: listenOnly, + isInAudio: connected, + isConnecting: connecting, + isInListenOnly: isListenOnly, handleJoinAudio: params.handleJoinAudio, handleCloseAudio: params.handleCloseAudio, }; diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-settings/component.jsx b/bigbluebutton-html5/imports/ui/components/audio/audio-settings/component.jsx index 089a247f3b0ffc79c6dde6010ccb4520b73452f0..3c76e00120a3311d1b6a387e9dce536b9b774fd0 100755 --- a/bigbluebutton-html5/imports/ui/components/audio/audio-settings/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/audio/audio-settings/component.jsx @@ -107,7 +107,7 @@ class AudioSettings extends React.Component { <div className={styles.col}> <div className={styles.formElement}> <label className={cx(styles.label, styles.labelSmall)}> - {intl.formatMessage(intlMessages.streamVolumeLabel)} + {intl.formatMessage(intlMessages.streamVolumeLabel)} <AudioStreamVolume deviceId={this.state.inputDeviceId} className={styles.audioMeter} diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-stream-volume/component.jsx b/bigbluebutton-html5/imports/ui/components/audio/audio-stream-volume/component.jsx index 0104cd50d5618886324c9ce843264d87cdc924b6..bd733931234d8e093e8b8c6e284b927674581a02 100755 --- a/bigbluebutton-html5/imports/ui/components/audio/audio-stream-volume/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/audio/audio-stream-volume/component.jsx @@ -89,7 +89,7 @@ class AudioStreamVolume extends Component { handleConnectStreamToProcessor(stream) { this.source = this.audioContext.createMediaStreamSource(stream); this.source.connect(this.scriptProcessor); - this.scriptProcessor.connect(this.audioContext.destination); + // this.scriptProcessor.connect(this.audioContext.destination); } handleAudioProcess(event) { diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/mute-button/component.jsx b/bigbluebutton-html5/imports/ui/components/audio/mute-button/component.jsx similarity index 66% rename from bigbluebutton-html5/imports/ui/components/actions-bar/mute-button/component.jsx rename to bigbluebutton-html5/imports/ui/components/audio/mute-button/component.jsx index be0d7190f7d1de9a95b905800689327ed1e94f4c..b20650d198bc3c411ed536d9bca9e2b4ec6bf852 100755 --- a/bigbluebutton-html5/imports/ui/components/actions-bar/mute-button/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/audio/mute-button/component.jsx @@ -1,7 +1,7 @@ import React from 'react'; import Button from '/imports/ui/components/button/component'; -import styles from '../styles.scss'; - +import styles from './styles.scss'; +// import { defineMessages, injectIntl } from 'react-intl'; const intlMessages = defineMessages({ @@ -21,35 +21,34 @@ class MuteAudio extends React.Component { const { isInAudio, isMuted, - callback, + toggleMuteMicrophone, isTalking, intl, + isListenOnly, } = this.props; - if (!isInAudio) return null; - const muteLabel = intl.formatMessage(intlMessages.muteLabel); - const unmuteLabel = intl.formatMessage(intlMessages.unmuteLabel); - - const label = !isMuted ? muteLabel : unmuteLabel; const icon = !isMuted ? 'unmute' : 'mute'; - const tabIndex = !isInAudio ? -1 : 0; - let className = null; + const label = intl.formatMessage(!isMuted ? intlMessages.muteLabel : + intlMessages.unmuteLabel); + // const tabIndex = !isInAudio ? -1 : 0; + let className; - if (isInAudio && isTalking) { + if (isTalking) { className = styles.circleGlow; } return ( <Button - onClick={callback} + onClick={toggleMuteMicrophone} label={label} color={'primary'} icon={icon} size={'lg'} circle className={className} - tabIndex={tabIndex} /> + + //tabIndex={tabIndex} ); } } diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/mute-button/container.jsx b/bigbluebutton-html5/imports/ui/components/audio/mute-button/container.jsx similarity index 59% rename from bigbluebutton-html5/imports/ui/components/actions-bar/mute-button/container.jsx rename to bigbluebutton-html5/imports/ui/components/audio/mute-button/container.jsx index 175aebd3f4a3e57b9459c2de8d2389e80cfd7ed0..c74a7895b920d55051ac13a54b249f89c568f2ef 100755 --- a/bigbluebutton-html5/imports/ui/components/actions-bar/mute-button/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/audio/mute-button/container.jsx @@ -1,9 +1,9 @@ import React from 'react'; import { createContainer } from 'meteor/react-meteor-data'; -import { makeCall } from '/imports/ui/services/api'; import VoiceUsers from '/imports/api/2.0/voice-users'; import Auth from '/imports/ui/services/auth/index'; import MuteAudio from './component'; +import AudioManager from '/imports/ui/services/audio-manager'; const MuteAudioContainer = props => (<MuteAudio {...props} />); @@ -11,14 +11,15 @@ export default createContainer(() => { const userId = Auth.userID; const voiceUser = VoiceUsers.findOne({ intId: userId }); - const { muted, joined, talking } = voiceUser; + const { isConnected, isMuted, toggleMuteMicrophone } = AudioManager; + const { talking } = voiceUser; - const callback = () => makeCall('toggleSelfVoice'); + // const callback = () => makeCall('toggleSelfVoice'); const data = { - isInAudio: joined, - isMuted: muted, - callback, + isConnected: isConnected, + isMuted: isMuted, + toggleMuteMicrophone: toggleMuteMicrophone.bind(AudioManager), isTalking: talking, }; return data; diff --git a/bigbluebutton-html5/imports/ui/components/audio/mute-button/styles.scss b/bigbluebutton-html5/imports/ui/components/audio/mute-button/styles.scss new file mode 100644 index 0000000000000000000000000000000000000000..1c4da32635f042c0fa3eeb5779108c5e6eb7289d --- /dev/null +++ b/bigbluebutton-html5/imports/ui/components/audio/mute-button/styles.scss @@ -0,0 +1,3 @@ +.circleGlow > :first-child{ + box-shadow: 0 0 .15rem #FFF !important; +} diff --git a/bigbluebutton-html5/imports/ui/components/audio/open-audio-modal-button/component.jsx b/bigbluebutton-html5/imports/ui/components/audio/open-audio-modal-button/component.jsx new file mode 100644 index 0000000000000000000000000000000000000000..7ed959b2c5c72a89cf874704465149efb099139a --- /dev/null +++ b/bigbluebutton-html5/imports/ui/components/audio/open-audio-modal-button/component.jsx @@ -0,0 +1,16 @@ +import React, { Component } from 'react'; +import Button from '/imports/ui/components/button/component'; +import styles from './styles.scss'; +// +import { defineMessages, injectIntl } from 'react-intl'; + +class OpenAudioModalButton extends Component { + + render() { + return ( + <h1>asdasdasasdsad</h1> + ); + } +} + +export default injectIntl(OpenAudioModalButton); diff --git a/bigbluebutton-html5/imports/ui/components/audio/open-audio-modal-button/container.jsx b/bigbluebutton-html5/imports/ui/components/audio/open-audio-modal-button/container.jsx new file mode 100644 index 0000000000000000000000000000000000000000..c74a7895b920d55051ac13a54b249f89c568f2ef --- /dev/null +++ b/bigbluebutton-html5/imports/ui/components/audio/open-audio-modal-button/container.jsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { createContainer } from 'meteor/react-meteor-data'; +import VoiceUsers from '/imports/api/2.0/voice-users'; +import Auth from '/imports/ui/services/auth/index'; +import MuteAudio from './component'; +import AudioManager from '/imports/ui/services/audio-manager'; + +const MuteAudioContainer = props => (<MuteAudio {...props} />); + +export default createContainer(() => { + const userId = Auth.userID; + const voiceUser = VoiceUsers.findOne({ intId: userId }); + + const { isConnected, isMuted, toggleMuteMicrophone } = AudioManager; + const { talking } = voiceUser; + + // const callback = () => makeCall('toggleSelfVoice'); + + const data = { + isConnected: isConnected, + isMuted: isMuted, + toggleMuteMicrophone: toggleMuteMicrophone.bind(AudioManager), + isTalking: talking, + }; + return data; +}, MuteAudioContainer); diff --git a/bigbluebutton-html5/imports/ui/components/audio/open-audio-modal-button/styles.scss b/bigbluebutton-html5/imports/ui/components/audio/open-audio-modal-button/styles.scss new file mode 100644 index 0000000000000000000000000000000000000000..1c4da32635f042c0fa3eeb5779108c5e6eb7289d --- /dev/null +++ b/bigbluebutton-html5/imports/ui/components/audio/open-audio-modal-button/styles.scss @@ -0,0 +1,3 @@ +.circleGlow > :first-child{ + box-shadow: 0 0 .15rem #FFF !important; +} diff --git a/bigbluebutton-html5/imports/ui/components/audio/service.js b/bigbluebutton-html5/imports/ui/components/audio/service.js index 4238d4eac9350ff39243d092f54d3070aa0510a9..65a2fcada3f1058f056a747c1579126c86b95536 100755 --- a/bigbluebutton-html5/imports/ui/components/audio/service.js +++ b/bigbluebutton-html5/imports/ui/components/audio/service.js @@ -1,9 +1,10 @@ import Users from '/imports/api/2.0/users'; import Auth from '/imports/ui/services/auth'; -import AudioManager from '/imports/api/2.0/audio/client/manager'; +import AudioManager from '/imports/ui/services/audio-manager'; import Meetings from '/imports/api/2.0/meetings'; const init = () => { + console.log('Running audio service init.'); const userId = Auth.userID; const User = Users.findOne({ userId }); const username = User.name; @@ -20,16 +21,19 @@ const init = () => { microphoneLockEnforced, }; - AudioManager.init(userData); + AudioManager.userData = userData; }; -const exitAudio = () => AudioManager.exitAudio(); -const joinListenOnly = () => AudioManager.joinAudio(true); -const joinMicrophone = () => AudioManager.joinAudio(false); - export default { init, - exitAudio, - joinListenOnly, - joinMicrophone, + exitAudio: () => AudioManager.exitAudio(), + joinListenOnly: () => AudioManager.joinAudio(true), + joinMicrophone: () => AudioManager.joinAudio(), + toggleMuteMicrophone: () => AudioManager.toggleMuteMicrophone(), + isConnected: () => AudioManager.isConnected, + isMuted: () => AudioManager.isMuted, + isConnecting: () => AudioManager.isConnecting, + isListenOnly: () => AudioManager.isListenOnly, + inputDeviceId: () => AudioManager.inputDeviceId, + outputDeviceId: () => AudioManager.outputDeviceId, }; diff --git a/bigbluebutton-html5/imports/ui/components/user-list/service.js b/bigbluebutton-html5/imports/ui/components/user-list/service.js index 071ccd55467e0d85509aaf9b777d4b4e131285e1..2a7eb629744596f207aa7a3eba509e27cf68a93f 100644 --- a/bigbluebutton-html5/imports/ui/components/user-list/service.js +++ b/bigbluebutton-html5/imports/ui/components/user-list/service.js @@ -141,6 +141,9 @@ const userFindSorting = { }; const getUsers = () => { + console.log('REMOVE ME BEFORE COMMIT'); + window.Users = Users; + const users = Users .find({ connectionStatus: 'online' }, userFindSorting) .fetch(); diff --git a/bigbluebutton-html5/imports/ui/services/audio-manager/index.js b/bigbluebutton-html5/imports/ui/services/audio-manager/index.js new file mode 100644 index 0000000000000000000000000000000000000000..69eeb03288099eb1180f21d13994fc49d30ccd33 --- /dev/null +++ b/bigbluebutton-html5/imports/ui/services/audio-manager/index.js @@ -0,0 +1,110 @@ +import { Tracker } from 'meteor/tracker'; + +const joinAudioMicrophone = (cb) => { + this.setTimeout(() => { + console.log('joining microphone mock...'); + cb(); + }, 1000) +} + +const exitAudio = (cb) => { + setTimeout(() => { + console.log('exit audio mock...'); + cb(); + }, 1000); +} + +const toggleMuteMicrophone = (cb) => { + cb(); +} + +// const collection = new Mongo.Collection(null); + +class AudioManager { + constructor() { + this.defineProperties({ + isMuted: false, + isConnected: false, + isConnecting: false, + isListenOnly: null, + error: null, + inputDeviceId: null, + outputDeviceId: null, + }); + } + + defineProperties(obj) { + Object.keys(obj).forEach(key => { + let originalKey = `_${key}`; + this[originalKey] = { + value: obj[key], + tracker: new Tracker.Dependency + } + + Object.defineProperty(this, key, { + set: (value) => { + this[originalKey].value = value; + this[originalKey].tracker.changed(); + // console.log('set', originalKey, value); + // this.update(originalKey, value); + }, + get: () => { + this[originalKey].tracker.depend(); + return this[originalKey].value; + // console.log('get', originalKey, collection.findOne({})[originalKey]); + // return collection.findOne({})[originalKey]; + } + }) + }) + + // return collection.insert(obj); + } + + joinAudio(isListenOnly) { + console.log('joinAudio', this, isListenOnly); + this.isConnecting = true; + this.isListenOnly = isListenOnly + + joinAudioMicrophone(this.onAudioJoin.bind(this)); + } + + exitAudio() { + console.log('exitAudio', this); + exitAudio(this.onAudioExit.bind(this)); + } + + toggleMuteMicrophone() { + console.log('toggleMuteMicrophone', this); + toggleMuteMicrophone(this.onToggleMicrophoneMute.bind(this)); + } + + //---------------------------- + + onAudioJoin() { + this.isConnected = true; + this.isConnecting = false; + console.log('onAudioJoin', this); + } + + onAudioExit() { + this.isConnected = false; + this.isListenOnly = null; + this.isMuted = false; + console.log('onAudioExit', this); + } + + onToggleMicrophoneMute() { + this.isMuted = !this.isMuted; + console.log('onToggleMicrophoneMute', this); + } + + //--------------------------- + // update(key, value) { + // const query = { _id: this.stateId }; + // const modifier = { $set: { [key]: value }}; + // collection.update(query, modifier); + // } +} + +const audioManager = new AudioManager(); +export default audioManager;