Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions img/COPYING
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,11 @@
## leave_call.ogg
@author Marco Ambrosini ([email protected])
@license CC0-1.0

## join_call.flac
@author Marco Ambrosini ([email protected])
@license CC0-1.0

## leave_call.flac
@author Marco Ambrosini ([email protected])
@license CC0-1.0
Binary file added img/LibremPhoneCall.flac
Binary file not shown.
Binary file added img/join_call.flac
Binary file not shown.
Binary file added img/leave_call.flac
Binary file not shown.
2 changes: 1 addition & 1 deletion src/components/SettingsDialog/SettingsDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
@update:checked="togglePlaySounds">
{{ t('spreed', 'Play sounds when participants join or leave a call') }}
</NcCheckboxRadioSwitch>
<em>{{ t('spreed', 'Sounds can currently not be played in Safari browser and iPad and iPhone devices due to technical restrictions by the manufacturer.') }}</em>
<em>{{ t('spreed', 'Sounds can currently not be played on iPad and iPhone devices due to technical restrictions by the manufacturer.') }}</em>

<a :href="settingsUrl"
target="_blank"
Expand Down
3 changes: 3 additions & 0 deletions src/components/TopBar/CallButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
154 changes: 154 additions & 0 deletions src/store/soundsStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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 = {
Expand All @@ -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 = {
Expand All @@ -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 }
30 changes: 5 additions & 25 deletions src/utils/sounds.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
*
*/

import { generateFilePath } from '@nextcloud/router'

import store from '../store/index.js'

export const Sounds = {
Expand All @@ -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)
},

Expand All @@ -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(() => {
Expand All @@ -77,7 +57,7 @@ export const Sounds = {
}

console.debug('Playing waiting sound')
this.backgroundAudio.play()
store.dispatch('playWaitAudio')
this.playedWaiting++

}, 15000)
Expand Down Expand Up @@ -114,7 +94,7 @@ export const Sounds = {
if (playWaitingSound) {
await this.playWaiting()
} else {
this._playSoundOnce('join_call.ogg')
store.dispatch('playJoinAudio')
}
},

Expand Down Expand Up @@ -145,7 +125,7 @@ export const Sounds = {
}
this.lastPlayedLeave = currentTime

this._playSoundOnce('leave_call.ogg')
store.dispatch('playLeaveAudio')

if (playWaitingSound) {
this.playWaiting()
Expand Down