From 0c331a05ad9baebbfcb1d426fe30ad88cd9a02c4 Mon Sep 17 00:00:00 2001 From: Half-Shot Date: Tue, 3 Dec 2024 14:40:43 +0000 Subject: [PATCH] Integrate raise hand sound into call event renderer. --- src/room/CallEventAudioRenderer.test.tsx | 20 ++++++------- src/room/CallEventAudioRenderer.tsx | 22 ++++++++++++++- src/room/InCallView.tsx | 36 +----------------------- 3 files changed, 32 insertions(+), 46 deletions(-) diff --git a/src/room/CallEventAudioRenderer.test.tsx b/src/room/CallEventAudioRenderer.test.tsx index 9014e60b..21d94a54 100644 --- a/src/room/CallEventAudioRenderer.test.tsx +++ b/src/room/CallEventAudioRenderer.test.tsx @@ -51,7 +51,14 @@ afterEach(() => { window.HTMLMediaElement.prototype.play = originalPlayFn; }); -test("plays a sound when entering a call", () => { +/** + * We don't want to play a sound when loading the call state + * because typically this occurs in two stages. We first join + * the call as a local participant and *then* the remote + * participants join from our perspective. We don't want to make + * a noise every time. + */ +test("does NOT play a sound when entering a call", () => { const audioIsPlaying: string[] = mockMediaPlay(); const members = new Map([alice, bob].map((p) => [p.userId, p])); const remoteParticipants = of([aliceParticipant]); @@ -75,10 +82,7 @@ test("plays a sound when entering a call", () => { ); render(); - expect(audioIsPlaying).toEqual([ - // Joining the call - enterSound, - ]); + expect(audioIsPlaying).toHaveLength(0); }); test("plays no sound when muted", () => { @@ -141,8 +145,6 @@ test("plays a sound when a user joins", () => { }); // Play a sound when joining a call. expect(audioIsPlaying).toEqual([ - // Joining the call - enterSound, // Bob leaves enterSound, ]); @@ -178,14 +180,12 @@ test("plays a sound when a user leaves", () => { liveKitRoom.removeParticipant(aliceParticipant); }); expect(audioIsPlaying).toEqual([ - // Joining the call - enterSound, // Alice leaves leaveSound, ]); }); -test("plays no sound when the participant list", () => { +test("plays no sound when the participant list is more than the maximum size", () => { const audioIsPlaying: string[] = mockMediaPlay(); const members = new Map([alice].map((p) => [p.userId, p])); const remoteParticipants = new Map([ diff --git a/src/room/CallEventAudioRenderer.tsx b/src/room/CallEventAudioRenderer.tsx index 21e667e3..d95b8574 100644 --- a/src/room/CallEventAudioRenderer.tsx +++ b/src/room/CallEventAudioRenderer.tsx @@ -5,14 +5,17 @@ SPDX-License-Identifier: AGPL-3.0-only Please see LICENSE in the repository root for full details. */ -import { ReactNode, useEffect } from "react"; +import { ReactNode, useDeferredValue, useEffect, useMemo } from "react"; import { debounce, filter, interval, throttle } from "rxjs"; import { CallViewModel } from "../state/CallViewModel"; import joinCallSoundMp3 from "../sound/join_call.mp3"; import joinCallSoundOgg from "../sound/join_call.ogg"; import leftCallSoundMp3 from "../sound/left_call.mp3"; import leftCallSoundOgg from "../sound/left_call.ogg"; +import handSoundOgg from "../sound/raise_hand.ogg?url"; +import handSoundMp3 from "../sound/raise_hand.mp3?url"; import { prefetchSounds, useAudioContext } from "../useAudioContext"; +import { useReactions } from "../useReactions"; // Do not play any sounds if the participant count has exceeded this // number. @@ -29,6 +32,10 @@ const Sounds = prefetchSounds({ mp3: leftCallSoundMp3, ogg: leftCallSoundOgg, }, + raiseHand: { + mp3: handSoundMp3, + ogg: handSoundOgg, + }, }); export function CallEventAudioRenderer({ @@ -41,6 +48,19 @@ export function CallEventAudioRenderer({ latencyHint: "interactive", }); + const { raisedHands } = useReactions(); + const raisedHandCount = useMemo( + () => Object.keys(raisedHands).length, + [raisedHands], + ); + const previousRaisedHandCount = useDeferredValue(raisedHandCount); + + useEffect(() => { + if (audioEngineCtx && previousRaisedHandCount < raisedHandCount) { + audioEngineCtx.playSound("raiseHand"); + } + }, [audioEngineCtx, previousRaisedHandCount, raisedHandCount]); + useEffect(() => { if (!audioEngineCtx) { return; diff --git a/src/room/InCallView.tsx b/src/room/InCallView.tsx index f1afa3e4..2586182f 100644 --- a/src/room/InCallView.tsx +++ b/src/room/InCallView.tsx @@ -19,7 +19,6 @@ import { TouchEvent, forwardRef, useCallback, - useDeferredValue, useEffect, useMemo, useRef, @@ -81,11 +80,8 @@ import { makeSpotlightLandscapeLayout } from "../grid/SpotlightLandscapeLayout"; import { makeSpotlightPortraitLayout } from "../grid/SpotlightPortraitLayout"; import { GridTileViewModel, TileViewModel } from "../state/TileViewModel"; import { ReactionsProvider, useReactions } from "../useReactions"; -import handSoundOgg from "../sound/raise_hand.ogg?url"; -import handSoundMp3 from "../sound/raise_hand.mp3?url"; import { ReactionsAudioRenderer } from "./ReactionAudioRenderer"; import { useSwitchCamera } from "./useSwitchCamera"; -import { soundEffectVolumeSetting, useSetting } from "../settings/settings"; import { ReactionsOverlay } from "./ReactionsOverlay"; import { CallEventAudioRenderer } from "./CallEventAudioRenderer"; @@ -183,14 +179,7 @@ export const InCallView: FC = ({ connState, onShareClick, }) => { - const [soundEffectVolume] = useSetting(soundEffectVolumeSetting); - const { supportsReactions, raisedHands, sendReaction, toggleRaisedHand } = - useReactions(); - const raisedHandCount = useMemo( - () => Object.keys(raisedHands).length, - [raisedHands], - ); - const previousRaisedHandCount = useDeferredValue(raisedHandCount); + const { supportsReactions, sendReaction, toggleRaisedHand } = useReactions(); useWakeLock(); @@ -340,25 +329,6 @@ export const InCallView: FC = ({ [vm], ); - // Play a sound when the raised hand count increases. - const handRaisePlayer = useRef(null); - useEffect(() => { - if (!handRaisePlayer.current) { - return; - } - if (previousRaisedHandCount < raisedHandCount) { - handRaisePlayer.current.volume = soundEffectVolume; - handRaisePlayer.current.play().catch((ex) => { - logger.warn("Failed to play raise hand sound", ex); - }); - } - }, [ - raisedHandCount, - handRaisePlayer, - previousRaisedHandCount, - soundEffectVolume, - ]); - useEffect(() => { widget?.api.transport .send( @@ -672,10 +642,6 @@ export const InCallView: FC = ({ {renderContent()} - {footer}