From 34d6a2fbac583a1b83c3d790dee13318cb02639d Mon Sep 17 00:00:00 2001 From: Nuwan Date: Thu, 19 Feb 2026 14:19:14 +0530 Subject: [PATCH] fix(ui): correct Volume modal to use category mixers for proper display - Use MonitorCatGroup category mixers with AudioInputMusic/AudioInputChat names instead of incorrect MasterGroup/MonitorGroup channel mixers - Add refresh on modal open to fetch fresh data from native client - Remove FTUESave call that was causing VU meters to stop working - Export getAudioInputCategoryMixer and getChatCategoryMixer from useMixerHelper Co-Authored-By: Claude Opus 4.5 --- .../components/client/JKSessionVolumeModal.js | 81 +++++++++++++------ jam-ui/src/hooks/useMixerHelper.js | 3 + 2 files changed, 61 insertions(+), 23 deletions(-) diff --git a/jam-ui/src/components/client/JKSessionVolumeModal.js b/jam-ui/src/components/client/JKSessionVolumeModal.js index 2f3e9ed43..546ecd333 100644 --- a/jam-ui/src/components/client/JKSessionVolumeModal.js +++ b/jam-ui/src/components/client/JKSessionVolumeModal.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect, useState, useCallback } from 'react'; import { Modal, ModalHeader, @@ -7,41 +7,76 @@ import { import SessionTrackVU from './SessionTrackVU'; import SessionTrackGain from './SessionTrackGain' import { useMixersContext } from '../../context/MixersContext'; -import { ChannelGroupIds } from '../../helpers/globals.js'; +import { useJamClient } from '../../context/JamClientContext'; +import { MIX_MODES, ChannelGroupIds, CategoryGroupIds } from '../../helpers/globals.js'; const JKSessionVolumeModal = ({ isOpen, toggle }) => { const mixerHelper = useMixersContext(); + const jamClient = useJamClient(); const mixers = mixerHelper.myTracks[0]?.mixers; - // Get the real backend mixers for volume controls (like web version) - const getMusicMixers = () => { - const allMixers = mixerHelper.mixers; - const mode = mixerHelper.mixMode; - const targetGroupId = mode === true ? ChannelGroupIds.MasterGroup : ChannelGroupIds.MonitorGroup; + // Local state for fresh mixer data from native client + const [musicMixer, setMusicMixer] = useState(null); + const [chatMixer, setChatMixer] = useState(null); - // Find the real mixer with correct volume values - for (const key in allMixers) { - if (allMixers[key] && allMixers[key].group_id === targetGroupId) { - return allMixers[key]; // Return the real mixer object - } + // Refresh mixer data from native client when modal opens + // This ensures we have the latest values, including changes made in legacy app + useEffect(() => { + if (isOpen && jamClient) { + const refreshMixers = async () => { + try { + // Get fresh mixer data from native client (PERSONAL mode for monitor output) + const freshMixers = await jamClient.SessionGetAllControlState(false); + + // Find music and chat category mixers from fresh data + // Category mixers are in MonitorCatGroup (group_id 3) with specific name properties + for (const mixer of freshMixers) { + if (mixer.group_id === ChannelGroupIds.MonitorCatGroup) { + if (mixer.name === CategoryGroupIds.AudioInputMusic) { + setMusicMixer(mixer); + } else if (mixer.name === CategoryGroupIds.AudioInputChat) { + setChatMixer(mixer); + } + } + } + } catch (error) { + console.warn('Failed to refresh mixer data:', error); + } + }; + refreshMixers(); + } + }, [isOpen, jamClient]); + + // Get music category mixer - prefer fresh data from state, fallback to context + const getMusicMixers = useCallback(() => { + if (musicMixer) { + return musicMixer; + } + // Fallback to context data + const categoryMixerResult = mixerHelper.getAudioInputCategoryMixer(MIX_MODES.PERSONAL); + if (categoryMixerResult && categoryMixerResult.mixer) { + return categoryMixerResult.mixer; } return null; - }; + }, [musicMixer, mixerHelper]); - const getChatMixers = () => { - const allMixers = mixerHelper.mixers; - const targetGroupId = ChannelGroupIds.AudioInputChatGroup; - - // Find the real chat mixer with correct volume values - for (const key in allMixers) { - if (allMixers[key] && allMixers[key].group_id === targetGroupId) { - return allMixers[key]; // Return the real mixer object - } + // Get chat category mixer - prefer fresh data from state, fallback to context + const getChatMixers = useCallback(() => { + if (chatMixer) { + return chatMixer; + } + // Fallback to context data + const categoryMixerResult = mixerHelper.getChatCategoryMixer(MIX_MODES.PERSONAL); + if (categoryMixerResult && categoryMixerResult.mixer) { + return categoryMixerResult.mixer; } return null; - }; + }, [chatMixer, mixerHelper]); const handleCancel = () => { + // Volume changes are applied immediately via setSessionMixerCategoryPlayoutState + // when the slider is moved, so no explicit save is needed here. + // Note: FTUESave was removed because it was causing VU meters to stop working. toggle(); }; diff --git a/jam-ui/src/hooks/useMixerHelper.js b/jam-ui/src/hooks/useMixerHelper.js index 652dff432..ccfa3d3da 100644 --- a/jam-ui/src/hooks/useMixerHelper.js +++ b/jam-ui/src/hooks/useMixerHelper.js @@ -999,6 +999,9 @@ const useMixerHelper = () => { faderChanged, initGain, setMixerPan, + // Category mixer functions for Volume modal + getAudioInputCategoryMixer, + getChatCategoryMixer, // Media arrays from mediaSlice backingTracks, jamTracks,