Skip to content
Snippets Groups Projects
Commit a801b78f authored by dx's avatar dx Committed by moon2
Browse files

Headphone detection override state in audio settings

Audio settings in the headphones section now has a "jack detection"
on/off setting that when set to off shows a "headphone state" setting.
If jack detection is off and headphone state is on, headphones will be
assumed to be connected. If headphone state is off, headphones will be
assumed to be disconnected.

On the backend, this uses the existing but almost unused API
audio.headphones_detection_override(). This API is extended to take a
second optional parameter for the desired state (default True to keep
the previous behavior)

For UI clarity/space reasons, audio settings refers to jack detection
being on or off which is the opposite of override being on or off.
Jack detection on means override off.

The main motivation for this change is to allow the user to record audio
through the headset mic (which, unlike line in, can receive power from
TRRS) but still output sound through the internal speaker. So connecting
a TRRS lavalier mic to headset out doesn't result in losing sound output.
parent 2e4b2345
No related branches found
No related tags found
1 merge request!657Headphone detection override state in audio settings
Pipeline #12757 passed
......@@ -28,11 +28,19 @@ STATIC mp_obj_t mp_headphones_are_connected() {
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_headphones_are_connected_obj,
mp_headphones_are_connected);
STATIC mp_obj_t mp_headphones_detection_override(mp_obj_t enable) {
st3m_audio_headphones_detection_override(mp_obj_get_int(enable));
STATIC mp_obj_t mp_headphones_detection_override(size_t n_args,
const mp_obj_t *args) {
bool enable = mp_obj_get_int(args[0]);
bool override_state = true;
if (n_args > 1) {
override_state = mp_obj_get_int(args[1]);
}
st3m_audio_headphones_detection_override(enable, override_state);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_headphones_detection_override_obj,
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_headphones_detection_override_obj,
1, 2,
mp_headphones_detection_override);
STATIC mp_obj_t mp_headphones_set_volume_dB(mp_obj_t vol_dB) {
......
......@@ -216,9 +216,14 @@ static void _audio_speaker_apply(st3m_audio_output_t *out) {
typedef struct {
flow3r_bsp_audio_jacksense_state_t jacksense;
// True if system should pretend headphones are plugged in.
// True if system should ignore jacksense and use
// headphones_detection_override_state to determine
// whether headphones are connected (true) or not (false)
bool headphones_detection_override;
// Defaults to true
bool headphones_detection_override_state;
// The two output channels.
st3m_audio_output_t headphones;
st3m_audio_output_t speaker;
......@@ -262,6 +267,7 @@ static st3m_audio_state_t state = {
.line_in = false,
},
.headphones_detection_override = false,
.headphones_detection_override_state = true,
.headphones =
{
.volume = 0,
......@@ -310,7 +316,10 @@ static st3m_audio_state_t state = {
//
// Lock must be taken.
static bool _headphones_connected(void) {
return state.jacksense.headphones || state.headphones_detection_override;
if (state.headphones_detection_override) {
return state.headphones_detection_override_state;
}
return state.jacksense.headphones;
}
static void _audio_input_set_source(st3m_audio_input_source_t source) {
......@@ -915,9 +924,11 @@ float st3m_audio_headphones_set_volume_dB(float vol_dB) {
LOCKED(float, _output_set_volume(&state.headphones, vol_dB));
}
void st3m_audio_headphones_detection_override(bool enable) {
void st3m_audio_headphones_detection_override(bool enable,
bool override_state) {
LOCK;
state.headphones_detection_override = enable;
state.headphones_detection_override_state = override_state;
_output_apply(&state.headphones);
_output_apply(&state.speaker);
UNLOCK;
......
......@@ -76,12 +76,19 @@ bool st3m_audio_headset_is_connected(void);
/* Returns true if the line-in jack is connected to a cable. */
bool st3m_audio_line_in_is_connected(void);
/* If a sleeve contact mic doesn't pull the detection pin low enough the
* codec's built in headphone detection might fail. Calling this function
* with 'enable = 1' overrides the detection and assumes there's headphones
* plugged in. Call with 'enable = 0' to revert to automatic detection.
/* Set to 'enable = 1' if the system should ignore jacksense and use
* headphones_detection_override_state to determine whether headphones are
* connected (true) or not (false).
*
* Use cases:
* - If a sleeve contact mic doesn't pull the detection pin low enough the
* codec's built in headphone detection might fail.
* - If the headset only has a mic connected but we wish to use the internal
* speaker anyway
*
* Call with 'enable = 0' to revert to automatic detection.
*/
void st3m_audio_headphones_detection_override(bool enable);
void st3m_audio_headphones_detection_override(bool enable, bool override_state);
/* Attempts to set target volume for the headphone output/onboard speakers
* respectively, clamps/rounds if necessary and returns the actual volume.
......
......@@ -152,16 +152,28 @@ in the user config.
OS development
--------------
.. warning::
These functions are not to be used in applications, but only by OS settings.
Many of these functions are available in three variants: headphone volume,
speaker volume, and volume. If :code:`headphones_are_connected()` returns 1
the "headphone" variant is chosen, else the "speaker" variant is chosen.
.. py:function:: headphones_detection_override(enable : bool)
.. py:function:: headphones_detection_override(enable : bool, override_state : bool)
Set to 'enable = True' if the system should ignore jacksense and use
override_state to determine whether headphones are connected (True) or not
(False).
Use cases:
- If a sleeve contact mic doesn't pull the detection pin low enough the
codec's built in headphone detection might fail.
- If the headset only has a mic connected but we wish to use the internal
speaker anyway
If a sleeve contact mic doesn't pull the detection pin low enough the
codec's built in headphone detection might fail. Calling this function
with 'enable = 1' overrides the detection and assumes there's headphones
plugged in. Call with 'enable = 0' to revert to automatic detection.
Call with 'enable = 0' to revert to automatic detection.
.. py:function:: headphones_set_volume_dB(vol_dB : float) -> float
.. py:function:: speaker_set_volume_dB(vol_dB : float) -> float
......
......@@ -334,12 +334,12 @@ class SpeakerMenu(Submenu):
class HeadphonesMenu(Submenu):
def __init__(self, press):
super().__init__(press)
self.num_widgets = 5
self.overhang = -40
self.num_widgets = 6
self.overhang = -80
self.mid_x = 50
self.focus_pos_limit_min = -100
self.focus_pos_limit_min = -20
self.focus_pos_limit_max = 100
self.focus_pos_limit_first = -100
self.focus_pos_limit_first = -40
self.focus_pos_limit_last = 100
def _draw(self, ctx):
......@@ -377,6 +377,43 @@ class HeadphonesMenu(Submenu):
audio.headphones_get_maximum_volume_dB()
)
self.y += 8
# note: jack detection is the inverse of headphones detection override
# jack detection off means headphones detection override on
tmp = self.draw_boolean(
"jack detection",
settings.onoff_headphones_detection_override.value,
off_str="on", # sic
on_str="off", # sic
)
if settings.onoff_headphones_detection_override.value != tmp:
settings.onoff_headphones_detection_override.set_value(tmp)
audio.headphones_detection_override(
settings.onoff_headphones_detection_override.value,
settings.onoff_headphones_detection_override_state.value,
)
if tmp:
self.num_widgets = 7
tmp = self.draw_boolean(
"headphone state",
settings.onoff_headphones_detection_override_state.value,
on_str="on",
off_str="off",
on_hint="sound will always play\nthrough headphones",
off_hint="sound will always play\nthrough speaker",
)
if settings.onoff_headphones_detection_override_state.value != tmp:
settings.onoff_headphones_detection_override_state.set_value(tmp)
audio.headphones_detection_override(
settings.onoff_headphones_detection_override.value,
settings.onoff_headphones_detection_override_state.value,
)
else:
self.num_widgets = 6
self.overhang = -80
class VolumeControlMenu(Submenu):
def __init__(self, press):
......
......@@ -159,6 +159,11 @@ def run_main() -> None:
audio.onboard_mic_to_speaker_set_allowed(
settings.onoff_onboard_mic_to_speaker_allowed.value
)
if settings.onoff_headphones_detection_override.value:
audio.headphones_detection_override(
settings.onoff_headphones_detection_override.value,
settings.onoff_headphones_detection_override_state.value,
)
leds.set_brightness(settings.num_leds_brightness.value)
sys_display.set_backlight(settings.num_display_brightness.value)
......
......@@ -255,6 +255,16 @@ onoff_onboard_mic_to_speaker_allowed = OnOffTunable(
"system.audio.onboard_mic_to_speaker_allowed",
False,
)
onoff_headphones_detection_override = OnOffTunable(
"Headphones detection override enabled",
"system.audio.headphones_detection_override",
False,
)
onoff_headphones_detection_override_state = OnOffTunable(
"Headphones detection override state",
"system.audio.headphones_detection_override_state",
True,
)
num_headset_mic_gain_db = NumberTunable(
"Headset Mic Gain dB", "system.audio.headset_mic_gain_dB", 0
......@@ -306,6 +316,8 @@ load_save_settings: List[UnaryTunable] = [
onoff_onboard_mic_allowed,
onoff_line_in_allowed,
onoff_onboard_mic_to_speaker_allowed,
onoff_headphones_detection_override,
onoff_headphones_detection_override_state,
num_headset_mic_gain_db,
num_onboard_mic_gain_db,
num_line_in_gain_db,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment