diff --git a/bigbluebutton-html5/imports/api/audio/client/bridge/sip.js b/bigbluebutton-html5/imports/api/audio/client/bridge/sip.js index 271b8e5a3634373776114af6a4b076535e3f9f75..c73616743ade1416b92de5e004a694782983dc7f 100644 --- a/bigbluebutton-html5/imports/api/audio/client/bridge/sip.js +++ b/bigbluebutton-html5/imports/api/audio/client/bridge/sip.js @@ -301,41 +301,41 @@ export default class SIPBridge extends BaseAudioBridge { }); } - getMediaStream(constraints) { - return navigator.mediaDevices.getUserMedia(constraints).catch((err) => { - console.error(err); - throw new Error(this.baseErrorCodes.MEDIA_ERROR); - }); - } + setDefaultInputDevice() { + const handleMediaSuccess = (mediaStream) => { + const deviceLabel = mediaStream.getAudioTracks()[0].label; + return navigator.mediaDevices.enumerateDevices().then((mediaDevices) => { + const device = mediaDevices.find(d => d.label === deviceLabel); + return this.changeInputDevice(device.deviceId); + }); + } - async setDefaultInputDevice() { - const mediaStream = await this.getMediaStream({ audio: true }); - const deviceLabel = mediaStream.getAudioTracks()[0].label; - const mediaDevices = await navigator.mediaDevices.enumerateDevices(); - const device = mediaDevices.find(d => d.label === deviceLabel); - return this.changeInputDevice(device.deviceId); + return navigator.mediaDevices.getUserMedia({ audio: true }).then(handleMediaSuccess); } - async changeInputDevice(value) { + changeInputDevice(value) { const { media, } = this; if (media.inputDevice.audioContext) { - media.inputDevice.audioContext.close().then(() => { + const handleAudioContextCloseSuccess = () => { media.inputDevice.audioContext = null; media.inputDevice.scriptProcessor = null; media.inputDevice.source = null; return this.changeInputDevice(value); - }); + } + + return media.inputDevice.audioContext.close().then(handleAudioContextCloseSuccess); } - media.inputDevice.id = value; if ('AudioContext' in window) { media.inputDevice.audioContext = new window.AudioContext(); } else { media.inputDevice.audioContext = new window.webkitAudioContext(); } + + media.inputDevice.id = value; media.inputDevice.scriptProcessor = media.inputDevice.audioContext .createScriptProcessor(2048, 1, 1); media.inputDevice.source = null; @@ -346,13 +346,16 @@ export default class SIPBridge extends BaseAudioBridge { }, }; - const mediaStream = await this.getMediaStream(constraints); - media.inputDevice.stream = mediaStream; - media.inputDevice.source = media.inputDevice.audioContext.createMediaStreamSource(mediaStream); - media.inputDevice.source.connect(media.inputDevice.scriptProcessor); - media.inputDevice.scriptProcessor.connect(media.inputDevice.audioContext.destination); + const handleMediaSuccess = (mediaStream) => { + media.inputDevice.stream = mediaStream; + media.inputDevice.source = media.inputDevice.audioContext.createMediaStreamSource(mediaStream); + media.inputDevice.source.connect(media.inputDevice.scriptProcessor); + media.inputDevice.scriptProcessor.connect(media.inputDevice.audioContext.destination); + + return this.media.inputDevice; + } - return this.media.inputDevice; + return navigator.mediaDevices.getUserMedia(constraints).then(handleMediaSuccess); } async changeOutputDevice(value) { diff --git a/bigbluebutton-html5/imports/ui/components/audio/container.jsx b/bigbluebutton-html5/imports/ui/components/audio/container.jsx index fbf0ea116c9cfd9d9cdbb38c30af8d33182f6167..c44556f1c6052d4efc4b2327df2169337e7a26ac 100644 --- a/bigbluebutton-html5/imports/ui/components/audio/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/audio/container.jsx @@ -71,6 +71,7 @@ export default withModalMounter(injectIntl(createContainer(({ mountModal, intl } CONNECTION_ERROR: intl.formatMessage(intlMessages.connectionError), REQUEST_TIMEOUT: intl.formatMessage(intlMessages.requestTimeout), INVALID_TARGET: intl.formatMessage(intlMessages.invalidTarget), + MEDIA_ERROR: intl.formatMessage(intlMessages.mediaError), }, }; diff --git a/bigbluebutton-html5/imports/ui/services/audio-manager/index.js b/bigbluebutton-html5/imports/ui/services/audio-manager/index.js index 2480edb5b44bae70e1cdfaf9b2172610af188c62..ae6280fda6afaadc8c6f4a0d5c73444cccf2c0e2 100644 --- a/bigbluebutton-html5/imports/ui/services/audio-manager/index.js +++ b/bigbluebutton-html5/imports/ui/services/audio-manager/index.js @@ -65,28 +65,39 @@ class AudioManager { isEchoTest, } = options; - if (!this.devicesInitialized) { - this.setDefaultInputDevice(); - this.changeOutputDevice('default'); + const doCall = () => { this.devicesInitialized = true; + this.isConnecting = true; + this.isMuted = false; + this.error = null; + this.isListenOnly = isListenOnly || false; + this.isEchoTest = isEchoTest || false; + + const callOptions = { + isListenOnly: this.isListenOnly, + extension: isEchoTest ? ECHO_TEST_NUMBER : null, + inputStream: this.isListenOnly ? this.createListenOnlyStream() : this.inputStream, + }; + + return this.bridge.joinAudio(callOptions, this.callStateCallback.bind(this)); } - this.isConnecting = true; - this.isMuted = false; - this.error = null; - this.isListenOnly = isListenOnly || false; - this.isEchoTest = isEchoTest || false; - - const callOptions = { - isListenOnly: this.isListenOnly, - extension: isEchoTest ? ECHO_TEST_NUMBER : null, - inputStream: this.isListenOnly ? this.createListenOnlyStream() : this.inputStream, - }; + if (this.devicesInitialized) return doCall(); - return this.bridge.joinAudio(callOptions, this.callStateCallback.bind(this)); + return Promise.all([ + this.setDefaultInputDevice(), + this.setDefaultOutputDevice(), + ]).then(doCall) + .catch(err => { + this.error = err; + this.notify(err); + return Promise.reject(); + }); } exitAudio() { + if (!this.isConnected) return Promise.resolve(); + this.isHangingUp = true; return this.bridge.exitAudio(); } @@ -173,20 +184,27 @@ class AudioManager { } setDefaultInputDevice() { - this.changeInputDevice(); + return this.changeInputDevice(); } - async changeInputDevice(deviceId) { - try { - if (!deviceId) { - this.inputDevice = await await this.bridge.setDefaultInputDevice(); - return; - } - this.inputDevice = await this.bridge.changeInputDevice(deviceId); - } catch(err) { - this.error = err; - this.notify('There was a problem getting the media devices'); + setDefaultOutputDevice() { + return this.changeOutputDevice('default'); + } + + changeInputDevice(deviceId) { + const handleChangeInputDeviceSuccess = (inputDevice) => { + this.inputDevice = inputDevice; + return inputDevice; + }; + + const handleChangeInputDeviceError = () => Promise.reject(this.messages.error.MEDIA_ERROR); + + if (!deviceId) { + return this.bridge.setDefaultInputDevice().then(handleChangeInputDeviceSuccess) + .catch(handleChangeInputDeviceError); } + return this.bridge.changeInputDevice(deviceId).then(handleChangeInputDeviceSuccess) + .catch(handleChangeInputDeviceError);; } async changeOutputDevice(deviceId) { diff --git a/bigbluebutton-html5/private/locales/en.json b/bigbluebutton-html5/private/locales/en.json index ceba85eaa22145f9153873464e7fb40e97c2c60a..90993d0f13bd803459873ce6903478d7e3c1802c 100644 --- a/bigbluebutton-html5/private/locales/en.json +++ b/bigbluebutton-html5/private/locales/en.json @@ -215,7 +215,7 @@ "app.audioManager.connectionError": "Error: Connection error", "app.audioManager.requestTimeout": "Error: There was a timeout in the request", "app.audioManager.invalidTarget": "Error: Tried to request something to an invalid target", - "app.audioManager.mediaError": "Error: There was an error getting your media devices", + "app.audioManager.mediaError": "Error: There was an issue getting your media devices", "app.audio.joinAudio": "Join Audio", "app.audio.leaveAudio": "Leave Audio", "app.audio.enterSessionLabel": "Enter Session",