From 2f78fc05d2594b9d586b0200fbe699d65c8cb32b Mon Sep 17 00:00:00 2001 From: Mario Jr <mariogasparoni@gmail.com> Date: Thu, 22 Apr 2021 15:03:43 -0300 Subject: [PATCH] fix: breakout audio don't use previously selected output device When joining breakout audio, the output device selected in the main room is used in breakout. When returning from breakout rooms, the output audio device previously set in the main room is restored. Some specific info: SIPSession doesn't handle Storage anymore, we do this in SIPBridge, since it has more info about the current selected device and it doesn't depend of a session being oppened. We also now pass the output device ID when joining audio sessions. We can then keep this information in the Storage. Closes #11663 --- .../imports/api/audio/client/bridge/sip.js | 53 ++++++++++++++----- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/bigbluebutton-html5/imports/api/audio/client/bridge/sip.js b/bigbluebutton-html5/imports/api/audio/client/bridge/sip.js index ca41fc8f87..c5ddce996f 100755 --- a/bigbluebutton-html5/imports/api/audio/client/bridge/sip.js +++ b/bigbluebutton-html5/imports/api/audio/client/bridge/sip.js @@ -220,10 +220,14 @@ class SIPSession { set outputDeviceId(deviceId) { this._outputDeviceId = deviceId; - Storage.setItem(OUTPUT_DEVICE_ID_KEY, deviceId); } - joinAudio({ isListenOnly, extension, inputDeviceId }, managerCallback) { + joinAudio({ + isListenOnly, + extension, + inputDeviceId, + outputDeviceId, + }, managerCallback) { return new Promise((resolve, reject) => { const callExtension = extension ? `${extension}${this.userData.voiceBridge}` : this.userData.voiceBridge; @@ -250,10 +254,14 @@ class SIPSession { // If there's an extension passed it means that we're joining the echo test first this.inEchoTest = !!extension; - return this.doCall({ callExtension, isListenOnly, inputDeviceId }) - .catch((reason) => { - reject(reason); - }); + return this.doCall({ + callExtension, + isListenOnly, + inputDeviceId, + outputDeviceId, + }).catch((reason) => { + reject(reason); + }); }); } @@ -278,9 +286,11 @@ class SIPSession { const { isListenOnly, inputDeviceId, + outputDeviceId, } = options; this.inputDeviceId = inputDeviceId; + this.outputDeviceId = outputDeviceId; const { userId, @@ -1217,7 +1227,6 @@ export default class SIPBridge extends BaseAudioBridge { get outputDeviceId() { const sessionOutputDeviceId = Storage.getItem(OUTPUT_DEVICE_ID_KEY); - if (sessionOutputDeviceId) { return sessionOutputDeviceId; } @@ -1278,13 +1287,15 @@ export default class SIPBridge extends BaseAudioBridge { const fallbackExtension = this.activeSession.inEchoTest ? extension : undefined; this.activeSession = new SIPSession(this.user, this.userData, this.protocol, hostname, this.baseCallStates, this.baseErrorCodes, true); - const { inputDeviceId } = this; + const { inputDeviceId, outputDeviceId } = this; this.activeSession.joinAudio({ isListenOnly, extension: fallbackExtension, inputDeviceId, + outputDeviceId, }, callback) .then((value) => { + this.changeOutputDevice(outputDeviceId, true); resolve(value); }).catch((reason) => { reject(reason); @@ -1295,13 +1306,15 @@ export default class SIPBridge extends BaseAudioBridge { return managerCallback(message); }; - const { inputDeviceId } = this; + const { inputDeviceId, outputDeviceId } = this; this.activeSession.joinAudio({ isListenOnly, extension, inputDeviceId, + outputDeviceId, }, callback) .then((value) => { + this.changeOutputDevice(outputDeviceId, true); resolve(value); }).catch((reason) => { reject(reason); @@ -1343,17 +1356,29 @@ export default class SIPBridge extends BaseAudioBridge { return this.activeSession.liveChangeInputDevice(deviceId); } + reloadAudioElement(audioElement) { + if (audioElement && (audioElement.readyState > 0)) { + logger.debug({ + logCode: 'sip_js_reload_audio_element', + extraInfo: { + callerIdName: this.user.callerIdName, + }, + }, 'Reloading audio element after changing output device'); + audioElement.load(); + } + } + async changeOutputDevice(value, isLive) { - const audioContext = document.querySelector(MEDIA_TAG); + const audioElement = document.querySelector(MEDIA_TAG); - if (audioContext.setSinkId) { + if (audioElement.setSinkId) { try { if (!isLive) { - audioContext.srcObject = null; + audioElement.srcObject = null; } - await audioContext.setSinkId(value); - audioContext.load(); + await audioElement.setSinkId(value); + this.reloadAudioElement(audioElement); this.outputDeviceId = value; } catch (err) { logger.error({ -- GitLab