diff --git a/docs/capabilities.md b/docs/capabilities.md
index f8bebf371cd..a23dbef4c40 100644
--- a/docs/capabilities.md
+++ b/docs/capabilities.md
@@ -162,3 +162,4 @@
* `download-call-participants` - Whether the endpoints for moderators to download the call participants is available
* `config => call => start-without-media` (local) - Boolean, whether media should be disabled when starting or joining a conversation
* `config => call => max-duration` - Integer, maximum call duration in seconds. Please note that this should only be used with system cron and with a reasonable high value, due to the expended duration until the background job ran.
+* `config => call => blur-virtual-background` (local) - Boolean, whether blur background is set by default when joining a conversation
diff --git a/docs/settings.md b/docs/settings.md
index 6093c41af7e..ad2543d8412 100644
--- a/docs/settings.md
+++ b/docs/settings.md
@@ -24,13 +24,14 @@
**Note:** Settings from `calls_start_without_media` onwards can not be set via above API.
Instead, the server API `POST /ocs/v2.php/apps/provisioning_api/api/v1/config/users/{appId}/{configKey}` needs to be used.
-| Key | Capability | Default | Valid values |
-|-----------------------------|-----------------------------------------|----------------------------------------------------|----------------------------------------------------------------------------------------------------------|
-| `attachment_folder` | `config => attachments => folder` | Value of app config `default_attachment_folder` | Path owned by the user to store uploads and received shares. It is created if it does not exist. |
-| `read_status_privacy` | `config => chat => read-privacy` | `0` | One of the read-status constants from the [constants list](constants.md#participant-read-status-privacy) |
-| `typing_privacy` | `config => chat => typing-privacy` | `0` | One of the typing privacy constants from the [constants list](constants.md#participant-typing-privacy) |
-| `play_sounds` | | `'yes'` | `'yes'` and `'no'` |
-| `calls_start_without_media` | `config => call => start-without-media` | `''` falling back to app config with the same name | `'yes'` and `'no'` |
+| Key | Capability | Default | Valid values |
+|-----------------------------|---------------------------------------------|----------------------------------------------------|----------------------------------------------------------------------------------------------------------|
+| `attachment_folder` | `config => attachments => folder` | Value of app config `default_attachment_folder` | Path owned by the user to store uploads and received shares. It is created if it does not exist. |
+| `read_status_privacy` | `config => chat => read-privacy` | `0` | One of the read-status constants from the [constants list](constants.md#participant-read-status-privacy) |
+| `typing_privacy` | `config => chat => typing-privacy` | `0` | One of the typing privacy constants from the [constants list](constants.md#participant-typing-privacy) |
+| `play_sounds` | | `'yes'` | `'yes'` and `'no'` |
+| `calls_start_without_media` | `config => call => start-without-media` | `''` falling back to app config with the same name | `'yes'` and `'no'` |
+| `blur_virtual_background` | `config => call => blur-virtual-background` | `'no'` | `'yes'` and `'no'` |
## Set SIP settings
diff --git a/lib/Capabilities.php b/lib/Capabilities.php
index cb30c4bb443..4d777717ef0 100644
--- a/lib/Capabilities.php
+++ b/lib/Capabilities.php
@@ -130,6 +130,7 @@ class Capabilities implements IPublicCapability {
'predefined-backgrounds',
'can-upload-background',
'start-without-media',
+ 'blur-virtual-background',
],
'chat' => [
'read-privacy',
@@ -201,6 +202,7 @@ public function getCapabilities(): array {
'can-enable-sip' => false,
'start-without-media' => $this->talkConfig->getCallsStartWithoutMedia($user?->getUID()),
'max-duration' => $this->appConfig->getAppValueInt('max_call_duration'),
+ 'blur-virtual-background' => $this->talkConfig->getBlurVirtualBackground($user?->getUID()),
],
'chat' => [
'max-length' => ChatManager::MAX_CHAT_LENGTH,
@@ -250,6 +252,7 @@ public function getCapabilities(): array {
$capabilities['config']['attachments']['folder'] = $this->talkConfig->getAttachmentFolder($user->getUID());
$capabilities['config']['chat']['read-privacy'] = $this->talkConfig->getUserReadPrivacy($user->getUID());
$capabilities['config']['chat']['typing-privacy'] = $this->talkConfig->getUserTypingPrivacy($user->getUID());
+ $capabilities['config']['call']['blur-virtual-background'] = $this->talkConfig->getBlurVirtualBackground($user->getUID());
}
$pubKey = $this->talkConfig->getSignalingTokenPublicKey();
diff --git a/lib/Config.php b/lib/Config.php
index 2019731d976..87f26c52cd5 100644
--- a/lib/Config.php
+++ b/lib/Config.php
@@ -680,4 +680,18 @@ public function getCallsStartWithoutMedia(?string $userId): bool {
return $this->appConfig->getAppValueBool('calls_start_without_media');
}
+
+ /**
+ * User setting for blur background
+ *
+ * @param ?string $userId
+ * @return bool
+ */
+ public function getBlurVirtualBackground(?string $userId): bool {
+ if ($userId !== null) {
+ $userSetting = $this->config->getUserValue($userId, 'spreed', UserPreference::BLUR_VIRTUAL_BACKGROUND);
+ return $userSetting === 'yes';
+ }
+ return false;
+ }
}
diff --git a/lib/Controller/RoomController.php b/lib/Controller/RoomController.php
index 17821e88409..4efb1c853ff 100644
--- a/lib/Controller/RoomController.php
+++ b/lib/Controller/RoomController.php
@@ -2458,6 +2458,9 @@ public function getCapabilities(): DataResponse {
if (isset($data['config']['call']['start-without-media'])) {
$data['config']['call']['start-without-media'] = $this->talkConfig->getCallsStartWithoutMedia($this->userId);
}
+ if (isset($data['config']['call']['blur-virtual-background'])) {
+ $data['config']['call']['blur-virtual-background'] = $this->talkConfig->getBlurVirtualBackground($this->userId);
+ }
if ($response->getHeaders()['X-Nextcloud-Talk-Hash']) {
$headers['X-Nextcloud-Talk-Proxy-Hash'] = $response->getHeaders()['X-Nextcloud-Talk-Hash'];
diff --git a/lib/Federation/Proxy/TalkV1/ProxyRequest.php b/lib/Federation/Proxy/TalkV1/ProxyRequest.php
index 04305ca24d1..ea5d606bc2f 100644
--- a/lib/Federation/Proxy/TalkV1/ProxyRequest.php
+++ b/lib/Federation/Proxy/TalkV1/ProxyRequest.php
@@ -42,6 +42,9 @@ public function overwrittenRemoteTalkHash(string $hash): string {
'read-privacy',
'typing-privacy',
],
+ 'call' => [
+ 'blur-virtual-background',
+ ]
],
]
]));
diff --git a/lib/ResponseDefinitions.php b/lib/ResponseDefinitions.php
index 9722340e49d..3fef42ab4db 100644
--- a/lib/ResponseDefinitions.php
+++ b/lib/ResponseDefinitions.php
@@ -348,6 +348,7 @@
* can-enable-sip: bool,
* start-without-media: bool,
* max-duration: int,
+ * blur-virtual-background: bool,
* },
* chat: array{
* max-length: int,
diff --git a/lib/Settings/BeforePreferenceSetEventListener.php b/lib/Settings/BeforePreferenceSetEventListener.php
index 00f41f19f6a..1fe87fdb1d5 100644
--- a/lib/Settings/BeforePreferenceSetEventListener.php
+++ b/lib/Settings/BeforePreferenceSetEventListener.php
@@ -60,7 +60,8 @@ public function validatePreference(string $userId, string $key, string|int|null
// "boolean" yes/no
if ($key === UserPreference::CALLS_START_WITHOUT_MEDIA
- || $key === UserPreference::PLAY_SOUNDS) {
+ || $key === UserPreference::PLAY_SOUNDS
+ || $key === UserPreference::BLUR_VIRTUAL_BACKGROUND) {
return $value === 'yes' || $value === 'no';
}
diff --git a/lib/Settings/UserPreference.php b/lib/Settings/UserPreference.php
index f360172f20e..6c729ae0f11 100644
--- a/lib/Settings/UserPreference.php
+++ b/lib/Settings/UserPreference.php
@@ -9,6 +9,7 @@
namespace OCA\Talk\Settings;
class UserPreference {
+ public const BLUR_VIRTUAL_BACKGROUND = 'blur_virtual_background';
public const CALLS_START_WITHOUT_MEDIA = 'calls_start_without_media';
public const PLAY_SOUNDS = 'play_sounds';
public const TYPING_PRIVACY = 'typing_privacy';
diff --git a/openapi-administration.json b/openapi-administration.json
index fa4e80bed78..84f73eb4e61 100644
--- a/openapi-administration.json
+++ b/openapi-administration.json
@@ -149,7 +149,8 @@
"sip-dialout-enabled",
"can-enable-sip",
"start-without-media",
- "max-duration"
+ "max-duration",
+ "blur-virtual-background"
],
"properties": {
"enabled": {
@@ -195,6 +196,9 @@
"max-duration": {
"type": "integer",
"format": "int64"
+ },
+ "blur-virtual-background": {
+ "type": "boolean"
}
}
},
diff --git a/openapi-backend-recording.json b/openapi-backend-recording.json
index f6b1d452627..11f4b758125 100644
--- a/openapi-backend-recording.json
+++ b/openapi-backend-recording.json
@@ -82,7 +82,8 @@
"sip-dialout-enabled",
"can-enable-sip",
"start-without-media",
- "max-duration"
+ "max-duration",
+ "blur-virtual-background"
],
"properties": {
"enabled": {
@@ -128,6 +129,9 @@
"max-duration": {
"type": "integer",
"format": "int64"
+ },
+ "blur-virtual-background": {
+ "type": "boolean"
}
}
},
diff --git a/openapi-backend-signaling.json b/openapi-backend-signaling.json
index ad42624f290..2d74e247e13 100644
--- a/openapi-backend-signaling.json
+++ b/openapi-backend-signaling.json
@@ -82,7 +82,8 @@
"sip-dialout-enabled",
"can-enable-sip",
"start-without-media",
- "max-duration"
+ "max-duration",
+ "blur-virtual-background"
],
"properties": {
"enabled": {
@@ -128,6 +129,9 @@
"max-duration": {
"type": "integer",
"format": "int64"
+ },
+ "blur-virtual-background": {
+ "type": "boolean"
}
}
},
diff --git a/openapi-backend-sipbridge.json b/openapi-backend-sipbridge.json
index 5df0b9eeb46..aecba7b3a81 100644
--- a/openapi-backend-sipbridge.json
+++ b/openapi-backend-sipbridge.json
@@ -125,7 +125,8 @@
"sip-dialout-enabled",
"can-enable-sip",
"start-without-media",
- "max-duration"
+ "max-duration",
+ "blur-virtual-background"
],
"properties": {
"enabled": {
@@ -171,6 +172,9 @@
"max-duration": {
"type": "integer",
"format": "int64"
+ },
+ "blur-virtual-background": {
+ "type": "boolean"
}
}
},
diff --git a/openapi-bots.json b/openapi-bots.json
index 8f24560fe4b..45a49772408 100644
--- a/openapi-bots.json
+++ b/openapi-bots.json
@@ -82,7 +82,8 @@
"sip-dialout-enabled",
"can-enable-sip",
"start-without-media",
- "max-duration"
+ "max-duration",
+ "blur-virtual-background"
],
"properties": {
"enabled": {
@@ -128,6 +129,9 @@
"max-duration": {
"type": "integer",
"format": "int64"
+ },
+ "blur-virtual-background": {
+ "type": "boolean"
}
}
},
diff --git a/openapi-federation.json b/openapi-federation.json
index 1b2274d22c7..99cc3664bef 100644
--- a/openapi-federation.json
+++ b/openapi-federation.json
@@ -125,7 +125,8 @@
"sip-dialout-enabled",
"can-enable-sip",
"start-without-media",
- "max-duration"
+ "max-duration",
+ "blur-virtual-background"
],
"properties": {
"enabled": {
@@ -171,6 +172,9 @@
"max-duration": {
"type": "integer",
"format": "int64"
+ },
+ "blur-virtual-background": {
+ "type": "boolean"
}
}
},
diff --git a/openapi-full.json b/openapi-full.json
index ee2f367ec0e..202b530c72d 100644
--- a/openapi-full.json
+++ b/openapi-full.json
@@ -301,7 +301,8 @@
"sip-dialout-enabled",
"can-enable-sip",
"start-without-media",
- "max-duration"
+ "max-duration",
+ "blur-virtual-background"
],
"properties": {
"enabled": {
@@ -347,6 +348,9 @@
"max-duration": {
"type": "integer",
"format": "int64"
+ },
+ "blur-virtual-background": {
+ "type": "boolean"
}
}
},
diff --git a/openapi.json b/openapi.json
index cdfc0dadfab..bccf2ab6a57 100644
--- a/openapi.json
+++ b/openapi.json
@@ -242,7 +242,8 @@
"sip-dialout-enabled",
"can-enable-sip",
"start-without-media",
- "max-duration"
+ "max-duration",
+ "blur-virtual-background"
],
"properties": {
"enabled": {
@@ -288,6 +289,9 @@
"max-duration": {
"type": "integer",
"format": "int64"
+ },
+ "blur-virtual-background": {
+ "type": "boolean"
}
}
},
diff --git a/src/__mocks__/capabilities.ts b/src/__mocks__/capabilities.ts
index 4064044190f..4a21c8c7f8d 100644
--- a/src/__mocks__/capabilities.ts
+++ b/src/__mocks__/capabilities.ts
@@ -119,6 +119,7 @@ export const mockedCapabilities: Capabilities = {
'can-enable-sip': true,
'start-without-media': false,
'max-duration': 0,
+ 'blur-virtual-background': false,
},
chat: {
'max-length': 32000,
@@ -151,6 +152,7 @@ export const mockedCapabilities: Capabilities = {
'predefined-backgrounds',
'can-upload-background',
'start-without-media',
+ 'blur-virtual-background',
],
chat: [
'read-privacy',
diff --git a/src/components/MediaSettings/MediaSettings.vue b/src/components/MediaSettings/MediaSettings.vue
index eb2fd8af0f9..f0f981279e0 100644
--- a/src/components/MediaSettings/MediaSettings.vue
+++ b/src/components/MediaSettings/MediaSettings.vue
@@ -93,6 +93,7 @@
@@ -321,6 +322,7 @@ export default {
isRecordingFromStart: false,
isPublicShareAuthSidebar: false,
isMirrored: false,
+ skipBlurVirtualBackground: false,
}
},
@@ -352,6 +354,10 @@ export default {
return this.settingsStore.getShowMediaSettings(this.token)
},
+ blurVirtualBackgroundEnabled() {
+ return this.settingsStore.blurVirtualBackgroundEnabled
+ },
+
showVideo() {
return this.videoPreviewAvailable && this.videoOn
},
@@ -423,6 +429,10 @@ export default {
return this.updatedBackground || this.audioDeviceStateChanged
|| this.videoDeviceStateChanged
},
+
+ connectionFailed() {
+ return this.$store.getters.connectionFailed(this.token)
+ },
},
watch: {
@@ -439,6 +449,9 @@ export default {
} else if (BrowserStorage.getItem('virtualBackgroundType_' + this.token) === VIRTUAL_BACKGROUND.BACKGROUND_TYPE.IMAGE) {
this.setVirtualBackgroundImage(BrowserStorage.getItem('virtualBackgroundUrl_' + this.token))
}
+ } else if (this.blurVirtualBackgroundEnabled && !this.skipBlurVirtualBackground) {
+ // Fall back to global blur background setting
+ this.blurVirtualBackground()
} else {
this.clearVirtualBackground()
}
@@ -464,6 +477,25 @@ export default {
isRecordingFromStart(value) {
this.setRecordingConsentGiven(value)
},
+
+ isInCall(value) {
+ if (value) {
+ const virtualBackgroundEnabled = BrowserStorage.getItem('virtualBackgroundEnabled_' + this.token) === 'true'
+ // Apply global blur background setting
+ if (this.blurVirtualBackgroundEnabled && !this.skipBlurVirtualBackground && !virtualBackgroundEnabled) {
+ this.blurBackground(true)
+ }
+ } else {
+ // Reset the flag for the next call
+ this.skipBlurVirtualBackground = false
+ }
+ },
+
+ connectionFailed(value) {
+ if (value) {
+ this.skipBlurVirtualBackground = false
+ }
+ },
},
beforeMount() {
@@ -554,10 +586,15 @@ export default {
},
handleUpdateBackground(background) {
+ // Default global blur background setting was changed by user
+ if (this.blurVirtualBackgroundEnabled && background !== 'blur') {
+ this.skipBlurVirtualBackground = true
+ }
+ // Apply the new background
if (background === 'none') {
this.clearBackground()
} else if (background === 'blur') {
- this.blurBackground()
+ this.blurBackground(this.blurVirtualBackgroundEnabled)
} else {
this.setBackgroundImage(background)
}
@@ -605,12 +642,15 @@ export default {
/**
* Blurs the background of the participants in current or future call
+ *
+ * @param {boolean} globalBlurVirtualBackground - Whether the global blur background setting is enabled (in Talk settings)
*/
- blurBackground() {
+ blurBackground(globalBlurVirtualBackground = false) {
if (this.isInCall) {
localMediaModel.enableVirtualBackground()
- localMediaModel.setVirtualBackgroundBlur(VIRTUAL_BACKGROUND.BLUR_STRENGTH.DEFAULT)
- } else {
+ localMediaModel.setVirtualBackgroundBlur(VIRTUAL_BACKGROUND.BLUR_STRENGTH.DEFAULT, globalBlurVirtualBackground)
+ } else if (!globalBlurVirtualBackground) {
+ this.skipBlurVirtualBackground = true
BrowserStorage.setItem('virtualBackgroundEnabled_' + this.token, 'true')
BrowserStorage.setItem('virtualBackgroundType_' + this.token, VIRTUAL_BACKGROUND.BACKGROUND_TYPE.BLUR)
BrowserStorage.setItem('virtualBackgroundBlurStrength_' + this.token, VIRTUAL_BACKGROUND.BLUR_STRENGTH.DEFAULT)
diff --git a/src/components/MediaSettings/VideoBackgroundEditor.vue b/src/components/MediaSettings/VideoBackgroundEditor.vue
index ec3db3e9f35..b6123e2e338 100644
--- a/src/components/MediaSettings/VideoBackgroundEditor.vue
+++ b/src/components/MediaSettings/VideoBackgroundEditor.vue
@@ -87,6 +87,7 @@ import { VIRTUAL_BACKGROUND } from '../../constants.js'
import BrowserStorage from '../../services/BrowserStorage.js'
import { getTalkConfig } from '../../services/CapabilitiesManager.ts'
import { getDavClient } from '../../services/DavClient.js'
+import { useSettingsStore } from '../../stores/settings.js'
import { findUniquePath } from '../../utils/fileUpload.js'
const predefinedBackgroundLabels = {
@@ -117,6 +118,11 @@ export default {
type: String,
required: true,
},
+
+ skipBlurVirtualBackground: {
+ type: Boolean,
+ default: false,
+ },
},
emits: ['update-background'],
@@ -125,6 +131,7 @@ export default {
return {
canUploadBackgrounds: getTalkConfig('local', 'call', 'can-upload-background'),
predefinedBackgrounds: getTalkConfig('local', 'call', 'predefined-backgrounds'),
+ settingsStore: useSettingsStore(),
}
},
@@ -263,6 +270,8 @@ export default {
} else {
this.selectedBackground = 'none'
}
+ } else if (this.settingsStore.blurVirtualBackgroundEnabled && !this.skipBlurVirtualBackground) {
+ this.selectedBackground = 'blur'
} else {
this.selectedBackground = 'none'
}
diff --git a/src/components/SettingsDialog/MediaDevicesPreview.vue b/src/components/SettingsDialog/MediaDevicesPreview.vue
index d672aa1b14b..f694253e3a9 100644
--- a/src/components/SettingsDialog/MediaDevicesPreview.vue
+++ b/src/components/SettingsDialog/MediaDevicesPreview.vue
@@ -63,6 +63,12 @@
disablePictureInPicture="true"
tabindex="-1" />
+
+ {{ t('spreed', 'Enable blur background by default for all conversation') }}
+
@@ -75,10 +81,17 @@ import VideoOff from 'vue-material-design-icons/VideoOff.vue'
import { t } from '@nextcloud/l10n'
+import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js'
+
import MediaDevicesSelector from '../MediaSettings/MediaDevicesSelector.vue'
import VolumeIndicator from '../UIShared/VolumeIndicator.vue'
import { useDevices } from '../../composables/useDevices.js'
+import { VIRTUAL_BACKGROUND } from '../../constants.js'
+import { getTalkConfig } from '../../services/CapabilitiesManager.ts'
+import { useSettingsStore } from '../../stores/settings.js'
+
+const supportDefaultBlurVirtualBackground = getTalkConfig('local', 'call', 'blur-virtual-background') !== undefined
export default {
@@ -88,6 +101,7 @@ export default {
AlertCircle,
MediaDevicesSelector,
MicrophoneOff,
+ NcCheckboxRadioSwitch,
VideoOff,
VolumeIndicator,
},
@@ -108,6 +122,7 @@ export default {
audioStreamError,
videoStream,
videoStreamError,
+ virtualBackground,
} = useDevices(video, true)
return {
@@ -125,6 +140,9 @@ export default {
audioStreamError,
videoStream,
videoStreamError,
+ settingsStore: useSettingsStore(),
+ virtualBackground,
+ supportDefaultBlurVirtualBackground,
}
},
@@ -180,6 +198,23 @@ export default {
return t('spreed', 'Error while accessing camera')
},
+
+ blurVirtualBackgroundEnabled() {
+ return this.settingsStore.blurVirtualBackgroundEnabled
+ },
+ },
+
+ mounted() {
+ if (this.blurVirtualBackgroundEnabled) {
+ // wait for the virtual background to be ready
+ this.$nextTick(() => {
+ this.virtualBackground.setEnabled(true)
+ this.virtualBackground.setVirtualBackground({
+ backgroundType: VIRTUAL_BACKGROUND.BACKGROUND_TYPE.BLUR,
+ blurValue: VIRTUAL_BACKGROUND.BLUR_STRENGTH.DEFAULT,
+ })
+ })
+ }
},
methods: {
@@ -194,6 +229,23 @@ export default {
this.videoInputId = videoInputId
this.updatePreferences('videoinput')
},
+
+ async setBlurVirtualBackgroundEnabled(value) {
+ try {
+ await this.settingsStore.setBlurVirtualBackgroundEnabled(value)
+ if (value) {
+ this.virtualBackground.setEnabled(true)
+ this.virtualBackground.setVirtualBackground({
+ backgroundType: VIRTUAL_BACKGROUND.BACKGROUND_TYPE.BLUR,
+ blurValue: VIRTUAL_BACKGROUND.BLUR_STRENGTH.DEFAULT,
+ })
+ } else {
+ this.virtualBackground.setEnabled(false)
+ }
+ } catch (error) {
+ console.error('Failed to set blur background enabled:', error)
+ }
+ },
},
}
diff --git a/src/services/settingsService.js b/src/services/settingsService.js
index 684e8a8babe..b0f92149f16 100644
--- a/src/services/settingsService.js
+++ b/src/services/settingsService.js
@@ -78,6 +78,10 @@ const setStartWithoutMedia = async function(value) {
await setUserConfig('spreed', 'calls_start_without_media', value ? 'yes' : 'no')
}
+const setBlurVirtualBackground = async function(value) {
+ await setUserConfig('spreed', 'blur_virtual_background', value ? 'yes' : 'no')
+}
+
/**
* Set user config using provisioning API
*
@@ -93,6 +97,7 @@ const setUserConfig = async function(appId, configKey, configValue) {
export {
setAttachmentFolder,
+ setBlurVirtualBackground,
setReadStatusPrivacy,
setTypingStatusPrivacy,
setSIPSettings,
diff --git a/src/stores/__tests__/settings.spec.js b/src/stores/__tests__/settings.spec.js
index baa9cbb8ba2..f0a2eee7c68 100644
--- a/src/stores/__tests__/settings.spec.js
+++ b/src/stores/__tests__/settings.spec.js
@@ -71,8 +71,9 @@ describe('settingsStore', () => {
// Assert
expect(results).toEqual([true, false])
// It's always called at least once : BrowserStorage.getItem('cachedConversations')
- // +1
- expect(BrowserStorage.getItem).toHaveBeenCalledTimes(1)
+ // Whenever capabilitiesManager.ts is imported
+ // +2
+ expect(BrowserStorage.getItem).toHaveBeenCalledTimes(2)
})
it('shows correct values received from BrowserStorage', () => {
@@ -89,11 +90,11 @@ describe('settingsStore', () => {
// Assert
expect(results).toEqual([true, true, false])
- // It's always called at least once : BrowserStorage.getItem('cachedConversations')
- expect(BrowserStorage.getItem).toHaveBeenCalledTimes(4) // 1 + 3
- expect(BrowserStorage.getItem).toHaveBeenNthCalledWith(2, 'showMediaSettings_token-1')
- expect(BrowserStorage.getItem).toHaveBeenNthCalledWith(3, 'showMediaSettings_token-2')
- expect(BrowserStorage.getItem).toHaveBeenNthCalledWith(4, 'showMediaSettings_token-3')
+ // It's always called at least once : BrowserStorage.getItem('cachedConversations') (+2)
+ expect(BrowserStorage.getItem).toHaveBeenCalledTimes(5) // 2 + 3
+ expect(BrowserStorage.getItem).toHaveBeenNthCalledWith(3, 'showMediaSettings_token-1')
+ expect(BrowserStorage.getItem).toHaveBeenNthCalledWith(4, 'showMediaSettings_token-2')
+ expect(BrowserStorage.getItem).toHaveBeenNthCalledWith(5, 'showMediaSettings_token-3')
})
it('updates values correctly', async () => {
@@ -109,8 +110,8 @@ describe('settingsStore', () => {
// Assert
expect(results).toEqual([false, true])
- // It's always called at least once : BrowserStorage.getItem('cachedConversations')
- expect(BrowserStorage.getItem).toHaveBeenCalledTimes(1)
+ // It's always called at least once : BrowserStorage.getItem('cachedConversations') (+2)
+ expect(BrowserStorage.getItem).toHaveBeenCalledTimes(2)
expect(BrowserStorage.setItem).toHaveBeenCalledTimes(2)
expect(BrowserStorage.setItem).toHaveBeenNthCalledWith(1, 'showMediaSettings_token-1', 'false')
expect(BrowserStorage.setItem).toHaveBeenNthCalledWith(2, 'showMediaSettings_token-2', 'true')
diff --git a/src/stores/settings.js b/src/stores/settings.js
index 5eb93f533ef..9c3e37aaf63 100644
--- a/src/stores/settings.js
+++ b/src/stores/settings.js
@@ -14,7 +14,8 @@ import { getTalkConfig } from '../services/CapabilitiesManager.ts'
import {
setReadStatusPrivacy,
setTypingStatusPrivacy,
- setStartWithoutMedia
+ setStartWithoutMedia,
+ setBlurVirtualBackground,
} from '../services/settingsService.js'
/**
@@ -40,6 +41,7 @@ export const useSettingsStore = defineStore('settings', {
typingStatusPrivacy: loadState('spreed', 'typing_privacy', PRIVACY.PRIVATE),
showMediaSettings: {},
startWithoutMedia: getTalkConfig('local', 'call', 'start-without-media'),
+ blurVirtualBackgroundEnabled: getTalkConfig('local', 'call', 'blur-virtual-background'),
}),
getters: {
@@ -103,6 +105,11 @@ export const useSettingsStore = defineStore('settings', {
Vue.set(this.showMediaSettings, token, value)
},
+ async setBlurVirtualBackgroundEnabled(value) {
+ await setBlurVirtualBackground(value)
+ this.blurVirtualBackgroundEnabled = value
+ },
+
async setStartWithoutMedia(value) {
await setStartWithoutMedia(value)
this.startWithoutMedia = value
diff --git a/src/types/openapi/openapi-administration.ts b/src/types/openapi/openapi-administration.ts
index e960be1a078..6a5c7e4be1f 100644
--- a/src/types/openapi/openapi-administration.ts
+++ b/src/types/openapi/openapi-administration.ts
@@ -231,6 +231,7 @@ export type components = {
"start-without-media": boolean;
/** Format: int64 */
"max-duration": number;
+ "blur-virtual-background": boolean;
};
chat: {
/** Format: int64 */
diff --git a/src/types/openapi/openapi-backend-recording.ts b/src/types/openapi/openapi-backend-recording.ts
index 63f3a3b8602..7d5ede90d3f 100644
--- a/src/types/openapi/openapi-backend-recording.ts
+++ b/src/types/openapi/openapi-backend-recording.ts
@@ -65,6 +65,7 @@ export type components = {
"start-without-media": boolean;
/** Format: int64 */
"max-duration": number;
+ "blur-virtual-background": boolean;
};
chat: {
/** Format: int64 */
diff --git a/src/types/openapi/openapi-backend-signaling.ts b/src/types/openapi/openapi-backend-signaling.ts
index 54bf7d5d98b..e632042a376 100644
--- a/src/types/openapi/openapi-backend-signaling.ts
+++ b/src/types/openapi/openapi-backend-signaling.ts
@@ -51,6 +51,7 @@ export type components = {
"start-without-media": boolean;
/** Format: int64 */
"max-duration": number;
+ "blur-virtual-background": boolean;
};
chat: {
/** Format: int64 */
diff --git a/src/types/openapi/openapi-backend-sipbridge.ts b/src/types/openapi/openapi-backend-sipbridge.ts
index 84e84856e36..040cd5a9ede 100644
--- a/src/types/openapi/openapi-backend-sipbridge.ts
+++ b/src/types/openapi/openapi-backend-sipbridge.ts
@@ -146,6 +146,7 @@ export type components = {
"start-without-media": boolean;
/** Format: int64 */
"max-duration": number;
+ "blur-virtual-background": boolean;
};
chat: {
/** Format: int64 */
diff --git a/src/types/openapi/openapi-bots.ts b/src/types/openapi/openapi-bots.ts
index 5e29b8e7795..5698171ec98 100644
--- a/src/types/openapi/openapi-bots.ts
+++ b/src/types/openapi/openapi-bots.ts
@@ -69,6 +69,7 @@ export type components = {
"start-without-media": boolean;
/** Format: int64 */
"max-duration": number;
+ "blur-virtual-background": boolean;
};
chat: {
/** Format: int64 */
diff --git a/src/types/openapi/openapi-federation.ts b/src/types/openapi/openapi-federation.ts
index b498f99f0f7..f03075498c0 100644
--- a/src/types/openapi/openapi-federation.ts
+++ b/src/types/openapi/openapi-federation.ts
@@ -177,6 +177,7 @@ export type components = {
"start-without-media": boolean;
/** Format: int64 */
"max-duration": number;
+ "blur-virtual-background": boolean;
};
chat: {
/** Format: int64 */
diff --git a/src/types/openapi/openapi-full.ts b/src/types/openapi/openapi-full.ts
index d097abeb12c..113cbf01f16 100644
--- a/src/types/openapi/openapi-full.ts
+++ b/src/types/openapi/openapi-full.ts
@@ -1927,6 +1927,7 @@ export type components = {
"start-without-media": boolean;
/** Format: int64 */
"max-duration": number;
+ "blur-virtual-background": boolean;
};
chat: {
/** Format: int64 */
diff --git a/src/types/openapi/openapi.ts b/src/types/openapi/openapi.ts
index 303985fa07d..49c8a6fe7fd 100644
--- a/src/types/openapi/openapi.ts
+++ b/src/types/openapi/openapi.ts
@@ -1424,6 +1424,7 @@ export type components = {
"start-without-media": boolean;
/** Format: int64 */
"max-duration": number;
+ "blur-virtual-background": boolean;
};
chat: {
/** Format: int64 */
diff --git a/src/utils/webrtc/models/LocalMediaModel.js b/src/utils/webrtc/models/LocalMediaModel.js
index c8121182164..00c1a756e99 100644
--- a/src/utils/webrtc/models/LocalMediaModel.js
+++ b/src/utils/webrtc/models/LocalMediaModel.js
@@ -387,7 +387,7 @@ LocalMediaModel.prototype = {
this._webRtc.enableVirtualBackground()
},
- setVirtualBackgroundBlur(blurStrength) {
+ setVirtualBackgroundBlur(blurStrength, globalBlurVirtualBackground = false) {
if (!this._webRtc) {
throw new Error('WebRtc not initialized yet')
}
@@ -396,9 +396,11 @@ LocalMediaModel.prototype = {
blurStrength = VIRTUAL_BACKGROUND.BLUR_STRENGTH.DEFAULT
}
- BrowserStorage.setItem('virtualBackgroundType_' + this.get('token'), VIRTUAL_BACKGROUND.BACKGROUND_TYPE.BLUR)
- BrowserStorage.setItem('virtualBackgroundBlurStrength_' + this.get('token'), blurStrength)
- BrowserStorage.removeItem('virtualBackgroundUrl_' + this.get('token'))
+ if (!globalBlurVirtualBackground) {
+ BrowserStorage.setItem('virtualBackgroundType_' + this.get('token'), VIRTUAL_BACKGROUND.BACKGROUND_TYPE.BLUR)
+ BrowserStorage.setItem('virtualBackgroundBlurStrength_' + this.get('token'), blurStrength)
+ BrowserStorage.removeItem('virtualBackgroundUrl_' + this.get('token'))
+ }
this._webRtc.setVirtualBackground({
backgroundType: VIRTUAL_BACKGROUND.BACKGROUND_TYPE.BLUR,
diff --git a/tests/php/CapabilitiesTest.php b/tests/php/CapabilitiesTest.php
index f18ab3d3c55..9569ec7f184 100644
--- a/tests/php/CapabilitiesTest.php
+++ b/tests/php/CapabilitiesTest.php
@@ -121,6 +121,7 @@ public function testGetCapabilitiesGuest(): void {
'can-enable-sip' => false,
'start-without-media' => false,
'max-duration' => 0,
+ 'blur-virtual-background' => false,
'predefined-backgrounds' => [
'1_office.jpg',
'2_home.jpg',
@@ -256,6 +257,7 @@ public function testGetCapabilitiesUserAllowed(bool $isNotAllowed, bool $canCrea
'can-enable-sip' => false,
'start-without-media' => false,
'max-duration' => 0,
+ 'blur-virtual-background' => false,
'predefined-backgrounds' => [
'1_office.jpg',
'2_home.jpg',