tmix — todo list ================ ## UAT checklist Run through this before any release / major refactor. ### Startup - [ ] App launches without crash when PA is running - [ ] App launches without crash when PA is NOT running (graceful fail) - [ ] Window title shows "TMix - Volume Control" (not "TMix - Volume Control - TMix") - [ ] Tray icon appears when DockInTray=true - [ ] Window hidden on launch when DockInTray=true - [ ] Window visible on launch when DockInTray=false ### Tabs / device population - [ ] Output tab shows all PA sinks (hardware outputs) - [ ] Input tab shows all PA sources (mics etc.) but NOT monitor sources - [ ] Playback tab shows per-app sink inputs; tmix-peak streams NOT shown - [ ] Recording tab shows per-app source outputs; tmix-peak streams NOT shown - [ ] Devices added/removed live without restart (plug/unplug USB audio, start/stop app) - [ ] Correct icon shown per device (headphone, microphone, digital, fallback) - [ ] Correct app icon shown for Playback streams (Amarok, Firefox, etc.) - [ ] Vertical label shows device/stream name ### Volume - [ ] Dragging volume slider changes PA volume in real time - [ ] Volume % label updates live while dragging - [ ] Scrolling on tray icon changes default output volume - [ ] Volume change from another app (pavucontrol) reflects in tmix slider + label - [ ] Volume clamped 0–100%, no overflow ### Mute - [ ] Green LED = unmuted, off = muted - [ ] Clicking LED toggles mute state in PA - [ ] Mute change from another app reflects in LED - [ ] Right-click "Mute" mutes; item shows "Muted" with checkmark when muted; "Unmute" when muted ### Balance knob (Output + Playback only) - [ ] Knob renders cleanly (antialiased, no flicker) - [ ] Dragging up increases right balance, dragging down increases left - [ ] Scroll wheel adjusts ±5 - [ ] Double-click resets to centre - [ ] PA channel volumes update correctly (left attenuated when right-heavy) - [ ] Balance change from pavucontrol reflects in knob - [ ] Input tab has NO balance knob ### Level meter - [ ] Output: meter responds to audio playback through that sink - [ ] Input: meter responds to microphone input - [ ] Playback: meter shows per-stream level (only that app's audio, not the whole sink) - [ ] Recording: no meter (acceptable; source output monitoring not implemented) - [ ] Meter decays smoothly; attack is fast, decay is slower - [ ] Meter shows 0 when muted or silent ### Default device - [ ] Radio button filled on the current PA default output - [ ] Radio button filled on the current PA default input - [ ] Clicking empty radio button sets that device as PA default - [ ] Default change from pavucontrol updates radio buttons in tmix - [ ] Only one radio button filled at a time per tab - [ ] Tray icon reflects default output volume/mute state ### Recording indicator - [ ] Red LED on Input widget is OFF when no app is recording from that source - [ ] Red LED turns ON when an app starts recording from that source - [ ] Red LED turns OFF when recording app stops - [ ] Second tray icon (microphone) appears when any input is active - [ ] Second tray icon disappears when all recording stops ### Right-click context menu - [ ] Right-click on any device widget shows context menu - [ ] Menu title shows device name - [ ] "Mute"/"Muted" item works (see Mute section) - [ ] Output: "Set as Default Output" present and functional - [ ] Input: "Set as Default Input" present and functional - [ ] Playback: "Move to Sink" section lists all available sinks - [ ] Current sink shown with checkmark in "Move to Sink" list - [ ] Selecting a different sink moves the stream - [ ] Output/Input: no "Move to Sink" section - [ ] Playback/Recording: no "Set as Default" item ### System tray - [ ] Volume icon shows muted/low/medium/high based on default output - [ ] Icon updates when volume changes (slider, scroll wheel, external) - [ ] Icon updates when mute state changes - [ ] Scroll wheel on tray raises/lowers default output volume - [ ] Left-click tray shows/hides main window - [ ] Right-click tray shows context menu with Quit (only one Quit entry) ### Window behaviour - [ ] Closing window hides to tray (DockInTray=true), does not quit - [ ] Closing window quits (DockInTray=false) - [ ] Session logout closes app cleanly (sessionSaving check) - [ ] File → Quit exits cleanly, no crash or double-free ### Stress / edge cases - [ ] Rapidly toggle mute — no crash, no stuck state - [ ] Rapidly drag slider — no crash, PA not flooded beyond responsiveness - [ ] Kill and restart PulseAudio while tmix is open — tmix recovers or fails gracefully - [ ] Open tmix with 0 devices on each tab — no crash, empty tabs look OK - [ ] Open tmix with 10+ playback streams — layout scrolls, no overlap ## Bugs / Polish - [x] Taskbar / dock icon missing - [x] Recording tray icon red dot not appearing - [x] Icons: app-specific icons for Firefox etc. - [x] Input devices always show microphone icon regardless of PA device name hint - [x] Right-click "Move to Sink": show checkmark on the sink the stream is currently on - [x] Right-click mute item: fixed label "Mute" with checkmark when muted - [x] Scroll area for 10+ devices — TQScrollView wrapping tab pages and flat strip; scroll bars appear only when content exceeds window width - [x] Window does not resize on card profile change (removed adjustSize()) - [x] Window position persists across restarts - [x] Single-instance enforcement — second launch raises/shows the existing window (KUniqueApplication) - [x] Settings dialog is non-blocking (modeless, false modal param in KDialogBase ctor) - [ ] Devices tab — sex it up vs pavucontrol-qt: - Port availability indicators (plugged/unplugged) with port-type icons (headphones, mic, HDMI, speaker, S/PDIF) from pa_card_port_info.type - availability_group handling: when a combo jack is detected (multiple ports share an availability_group), show a "What did you plug in?" prompt so the user can disambiguate headphones vs headset vs mic - Hide unavailable profiles by default (toggle to show all) ## Features ### Implemented - [x] Volume % label (live, updates on drag) - [x] Pan / balance slider per stereo device (reads + writes PA per-channel cvolume) - [x] Level meter — Output/Input via sink/source monitor; Playback via pa_stream_set_monitor_stream (per-stream) - [x] Slider tick marks every 5% - [x] Separator between devices - [x] Playback slider fix (was broken due to hardcoded 2-channel cvolume) - [x] Mute button: 3D toggle style - [x] App icons with multimedia fallback; amarok/TDE apps resolve via binary name - [x] tmix-peak streams hidden from Recording tab and pavucontrol (media.role=abstract) - [x] Menu bar — File: Quit, Settings: Configure TMix, Help: About TMix - [x] Per-device right-click context menu — mute (checkmark), set default, move to sink (checkmark on current) - [x] System tray (KSystemTray) — scroll wheel adjusts default sink volume, left-click popup/window toggle - [x] Tray icon — SmallIcon("kmix")/("audio-volume-medium") fallback; muted/low/medium/high states - [x] Tray popup (TmixPopup) — left-click, shows default output DeviceWidget + "Mixer" button, auto-dismiss on outside click, positions above/below tray, stays on top - [x] Recording tray icon — second KSystemTray icon when any input is active; tooltip lists names of active recording streams - [x] "Show all in one view" (no-tabs mode) — TQWidgetStack, rebuilds on toggle, live device add/remove works in both modes - [x] Show/hide individual tabs (Output, Input, Playback, Recording) via preferences - [x] Preferences dialog — modeless (non-blocking), OK+Apply+Cancel, General: dock in tray, popup on click, rec tray icon, confirm quit, scroll step View: no-tabs toggle, show/hide per tab - [x] Window auto-sizes to content (adjustSize on device add/remove), minimum 300×200 - [x] Bottom row fixed 30px height — all device widgets align regardless of content ### To do - [x] Devices tab — PA card profile switcher (dropdown per card, set active profile) - [ ] Switches tab (like KMix "Switches" view) Enumerate PA card profiles + ports (pa_context_get_card_info_list). Show as checkboxes/comboboxes: active profile, port retasking, IEC958 enable, Auto-Mute Mode, etc. May need ALSA fallback for raw HDA switches not surfaced by PulseAudio (snd-hda-intel ctl elements via alsa-lib). - [ ] Profiles / sources management tab List all PA sources and sinks with their active profile (e.g. "analog-stereo", "hdmi-stereo-extra1"). Allow switching profiles via dropdown. Show default sink/source with a star; click to set new default (pa_context_set_default_sink / pa_context_set_default_source). Subscribe to PA_SUBSCRIPTION_MASK_SERVER + CARD for live updates. - [x] Tray right-click: Configure, About, Quit (standard TDE style — no functional items) - [x] Remember window geometry across restarts ## Big Refactor — Backend Abstraction Goal: replace KMix entirely across all Trinity platforms (Linux PA/PW/ALSA, FreeBSD OSS, legacy systems). Each backend is self-contained end-to-end: its own model, its own widgets. The main window is a dumb shell. Architecture: AbstractBackend (minimal interface) - name() / open() / close() - createMixerWidget(parent) → TQWidget* - createDevicesWidget(parent)→ TQWidget* (null if not supported) PulseAudioBackend : AbstractBackend — current code, reorganised OSSBackend : AbstractBackend — flat sliders, no streams AlsaBackend : AbstractBackend — HDA controls, switches PipeWireBackend : AbstractBackend — routing graph if ever needed MixerWindow shrinks to: tray, menu, prefs, geometry, "host what backend gives me." Shared UI widgets (DeviceWidget, LevelMeter, BalanceKnob) become a toolkit backends may use or ignore — not a framework they're forced into. Backend selected at startup via config key "Backend" (default: pulseaudio). Build system conditionally compiles backends per platform. Why: the OSS→ALSA→PA retrofit history was painful. No backend should ever know about another; no generic UI code should check backend capabilities via flags. - [ ] DCOP interface (get/set volume, mute, list devices) - [ ] Horizontal layout mode — device strips laid out left-to-right instead of top-to-bottom; label above slider, level meter beside it. Toggle in View menu. - [ ] Current mixer selector — dropdown or sub-menu to switch between PulseAudio and raw ALSA hardware cards (like KMix "Current Mixer"). Each card gets its own tab set; PA is the default. Enumerate via pa_context_get_card_info_list for PA cards; snd_ctl_open for ALSA HDA cards. - [ ] Popup config options (Settings → General): Popup content: default output only (default) | all outputs | active playback streams Show level meter in popup: yes/no (saves vertical space) ## Settings / Polish (do later) - [ ] Settings dialog: switch from KDialogBase Tabbed to IconList style (like KMix) — big sidebar icons (General, View, etc.) with page content on the right. - [ ] Settings dialog: Defaults button, Help button - [ ] Settings dialog: grey out Apply until a change is actually made - [ ] Show/hide toggles for tickmarks, labels, level meters (View tab) - [ ] KMix-style classic tray widget — large tray area showing default sink volume slider directly in the panel (not a popup), like KMix's docked mixer strip. ## Distribution / Integration - [ ] .desktop file + icon - [ ] CMake install rules (bin, desktop, icon) - [ ] PipeWire-native backend (currently works via PW's PA compatibility layer) - [ ] Package as trinity-mixer