Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Ability to set video conf ringing/dialing volume #34926

Draft
wants to merge 11 commits into
base: develop
Choose a base branch
from
8 changes: 8 additions & 0 deletions .changeset/mean-numbers-chew.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@rocket.chat/meteor": minor
"@rocket.chat/i18n": patch
"@rocket.chat/rest-typings": patch
"@rocket.chat/ui-voip": patch
---

Enables control of video conference ringing and dialing sounds through the call ringer volume user preference, preventing video conf calls from always playing at maximum volume.
12 changes: 5 additions & 7 deletions apps/meteor/client/hooks/useUserSoundPreferences.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import { useUserPreference } from '@rocket.chat/ui-contexts';

const relativeVolume = (volume: number, masterVolume: number) => {
return (volume * masterVolume) / 100;
};
const relativeVolume = (volume: number, masterVolume: number) => (volume * masterVolume) / 100;

export const useUserSoundPreferences = () => {
const masterVolume = useUserPreference<number>('masterVolume', 100) || 100;
const notificationsSoundVolume = useUserPreference<number>('notificationsSoundVolume', 100) || 100;
const voipRingerVolume = useUserPreference<number>('voipRingerVolume', 100) || 100;
const masterVolume = useUserPreference<number>('masterVolume', 100) ?? 100;
const notificationsSoundVolume = useUserPreference<number>('notificationsSoundVolume', 100) ?? 100;
const callRingerVolume = useUserPreference<number>('callRingerVolume', 100) ?? 100;

return {
masterVolume,
notificationsSoundVolume: relativeVolume(notificationsSoundVolume, masterVolume),
voipRingerVolume: relativeVolume(voipRingerVolume, masterVolume),
callRingerVolume: relativeVolume(callRingerVolume, masterVolume),
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ type VoipSound = 'telephone' | 'outbound-call-ringing' | 'call-ended';

export const useVoipSounds = () => {
const { play, pause } = useCustomSound();
const { voipRingerVolume } = useUserSoundPreferences();
const { callRingerVolume } = useUserSoundPreferences();

return useMemo(
() => ({
play: (soundId: VoipSound, loop = true) => {
play(soundId, {
volume: Number((voipRingerVolume / 100).toPrecision(2)),
volume: Number((callRingerVolume / 100).toPrecision(2)),
loop,
});
},
Expand All @@ -23,6 +23,6 @@ export const useVoipSounds = () => {
pause('outbound-call-ringing');
},
}),
[play, pause, voipRingerVolume],
[play, pause, callRingerVolume],
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ const PreferencesSoundSection = () => {
const customSound = useCustomSound();
const soundsList: SelectOption[] = customSound?.getList()?.map((value) => [value._id, value.name]) || [];
const { control, watch } = useFormContext();
const { newMessageNotification, notificationsSoundVolume = 100, masterVolume = 100, voipRingerVolume = 100 } = watch();
const { newMessageNotification, notificationsSoundVolume = 100, masterVolume = 100, callRingerVolume = 100 } = watch();

const newRoomNotificationId = useUniqueId();
const newMessageNotificationId = useUniqueId();
const muteFocusedConversationsId = useUniqueId();
const masterVolumeId = useUniqueId();
const notificationsSoundVolumeId = useUniqueId();
const voipRingerVolumeId = useUniqueId();
const callRingerVolumeId = useUniqueId();

return (
<AccordionItem title={t('Sound')}>
Expand Down Expand Up @@ -71,23 +71,23 @@ const PreferencesSoundSection = () => {
</FieldRow>
</Field>
<Field>
<FieldLabel aria-describedby={`${voipRingerVolumeId}-hint`}>{t('Call_ringer_volume')}</FieldLabel>
<FieldHint id={`${voipRingerVolumeId}-hint`} mbe={4}>
<FieldLabel aria-describedby={`${callRingerVolumeId}-hint`}>{t('Call_ringer_volume')}</FieldLabel>
<FieldHint id={`${callRingerVolumeId}-hint`} mbe={4}>
{t('Call_ringer_volume_hint')}
</FieldHint>
<FieldRow>
<Controller
name='voipRingerVolume'
name='callRingerVolume'
control={control}
render={({ field: { onChange, value } }) => (
<Slider
aria-labelledby={voipRingerVolumeId}
aria-describedby={`${voipRingerVolumeId}-hint`}
aria-labelledby={callRingerVolumeId}
aria-describedby={`${callRingerVolumeId}-hint`}
value={value}
minValue={0}
maxValue={100}
onChange={(value: number) => {
const soundVolume = (voipRingerVolume * masterVolume) / 100;
const soundVolume = (callRingerVolume * masterVolume) / 100;
customSound.play('telephone', { volume: soundVolume / 100 });
onChange(value);
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export type AccountPreferencesData = {
sidebarGroupByType?: boolean;
masterVolume?: number;
notificationsSoundVolume?: number;
voipRingerVolume?: number;
callRingerVolume?: number;
};

export const useAccountPreferencesValues = (): AccountPreferencesData => {
Expand Down Expand Up @@ -75,7 +75,7 @@ export const useAccountPreferencesValues = (): AccountPreferencesData => {

const masterVolume = useUserPreference<number>('masterVolume', 100);
const notificationsSoundVolume = useUserPreference<number>('notificationsSoundVolume', 100);
const voipRingerVolume = useUserPreference<number>('voipRingerVolume', 100);
const callRingerVolume = useUserPreference<number>('callRingerVolume', 100);

return {
language,
Expand Down Expand Up @@ -106,6 +106,6 @@ export const useAccountPreferencesValues = (): AccountPreferencesData => {
muteFocusedConversations,
masterVolume,
notificationsSoundVolume,
voipRingerVolume,
callRingerVolume,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ import { useEffect, useMemo } from 'react';
import { FocusScope } from 'react-aria';

import VideoConfPopup from './VideoConfPopup';
import { useUserSoundPreferences } from '../../../../../hooks/useUserSoundPreferences';
import VideoConfPopupPortal from '../../../../../portals/VideoConfPopupPortal';

const VideoConfPopups = ({ children }: { children?: VideoConfPopupPayload }): ReactElement => {
const customSound = useCustomSound();
const incomingCalls = useVideoConfIncomingCalls();
const isRinging = useVideoConfIsRinging();
const isCalling = useVideoConfIsCalling();
const { callRingerVolume } = useUserSoundPreferences();

const popups = useMemo(
() =>
Expand All @@ -29,18 +31,18 @@ const VideoConfPopups = ({ children }: { children?: VideoConfPopupPayload }): Re

useEffect(() => {
if (isRinging) {
customSound.play('ringtone', { loop: true });
customSound.play('ringtone', { loop: true, volume: callRingerVolume / 100 });
}

if (isCalling) {
customSound.play('dialtone', { loop: true });
customSound.play('dialtone', { loop: true, volume: callRingerVolume / 100 });
}

return (): void => {
customSound.stop('ringtone');
customSound.stop('dialtone');
};
}, [customSound, isRinging, isCalling]);
}, [customSound, isRinging, isCalling, callRingerVolume]);

return (
<>
Expand Down
4 changes: 2 additions & 2 deletions apps/meteor/server/methods/saveUserPreferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type UserPreferences = {
unreadAlert: boolean;
masterVolume: number;
notificationsSoundVolume: number;
voipRingerVolume: number;
callRingerVolume: number;
desktopNotifications: string;
pushNotifications: string;
enableAutoAway: boolean;
Expand Down Expand Up @@ -101,7 +101,7 @@ export const saveUserPreferences = async (settings: Partial<UserPreferences>, us
unreadAlert: Match.Optional(Boolean),
masterVolume: Match.Optional(Number),
notificationsSoundVolume: Match.Optional(Number),
voipRingerVolume: Match.Optional(Number),
callRingerVolume: Match.Optional(Number),
desktopNotifications: Match.Optional(String),
pushNotifications: Match.Optional(String),
enableAutoAway: Match.Optional(Boolean),
Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/server/settings/accounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,7 @@ export const createAccountSettings = () =>
i18nLabel: 'Notification_volume',
});

await this.add('Accounts_Default_User_Preferences_voipRingerVolume', 100, {
await this.add('Accounts_Default_User_Preferences_callRingerVolume', 100, {
type: 'int',
public: true,
i18nLabel: 'Call_ringer_volume',
Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/tests/end-to-end/api/miscellaneous.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ describe('miscellaneous', () => {
'unreadAlert',
'masterVolume',
'notificationsSoundVolume',
'voipRingerVolume',
'callRingerVolume',
'omnichannelTranscriptEmail',
IS_EE ? 'omnichannelTranscriptPDF' : false,
'desktopNotifications',
Expand Down
2 changes: 1 addition & 1 deletion packages/i18n/src/locales/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -934,7 +934,7 @@
"Call_transfered_to__name__": "Call transfered to {{name}}",
"Call_terminated": "Call terminated",
"Call_ringer_volume": "Call ringer volume",
"Call_ringer_volume_hint": "For all incoming call notifications",
"Call_ringer_volume_hint": "For all incoming voice and video call notifications",
"Caller": "Caller",
"Caller_Id": "Caller ID",
"Camera_access_not_allowed": "Camera access was not allowed, please check your browser settings.",
Expand Down
2 changes: 1 addition & 1 deletion packages/i18n/src/locales/pt-BR.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,7 @@
"Call_transfered_to__name__": "Chamada transferida para {{name}}",
"Call_terminated": "Chamada encerrada",
"Call_ringer_volume": "Volume do toque de chamada",
"Call_ringer_volume_hint": "Para todas as notificações de chamadas recebidas",
"Call_ringer_volume_hint": "Para todas as notificações de chamadas de voz e vídeo recebidas",
"Caller": "Autor da chamada",
"Caller_Id": "ID do autor da chamada",
"Cancel": "Cancelar",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export type UsersSetPreferencesParamsPOST = {
unreadAlert?: boolean;
masterVolume?: number;
notificationsSoundVolume?: number;
voipRingerVolume?: number;
callRingerVolume?: number;
desktopNotifications?: string;
pushNotifications?: string;
enableAutoAway?: boolean;
Expand Down Expand Up @@ -120,7 +120,7 @@ const UsersSetPreferencesParamsPostSchema = {
type: 'number',
nullable: true,
},
voipRingerVolume: {
callRingerVolume: {
type: 'number',
nullable: true,
},
Expand Down
4 changes: 2 additions & 2 deletions packages/ui-voip/src/hooks/useVoipSounds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ type VoipSound = 'telephone' | 'outbound-call-ringing' | 'call-ended';
export const useVoipSounds = () => {
const { play, pause } = useCustomSound();
const masterVolume = useUserPreference<number>('masterVolume', 100) || 100;
const voipRingerVolume = useUserPreference<number>('voipRingerVolume', 100) || 100;
const audioVolume = Math.floor((voipRingerVolume * masterVolume) / 100);
const callRingerVolume = useUserPreference<number>('callRingerVolume', 100) || 100;
const audioVolume = Math.floor((callRingerVolume * masterVolume) / 100);

return useMemo(
() => ({
Expand Down
Loading