aethersdr / aethersdr/AetherSDR
M0 item 3 follow-up: the title-bar headphone slider is a second unconverted site for mixer headphone gain/mute
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 221
- Forks
- 117
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 299
Description
Follow-up to #5263 item 3, modelled on #5277: another unconverted site for
a command the milestone issue already names, filed as its own issue rather than
reopening the milestone.
Cited by file and symbol.
Duplicate check. All 455 open issues fetched paginated to exhaustion and
searched on headphone, hpVolume, hpSlider, setHeadphoneGain,
setHeadphoneMute and title-bar terms. The near neighbours are #5263 itself
(names the MIDI registry site, not this one), #4665 (the speaker button, a
different widget and a different defect), #5277 (the precedent), and #4722
(closed as completed — it fixed this control's routing and reconciliation,
not its capability gate). Nothing open covers the title-bar site.
What item 3 already covers
Item 3 names MIDI global.masterVolume / global.hpVolume — the
MainWindow_Controllers.cpp registry, reaching mixer lineout/headphone gain —
for the refuse-and-log gate, with the instruction:
"Do NOT reroute to client-side volume in M0: the Flex verbs drive the radio's
hardware outputs, and changing their meaning is a UX decision deferred to M4."
That is the right call and this follow-up does not touch it.
The site item 3 does not name
The title bar reaches the same two commands by a different path, with no
capability gate:
TitleBar::headphoneVolumeChanged -> RadioModel::setHeadphoneGain
-> sendCmd("mixer headphone gain %1")
TitleBar::headphoneMuteChanged -> RadioModel::setHeadphoneMute
-> sendCmd("mixer headphone mute %1")
Both connects live in MainWindow.cpp beside the applyMasterVolume connect,
with an audioOutputChanged reconciler immediately after them.
#4722 already fixed what it could here — those connects go straight to the
model setters rather than hand-writing wire text, and the reconciler drives both
setHeadphoneVolume and setHeadphoneMuted from radio status. That closed the
Principle II half properly and this issue does not reopen it. What #4722 did not
touch, and could not, is whether the control should be live on a radio that has
no such hardware.
On a backend with no Flex command plane both commands hit RadioModel::sendCmd's
hasCommandPlane() gate. Since M0 item 1 landed that is at least loud —
qCWarning(lcProtocol), commandDropped, kNoCommandPlaneCode, and a one-shot
status-bar notice per connect session. But the control still moves, still
persists a UI position, and still changes nothing the operator can hear.
The Hermes-Lite 2 case is the strong one: it has no headphone jack and no audio
output at all. Its receive audio arrives over Ethernet and the host plays it.
There is no hardware for the command to reach, so there is nothing this control
could ever do on that radio.
Proposed change, per the binding doctrine
Doctrine from #5262, quoted in #5263: "controls are never hidden per radio —
three states (dimmed/unavailable, greyed/inactive, colored/active); hiding only
at applet granularity." So:
- Dim, do not hide.
m_hpSlider,m_headphoneBtnandm_hpLabelin
TitleBar, using M0's "existing disabled-with-reason-tooltip pattern (the
ATU/MEM precedent)". - Gate on the established predicate —
usesFlexCommandPlane(), per item 3's
own note that M2/M4 later replace the predicate rather than the gate. - Mirror the disabled reason in
accessibleDescription, per item 3's accept
criterion anddocs/a11y.md. - No wire text to remove. Noted only so a reviewer does not go looking for
the hand-writtensendCommandthat #4665's speaker button still has —
#4722 already took it out of this path.
A hiding mechanism already exists in this widget — TitleBar::setMinimalMode
sets m_headphoneBtn, m_hpSlider and m_hpLabel invisible together — and is
deliberately not reused: it is a layout mode, not a capability gate, and
hiding is what the doctrine forbids.
Out of scope, deliberately
Labelling whose output each control is — an operator's proposal, in their
words: "the headphone slider should indicate it is the rig's output not the
computer."
It is a better fix than dimming alone, because it is not an HL2 problem: on a
Flex both sliders are real and the operator still cannot tell which is which. The
accessible names are "Master volume" and "Headphone volume", the descriptions
"Line out volume level, 0 to 100 percent" and "Headphone volume level, 0 to 100
percent", and neither says whose output it is.
But it is a UX change to a Flex-visible control, and #5263 defers exactly that
class to M4. Raised so a maintainer can pull it forward if they disagree, not
proposed as part of this. If it does land, it should land before the dimming
rather than after: a dimmed control that does not say whose output it is reads as
broken rather than as unavailable.
Acceptance
- On HL2/Icom the headphone slider, mute button and label are visibly dimmed with
a reason;accessibleDescriptioncarries it. - On Flex, behaviour and appearance unchanged.
- A test pins the gate both ways, following item 3's accept pattern.
Not verified
Whether Icom's backend has a headphone mixer. The HL2 case is established from
source and from a running application; the Icom case is assumed from
usesFlexCommandPlane() and has not been checked. Nothing about Flex hardware
was tested here — the Flex statements above are read from source and from #4665's
thread.
Part of #5262 (M0 item 3).
🤖 Generated with Claude Code
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in MainWindow.cpp at the TitleBar headphoneVolumeChanged and headphoneMuteChanged connections, then inspect TitleBar and the existing ATU/MEM disabled-with-reason-tooltip pattern. Check usesFlexCommandPlane() and docs/a11y.md before adding the gate and accessible description. Add or update a TitleBar test to cover both predicate states; done means the controls are dimmed with a reason on HL2/Icom and unchanged on Flex.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- accessibility, desktop, testing
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 72/100