From 029a13d2a08fd60287955057fd95f975051e2ef8 Mon Sep 17 00:00:00 2001 From: gcampes <gabrieldecampes@gmail.com> Date: Fri, 20 Oct 2017 08:11:51 -0200 Subject: [PATCH] better error handling, code cleanup --- .../imports/api/audio/client/bridge/sip.js | 94 ++++++++++--------- .../audio/audio-controls/component.jsx | 2 + .../audio/audio-controls/container.jsx | 26 +---- .../ui/services/audio-manager/index.js | 23 ++--- 4 files changed, 63 insertions(+), 82 deletions(-) diff --git a/bigbluebutton-html5/imports/api/audio/client/bridge/sip.js b/bigbluebutton-html5/imports/api/audio/client/bridge/sip.js index c2cd5653a7..894457edf9 100644 --- a/bigbluebutton-html5/imports/api/audio/client/bridge/sip.js +++ b/bigbluebutton-html5/imports/api/audio/client/bridge/sip.js @@ -9,22 +9,20 @@ const CALL_TRANSFER_TIMEOUT = MEDIA.callTransferTimeout; const fetchStunTurnServers = sessionToken => new Promise(async (resolve, reject) => { - const handleStunTurnResponse = ({ result, stunServers, turnServers }) => - new Promise((resolve) => { - if (result) { - resolve({ error: 404, stun: [], turn: [] }); - } - resolve({ - stun: stunServers.map(server => server.url), - turn: turnServers.map(server => server.url), - }); - }); + const handleStunTurnResponse = ({ stunServers, turnServers }) => { + if (!stunServers && !turnServers) { + return { error: 404, stun: [], turn: [] }; + } + return { + stun: stunServers.map(server => server.url), + turn: turnServers.map(server => server.url), + }; + }; const url = `${STUN_TURN_FETCH_URL}?sessionToken=${sessionToken}`; - const response = await fetch(url) .then(res => res.json()) - .then(json => handleStunTurnResponse(json)); + .then(handleStunTurnResponse); if (response.error) return reject('Could not fetch the stuns/turns servers!'); return resolve(response); @@ -52,7 +50,7 @@ export default class SIPBridge extends BaseAudioBridge { this.protocol = window.document.location.protocol; this.hostname = window.document.location.hostname; - const causes = window.SIP.C.causes + const causes = window.SIP.C.causes; this.errorCodes = { [causes.REQUEST_TIMEOUT]: this.baseErrorCodes.REQUEST_TIMEOUT, [causes.INVALID_TARGET]: this.baseErrorCodes.INVALID_TARGET, @@ -72,12 +70,42 @@ export default class SIPBridge extends BaseAudioBridge { return this.doCall({ callExtension, isListenOnly, inputStream }, callback) .catch((reason) => { - callback({ status: this.baseCallStates.failed, error: reason }); + callback({ + status: this.baseCallStates.failed, + error: this.baseErrorCodes.GENERIC_ERROR, + bridgeError: reason, + }); reject(reason); }); }); } + doCall(options) { + const { + isListenOnly, + } = options; + + const { + userId, + name, + sessionToken, + } = this.user; + + const callerIdName = [ + userId, + 'bbbID', + isListenOnly ? `LISTENONLY-${name}` : name, + ].join('-'); + + this.user.callerIdName = callerIdName; + this.callOptions = options; + + return fetchStunTurnServers(sessionToken) + .then(this.createUserAgent.bind(this)) + .then(this.inviteUserAgent.bind(this)) + .then(this.setupEventHandlers.bind(this)); + } + transferCall(onTransferSuccess) { return new Promise((resolve, reject) => { let trackerControl = null; @@ -89,7 +117,7 @@ export default class SIPBridge extends BaseAudioBridge { status: this.baseCallStates.failed, error: this.baseErrorCodes.REQUEST_TIMEOUT, bridgeError: 'Timeout on call transfer' }); - reject('Timeout on call transfer'); + reject(this.baseErrorCodes.REQUEST_TIMEOUT); }, CALL_TRANSFER_TIMEOUT); // This is is the call transfer code ask @chadpilkey @@ -123,32 +151,6 @@ export default class SIPBridge extends BaseAudioBridge { }); } - doCall(options) { - const { - isListenOnly, - } = options; - - const { - userId, - name, - sessionToken, - } = this.user; - - const callerIdName = [ - userId, - 'bbbID', - isListenOnly ? `LISTENONLY-${name}` : name, - ].join('-'); - - this.user.callerIdName = callerIdName; - this.callOptions = options; - - return fetchStunTurnServers(sessionToken) - .then(this.createUserAgent.bind(this)) - .then(this.inviteUserAgent.bind(this)) - .then(this.setupEventHandlers.bind(this)); - } - createUserAgent({ stun, turn }) { return new Promise((resolve, reject) => { const { @@ -187,9 +189,9 @@ export default class SIPBridge extends BaseAudioBridge { userAgent = null; this.callback({ status: this.baseCallStates.failed, - error: this.baseErrorCodes.GENERIC_ERROR, - bridgeError: 'User Agent' }); - reject('CONNECTION_ERROR'); + error: this.baseErrorCodes.CONNECTION_ERROR, + bridgeError: 'User Agent Disconnected' }); + reject(this.baseErrorCodes.CONNECTION_ERROR); }; userAgent.on('connected', handleUserAgentConnection); @@ -248,6 +250,7 @@ export default class SIPBridge extends BaseAudioBridge { const mappedCause = cause in this.errorCodes ? this.errorCodes[cause] : this.baseErrorCodes.GENERIC_ERROR; + return this.callback({ status: this.baseCallStates.failed, error: mappedCause, @@ -295,7 +298,7 @@ export default class SIPBridge extends BaseAudioBridge { media.inputDevice.audioContext = new window.webkitAudioContext(); } media.inputDevice.scriptProcessor = media.inputDevice.audioContext - .createScriptProcessor(2048, 1, 1); + .createScriptProcessor(2048, 1, 1); media.inputDevice.source = null; const constraints = { @@ -318,6 +321,7 @@ export default class SIPBridge extends BaseAudioBridge { if (audioContext.setSinkId) { audioContext.setSinkId(value); + this.media.outputDeviceId = value; } return value; diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/component.jsx b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/component.jsx index 6d7264a3b5..c01483ec7a 100644 --- a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/component.jsx @@ -18,6 +18,7 @@ const AudioControls = ({ handleLeaveAudio, mute, unmute, + disable, join, }) => ( <span className={styles.container}> @@ -34,6 +35,7 @@ const AudioControls = ({ <Button className={styles.button} onClick={join ? handleLeaveAudio : handleJoinAudio} + disable={disable} label={join ? 'Leave Audio' : 'Join Audio'} color={join ? 'danger' : 'primary'} icon={join ? 'audio_off' : 'audio_on'} diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx index dd7738ef43..1a85e64546 100644 --- a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx @@ -1,39 +1,19 @@ import React from 'react'; import { createContainer } from 'meteor/react-meteor-data'; -// import PropTypes from 'prop-types'; import { withModalMounter } from '/imports/ui/components/modal/service'; import AudioControls from './component'; import AudioModalContainer from '../audio-modal/container'; import Service from '../service'; -// const propTypes = { -// children: PropTypes.element, -// }; -// -// const defaultProps = { -// children: null, -// }; - const AudioControlsContainer = props => <AudioControls {...props} />; export default withModalMounter(createContainer(({ mountModal }) => - // 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; - ({ - mute: Service.isConnected() && !Service.isListenOnly(), + mute: Service.isConnected() && !Service.isListenOnly() && !Service.isEchoTest(), unmute: Service.isConnected() && !Service.isListenOnly() && Service.isMuted(), - join: Service.isConnected(), - + join: Service.isConnected() && !Service.isEchoTest(), + disable: Service.isConnecting(), handleToggleMuteMicrophone: () => Service.toggleMuteMicrophone(), handleJoinAudio: () => mountModal(<AudioModalContainer />), handleLeaveAudio: () => Service.exitAudio(), }), AudioControlsContainer)); - -// AudioControlsContainer.propTypes = propTypes; -// AudioControlsContainer.defaultProps = defaultProps; diff --git a/bigbluebutton-html5/imports/ui/services/audio-manager/index.js b/bigbluebutton-html5/imports/ui/services/audio-manager/index.js index 1e3c2d4868..98fdde688f 100644 --- a/bigbluebutton-html5/imports/ui/services/audio-manager/index.js +++ b/bigbluebutton-html5/imports/ui/services/audio-manager/index.js @@ -77,7 +77,7 @@ class AudioManager { inputStream: this.isListenOnly ? this.createListenOnlyStream() : this.inputStream, }; - return this.bridge.joinAudio(callOptions, this.callStateCallback.bind(this)); + return this.bridge.joinAudio(callOptions, this.callStateCallback.bind(this)) } exitAudio() { @@ -97,12 +97,11 @@ class AudioManager { onAudioJoin() { this.isConnecting = false; - if (this.isEchoTest) { - return; - }1 - - notify(this.messages.info.JOINED_AUDIO, 'info', 'audio_on'); this.isConnected = true; + + if (!this.isEchoTest) { + notify(this.messages.info.JOINED_AUDIO, 'info', 'audio_on'); + } } onTransferStart() { @@ -114,16 +113,11 @@ class AudioManager { this.isConnected = false; this.isConnecting = false; - if (this.isEchoTest) { - this.isEchoTest = false; - return; - } - if (this.error) { - return; + if (!this.error && !this.isEchoTest) { + notify(this.messages.info.LEFT_AUDIO, 'info', 'audio_on'); } - - notify(this.messages.info.LEFT_AUDIO, 'info', 'audio_on'); + this.isEchoTest = false; } onToggleMicrophoneMute() { @@ -151,6 +145,7 @@ class AudioManager { } else if (status === FAILED) { this.error = error; notify(this.messages.error[error], 'error', 'audio_on'); + console.error('Audio Error:', error); this.onAudioExit(); } }); -- GitLab