diff options
author | Marcel Müller <marcel-mueller@gmx.de> | 2023-05-02 11:32:40 +0200 |
---|---|---|
committer | backportbot-nextcloud[bot] <backportbot-nextcloud[bot]@users.noreply.github.com> | 2023-08-03 12:40:40 +0000 |
commit | 0738a81ca36d5373752d045edc71d7405a56155a (patch) | |
tree | bf8790e1637ab26d8dfe907eb1462fd79cf3b913 | |
parent | edc585cf7ec7e406119f6afeb0784a447ade7ec5 (diff) |
Create audio objects for call sounds as a result of a user interaction
Signed-off-by: Marcel Müller <marcel-mueller@gmx.de>
-rw-r--r-- | src/components/TopBar/CallButton.vue | 3 | ||||
-rw-r--r-- | src/store/soundsStore.js | 154 | ||||
-rw-r--r-- | src/utils/sounds.js | 30 |
3 files changed, 162 insertions, 25 deletions
diff --git a/src/components/TopBar/CallButton.vue b/src/components/TopBar/CallButton.vue index 82fa94d4f..22b3efb2f 100644 --- a/src/components/TopBar/CallButton.vue +++ b/src/components/TopBar/CallButton.vue @@ -332,6 +332,9 @@ export default { }, handleClick() { + // Create audio objects as a result of a user interaction to allow playing sounds in Safari + this.$store.dispatch('createAudioObjects') + const shouldShowMediaSettingsScreen = (BrowserStorage.getItem('showMediaSettings' + this.token) === null || BrowserStorage.getItem('showMediaSettings' + this.token) === 'true') && !this.forceJoinCall console.debug(shouldShowMediaSettingsScreen) diff --git a/src/store/soundsStore.js b/src/store/soundsStore.js index c67a27171..75dbf9b17 100644 --- a/src/store/soundsStore.js +++ b/src/store/soundsStore.js @@ -21,6 +21,7 @@ */ import { loadState } from '@nextcloud/initial-state' +import { generateFilePath } from '@nextcloud/router' import BrowserStorage from '../services/BrowserStorage.js' import { setPlaySounds } from '../services/settingsService.js' @@ -29,6 +30,10 @@ const state = { userId: undefined, playSoundsUser: loadState('spreed', 'play_sounds', false), playSoundsGuest: BrowserStorage.getItem('play_sounds') !== 'no', + audioObjectsCreated: false, + joinAudioObject: null, + leaveAudioObject: null, + waitAudioObject: null, } const getters = { @@ -55,6 +60,76 @@ const mutations = { setUserId(state, userId) { state.userId = userId }, + + /** + * Sets the join audio object + * + * @param {object} state current store state + * @param {HTMLAudioElement} audioObject new audio object + */ + setJoinAudioObject(state, audioObject) { + state.joinAudioObject = audioObject + }, + + /** + * Sets the leave audio object + * + * @param {object} state current store state + * @param {HTMLAudioElement} audioObject new audio object + */ + setLeaveAudioObject(state, audioObject) { + state.leaveAudioObject = audioObject + }, + + /** + * Sets the wait audio object + * + * @param {object} state current store state + * @param {HTMLAudioElement} audioObject new audio object + */ + setWaitAudioObject(state, audioObject) { + state.waitAudioObject = audioObject + }, + + /** + * Sets a flag that all audio objects were created + * + * @param {object} state current store state + */ + setAudioObjectsCreated(state) { + state.audioObjectsCreated = true + }, +} + +/** + * Helper method to get the full file path of an audio file in spreed/img. + * Example: getFullAudioFilepath('myAudio') => spreed/img/myAudio.ogg + * + * @param {string} fileName The name of the file without extension + * @return {string} The full path to the file in the spreed/img directory and adds .ogg/.flac depending on supported codecs + */ +const getFullAudioFilepath = function(fileName) { + const tempAudio = new Audio() + + // Prefer the .ogg version of sounds, but fall back to .flac in case .ogg is not supported (Safari) + if (tempAudio.canPlayType('audio/ogg')) { + return generateFilePath('spreed', 'img', fileName + '.ogg') + } else { + return generateFilePath('spreed', 'img', fileName + '.flac') + } +} + +/** + * Creates a HTMLAudioElement with the specified filePath and loads it + * + * @param {string} filePath Path to the file + * @return {HTMLAudioElement} The created and loaded HTMLAudioElement + */ +const createAudioObject = function(filePath) { + const audio = new Audio(filePath) + audio.load() + + return audio } const actions = { @@ -78,6 +153,85 @@ const actions = { await setPlaySounds(!context.state.userId, enabled) context.commit('setPlaySounds', enabled) }, + + /** + * Plays the join audio file with a volume of 0.75 + * + * @param {object} context default store context + */ + playJoinAudio(context) { + // Make sure the audio objects are really created before playing it + context.dispatch('createAudioObjects') + + const audio = context.state.joinAudioObject + audio.load() + audio.volume = 0.75 + audio.play() + }, + + /** + * Plays the leave audio file with a volume of 0.75 + * + * @param {object} context default store context + */ + playLeaveAudio(context) { + // Make sure the audio objects are really created before playing it + context.dispatch('createAudioObjects') + + const audio = context.state.leaveAudioObject + audio.load() + audio.volume = 0.75 + audio.play() + }, + + /** + * Plays the wait audio file with a volume of 0.5 + * + * @param {object} context default store context + */ + playWaitAudio(context) { + // Make sure the audio objects are really created before playing it + context.dispatch('createAudioObjects') + + const audio = context.state.waitAudioObject + audio.load() + audio.volume = 0.5 + audio.play() + }, + + /** + * Pauses the wait audio playback + * + * @param {object} context default store context + */ + pauseWaitAudio(context) { + const audio = context.state.waitAudioObject + audio.pause() + }, + + /** + * If not already created, this creates audio objects for join, leave and wait sounds + * + * @param {object} context default store context + */ + createAudioObjects(context) { + // No need to create the audio objects, if they were created already + if (context.state.audioObjectsCreated) { + return + } + + const joinFilepath = getFullAudioFilepath('join_call') + const joinAudio = createAudioObject(joinFilepath) + context.commit('setJoinAudioObject', joinAudio) + + const leaveFilepath = getFullAudioFilepath('leave_call') + const leaveAudio = createAudioObject(leaveFilepath) + context.commit('setLeaveAudioObject', leaveAudio) + + const waitFilepath = getFullAudioFilepath('LibremPhoneCall') + const waitAudio = createAudioObject(waitFilepath) + context.commit('setWaitAudioObject', waitAudio) + }, } export default { state, mutations, getters, actions } diff --git a/src/utils/sounds.js b/src/utils/sounds.js index 35563d670..e712b2866 100644 --- a/src/utils/sounds.js +++ b/src/utils/sounds.js @@ -18,8 +18,6 @@ * */ -import { generateFilePath } from '@nextcloud/router' - import store from '../store/index.js' export const Sounds = { @@ -29,22 +27,11 @@ export const Sounds = { lastPlayedJoin: 0, lastPlayedLeave: 0, playedWaiting: 0, - backgroundAudio: null, backgroundInterval: null, - _playSoundOnce(soundFile) { - const file = generateFilePath('spreed', 'img', soundFile) - const audio = new Audio(file) - audio.volume = 0.75 - audio.play() - }, - _stopWaiting() { console.debug('Stop waiting sound') - if (this.backgroundAudio) { - this.backgroundAudio.pause() - this.backgroundAudio = null - } + store.dispatch('pauseWaitAudio') clearInterval(this.backgroundInterval) }, @@ -53,15 +40,8 @@ export const Sounds = { return } - if (!this.backgroundAudio) { - console.debug('Loading waiting sound') - const file = generateFilePath('spreed', 'img', 'LibremPhoneCall.ogg') - this.backgroundAudio = new Audio(file) - this.backgroundAudio.volume = 0.5 - } - console.debug('Playing waiting sound') - this.backgroundAudio.play() + store.dispatch('playWaitAudio') this.playedWaiting = 0 this.backgroundInterval = setInterval(() => { @@ -77,7 +57,7 @@ export const Sounds = { } console.debug('Playing waiting sound') - this.backgroundAudio.play() + store.dispatch('playWaitAudio') this.playedWaiting++ }, 15000) @@ -114,7 +94,7 @@ export const Sounds = { if (playWaitingSound) { await this.playWaiting() } else { - this._playSoundOnce('join_call.ogg') + store.dispatch('playJoinAudio') } }, @@ -145,7 +125,7 @@ export const Sounds = { } this.lastPlayedLeave = currentTime - this._playSoundOnce('leave_call.ogg') + store.dispatch('playLeaveAudio') if (playWaitingSound) { this.playWaiting() |