From 7d09226df3fe38a76407ed63f3b875135b3ec44d Mon Sep 17 00:00:00 2001 From: Misha Behei <67476711+behei-vonage@users.noreply.github.com> Date: Thu, 20 Feb 2025 14:53:40 -0600 Subject: [PATCH 1/7] VIDCS-3392: BG blur state is not saved for the waiting room (#70) --- .../usePreviewPublisher.spec.tsx | 46 ++++++++++++++++--- .../usePreviewPublisher.tsx | 43 ++++++++++++----- 2 files changed, 70 insertions(+), 19 deletions(-) diff --git a/frontend/src/Context/PreviewPublisherProvider/usePreviewPublisher/usePreviewPublisher.spec.tsx b/frontend/src/Context/PreviewPublisherProvider/usePreviewPublisher/usePreviewPublisher.spec.tsx index 343d44ba..32c12340 100644 --- a/frontend/src/Context/PreviewPublisherProvider/usePreviewPublisher/usePreviewPublisher.spec.tsx +++ b/frontend/src/Context/PreviewPublisherProvider/usePreviewPublisher/usePreviewPublisher.spec.tsx @@ -1,6 +1,6 @@ import { act, cleanup, renderHook } from '@testing-library/react'; import { afterAll, afterEach, beforeEach, describe, expect, it, Mock, vi } from 'vitest'; -import { initPublisher, Publisher } from '@vonage/client-sdk-video'; +import { hasMediaProcessorSupport, initPublisher, Publisher } from '@vonage/client-sdk-video'; import EventEmitter from 'events'; import usePreviewPublisher from './usePreviewPublisher'; import { UserContextType } from '../../user'; @@ -19,7 +19,6 @@ vi.mock('@vonage/client-sdk-video'); vi.mock('../../../hooks/useUserContext.tsx'); vi.mock('../../../hooks/usePermissions.tsx'); vi.mock('../../../hooks/useDevices.tsx'); - const mockUseUserContext = useUserContext as Mock<[], UserContextType>; const mockUsePermissions = usePermissions as Mock<[], PermissionsHookType>; const mockUseDevices = useDevices as Mock< @@ -31,7 +30,7 @@ const defaultSettings = { publishAudio: false, publishVideo: false, name: '', - blur: false, + blur: true, noiseSuppression: true, }; const mockUserContextWithDefaultSettings = { @@ -46,14 +45,15 @@ describe('usePreviewPublisher', () => { getVideoSource: () => defaultVideoDevice, }) as unknown as Publisher; const mockedInitPublisher = vi.fn(); + const mockedHasMediaProcessorSupport = vi.fn(); const consoleErrorSpy = vi.spyOn(console, 'error'); const mockSetAccessStatus = vi.fn(); beforeEach(() => { vi.resetAllMocks(); - mockUseUserContext.mockImplementation(() => mockUserContextWithDefaultSettings); (initPublisher as Mock).mockImplementation(mockedInitPublisher); + (hasMediaProcessorSupport as Mock).mockImplementation(mockedHasMediaProcessorSupport); mockUseDevices.mockReturnValue({ getAllMediaDevices: vi.fn(), allMediaDevices, @@ -71,7 +71,6 @@ describe('usePreviewPublisher', () => { describe('initLocalPublisher', () => { it('should call initPublisher', () => { mockedInitPublisher.mockReturnValue(mockPublisher); - (initPublisher as Mock).mockImplementation(mockedInitPublisher); const { result } = renderHook(() => usePreviewPublisher()); result.current.initLocalPublisher(); @@ -93,6 +92,41 @@ describe('usePreviewPublisher', () => { }); expect(consoleErrorSpy).toHaveBeenCalledWith('initPublisher error: ', error); }); + + it('should apply background blur when initialized if set to true', () => { + mockedHasMediaProcessorSupport.mockReturnValue(true); + mockedInitPublisher.mockReturnValue(mockPublisher); + const { result } = renderHook(() => usePreviewPublisher()); + act(() => { + result.current.initLocalPublisher(); + }); + expect(mockedInitPublisher).toHaveBeenCalledWith( + undefined, + expect.objectContaining({ + videoFilter: expect.objectContaining({ + type: 'backgroundBlur', + blurStrength: 'high', + }), + }), + expect.any(Function) + ); + }); + + it('should not apply background blur when initialized if the device does not support it', () => { + mockedHasMediaProcessorSupport.mockReturnValue(false); + mockedInitPublisher.mockReturnValue(mockPublisher); + const { result } = renderHook(() => usePreviewPublisher()); + act(() => { + result.current.initLocalPublisher(); + }); + expect(mockedInitPublisher).toHaveBeenCalledWith( + undefined, + expect.objectContaining({ + videoFilter: undefined, + }), + expect.any(Function) + ); + }); }); describe('on accessDenied', () => { @@ -130,7 +164,6 @@ describe('usePreviewPublisher', () => { it('handles permission denial', async () => { mockedInitPublisher.mockReturnValue(mockPublisher); - (initPublisher as Mock).mockImplementation(mockedInitPublisher); const { result } = renderHook(() => usePreviewPublisher()); @@ -149,7 +182,6 @@ describe('usePreviewPublisher', () => { throw new Error('Whoops'); }); mockedInitPublisher.mockReturnValue(mockPublisher); - (initPublisher as Mock).mockImplementation(mockedInitPublisher); const { result } = renderHook(() => usePreviewPublisher()); diff --git a/frontend/src/Context/PreviewPublisherProvider/usePreviewPublisher/usePreviewPublisher.tsx b/frontend/src/Context/PreviewPublisherProvider/usePreviewPublisher/usePreviewPublisher.tsx index f8213769..11cd0afa 100644 --- a/frontend/src/Context/PreviewPublisherProvider/usePreviewPublisher/usePreviewPublisher.tsx +++ b/frontend/src/Context/PreviewPublisherProvider/usePreviewPublisher/usePreviewPublisher.tsx @@ -1,5 +1,12 @@ import { useState, useRef, useCallback, useEffect } from 'react'; -import { Publisher, Event, initPublisher } from '@vonage/client-sdk-video'; +import { + Publisher, + Event, + initPublisher, + VideoFilter, + hasMediaProcessorSupport, + PublisherProperties, +} from '@vonage/client-sdk-video'; import setMediaDevices from '../../../utils/mediaDeviceUtils'; import useDevices from '../../../hooks/useDevices'; import usePermissions from '../../../hooks/usePermissions'; @@ -47,7 +54,7 @@ export type PreviewPublisherContextType = { * @returns {PreviewPublisherContextType} preview context */ const usePreviewPublisher = (): PreviewPublisherContextType => { - const { setUser } = useUserContext(); + const { setUser, user } = useUserContext(); const { allMediaDevices, getAllMediaDevices } = useDevices(); const [publisherVideoElement, setPublisherVideoElement] = useState< HTMLVideoElement | HTMLObjectElement @@ -56,7 +63,8 @@ const usePreviewPublisher = (): PreviewPublisherContextType => { const { setAccessStatus, accessStatus } = usePermissions(); const publisherRef = useRef(null); const [isPublishing, setIsPublishing] = useState(false); - const [localBlur, setLocalBlur] = useState(false); + const initialLocalBlurRef = useRef(user.defaultSettings.blur); + const [localBlur, setLocalBlur] = useState(user.defaultSettings.blur); const [isVideoEnabled, setIsVideoEnabled] = useState(true); const [isAudioEnabled, setIsAudioEnabled] = useState(true); const [localVideoSource, setLocalVideoSource] = useState(undefined); @@ -88,6 +96,7 @@ const usePreviewPublisher = (): PreviewPublisherContextType => { }); } setLocalBlur(!localBlur); + window.localStorage.setItem('backgroundBlur', JSON.stringify(!localBlur)); if (setUser) { setUser((prevUser: UserType) => ({ ...prevUser, @@ -211,18 +220,28 @@ const usePreviewPublisher = (): PreviewPublisherContextType => { return; } - publisherRef.current = initPublisher( - undefined, - { insertDefaultUI: false, resolution: '1280x720' }, - (err: unknown) => { - if (err instanceof Error) { - publisherRef.current = null; - if (err.name === 'OT_USER_MEDIA_ACCESS_DENIED') { - console.error('initPublisher error: ', err); + const videoFilter: VideoFilter | undefined = + initialLocalBlurRef.current && hasMediaProcessorSupport() + ? { + type: 'backgroundBlur', + blurStrength: 'high', } + : undefined; + + const publisherOptions: PublisherProperties = { + insertDefaultUI: false, + videoFilter, + resolution: '1280x720', + }; + + publisherRef.current = initPublisher(undefined, publisherOptions, (err: unknown) => { + if (err instanceof Error) { + publisherRef.current = null; + if (err.name === 'OT_USER_MEDIA_ACCESS_DENIED') { + console.error('initPublisher error: ', err); } } - ); + }); addPublisherListeners(publisherRef.current); }, [addPublisherListeners]); From a258ccb0f013b0107f13e72228cfee76d7ba5062 Mon Sep 17 00:00:00 2001 From: Misha Behei Date: Thu, 20 Feb 2025 16:36:16 -0600 Subject: [PATCH 2/7] lets try this --- .github/workflows/auto-set-base.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/auto-set-base.yml b/.github/workflows/auto-set-base.yml index 2ed821ac..8a7a9b80 100644 --- a/.github/workflows/auto-set-base.yml +++ b/.github/workflows/auto-set-base.yml @@ -16,7 +16,18 @@ jobs: - name: Checkout Repository uses: actions/checkout@v3 + - name: Check for "release-candidate" label + id: check-release-candidate + uses: actions/github-script@v6 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + script: | + const pr = context.payload.pull_request; + const labels = pr.labels.map(label => label.name); + return labels.includes("release-candidate"); + - name: Check and Update Base Branch + if: steps.check-release-candidate.outputs.result == 'false' env: TARGET_BRANCH: ${{ github.event.pull_request.base.ref }} BASE_BRANCH: ${{ github.event.pull_request.head.ref }} From 54cca83e66b8aa891e2a489779e08c4e123562c0 Mon Sep 17 00:00:00 2001 From: Misha Behei Date: Thu, 20 Feb 2025 16:36:49 -0600 Subject: [PATCH 3/7] labeled --- .github/workflows/auto-set-base.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/auto-set-base.yml b/.github/workflows/auto-set-base.yml index 8a7a9b80..71c56343 100644 --- a/.github/workflows/auto-set-base.yml +++ b/.github/workflows/auto-set-base.yml @@ -2,7 +2,7 @@ name: Auto-set Base Branch to Develop on: pull_request: - types: [opened] + types: [opened, labeled] permissions: contents: read From 76ffd940c46134517a93b39a14b9e1a1616fa5fa Mon Sep 17 00:00:00 2001 From: Misha Behei Date: Fri, 21 Feb 2025 10:13:34 -0600 Subject: [PATCH 4/7] sure lets do this --- .github/workflows/auto-set-base.yml | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/.github/workflows/auto-set-base.yml b/.github/workflows/auto-set-base.yml index 71c56343..bcd95253 100644 --- a/.github/workflows/auto-set-base.yml +++ b/.github/workflows/auto-set-base.yml @@ -16,25 +16,14 @@ jobs: - name: Checkout Repository uses: actions/checkout@v3 - - name: Check for "release-candidate" label - id: check-release-candidate - uses: actions/github-script@v6 - with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - script: | - const pr = context.payload.pull_request; - const labels = pr.labels.map(label => label.name); - return labels.includes("release-candidate"); - - name: Check and Update Base Branch - if: steps.check-release-candidate.outputs.result == 'false' env: TARGET_BRANCH: ${{ github.event.pull_request.base.ref }} BASE_BRANCH: ${{ github.event.pull_request.head.ref }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PR_NUMBER: ${{ github.event.pull_request.number }} run: | - if [ "$TARGET_BRANCH" = "main" ] && [ "$BASE_BRANCH" != "develop" ]; then + if [ "$TARGET_BRANCH" = "main" ] && [ "$BASE_BRANCH" != "develop" ] && [ "$BASE_BRANCH" != rc-* ]; then echo "Switching base branch from $TARGET_BRANCH to develop..." gh pr edit "$PR_NUMBER" --base "develop" echo "Base branch updated to 'develop'." From 05ccdee7feacd9ce8eed06928018c36d2e735d6f Mon Sep 17 00:00:00 2001 From: Misha Behei Date: Fri, 21 Feb 2025 10:15:01 -0600 Subject: [PATCH 5/7] test --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7f9ccfdb..0215151b 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ -# Vonage Video API Reference App for React +### Vonage Video API Reference App for React ## Table of Contents +- [Vonage Video API Reference App for React](#vonage-video-api-reference-app-for-react) - [Table of Contents](#table-of-contents) - [What is it?](#what-is-it) - [Why use it?](#why-use-it) From 90c01fb316333a9bfd4c2b5af63bd2fb0e343e10 Mon Sep 17 00:00:00 2001 From: Misha Behei Date: Fri, 21 Feb 2025 10:33:14 -0600 Subject: [PATCH 6/7] try on here --- .github/workflows/auto-set-base.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/auto-set-base.yml b/.github/workflows/auto-set-base.yml index bcd95253..cd79c566 100644 --- a/.github/workflows/auto-set-base.yml +++ b/.github/workflows/auto-set-base.yml @@ -23,7 +23,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PR_NUMBER: ${{ github.event.pull_request.number }} run: | - if [ "$TARGET_BRANCH" = "main" ] && [ "$BASE_BRANCH" != "develop" ] && [ "$BASE_BRANCH" != rc-* ]; then + if [ "$TARGET_BRANCH" = "main" ] && [ "$BASE_BRANCH" != "develop" ] && [ "$BASE_BRANCH" != "rc-*" ]; then echo "Switching base branch from $TARGET_BRANCH to develop..." gh pr edit "$PR_NUMBER" --base "develop" echo "Base branch updated to 'develop'." From 151424abac494d472d0b2f5e0de019b0ec38269d Mon Sep 17 00:00:00 2001 From: Misha Behei Date: Fri, 21 Feb 2025 10:55:48 -0600 Subject: [PATCH 7/7] try this --- .github/workflows/auto-set-base.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/auto-set-base.yml b/.github/workflows/auto-set-base.yml index cd79c566..becf2ea8 100644 --- a/.github/workflows/auto-set-base.yml +++ b/.github/workflows/auto-set-base.yml @@ -23,7 +23,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PR_NUMBER: ${{ github.event.pull_request.number }} run: | - if [ "$TARGET_BRANCH" = "main" ] && [ "$BASE_BRANCH" != "develop" ] && [ "$BASE_BRANCH" != "rc-*" ]; then + if [[ "$TARGET_BRANCH" == "main" && "$BASE_BRANCH" != "develop" && ! "$BASE_BRANCH" == rc-* ]]; then echo "Switching base branch from $TARGET_BRANCH to develop..." gh pr edit "$PR_NUMBER" --base "develop" echo "Base branch updated to 'develop'."