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}