ALSA Jack Software Injection

Simple Introduction On Jack Injection

Here jack injection means users could inject plugin or plugout events to the audio jacks through debugfs interface, it is helpful to validate ALSA userspace changes. For example, we change the audio profile switching code in the pulseaudio, and we want to verify if the change works as expected and if the change introduce the regression, in this case, we could inject plugin or plugout events to an audio jack or to some audio jacks, we don't need to physically access the machine and plug/unplug physical devices to the audio jack.

In this design, an audio jack doesn't equal to a physical audio jack. Sometimes a physical audio jack contains multi functions, and the ALSA driver creates multi jack_kctl for a snd_jack, here the snd_jack represents a physical audio jack and the jack_kctl represents a function, for example a physical jack has two functions: headphone and mic_in, the ALSA ASoC driver will build 2 jack_kctl for this jack. The jack injection is implemented based on the jack_kctl instead of snd_jack.

To inject events to audio jacks, we need to enable the jack injection via sw_inject_enable first, once it is enabled, this jack will not change the state by hardware events anymore, we could inject plugin or plugout events via jackin_inject and check the jack state via status, after we finish our test, we need to disable the jack injection via sw_inject_enable too, once it is disabled, the jack state will be restored according to the last reported hardware events and will change by future hardware events.

The Layout of Jack Injection Interface

If users enable the SND_JACK_INJECTION_DEBUG in the kernel, the audio jack injection interface will be created as below:

$debugfs_mount_dir/sound
|-- card0
|-- |-- HDMI_DP_pcm_10_Jack
|-- |-- |-- jackin_inject
|-- |-- |-- kctl_id
|-- |-- |-- mask_bits
|-- |-- |-- status
|-- |-- |-- sw_inject_enable
|-- |-- |-- type
...
|-- |-- HDMI_DP_pcm_9_Jack
|--     |-- jackin_inject
|--     |-- kctl_id
|--     |-- mask_bits
|--     |-- status
|--     |-- sw_inject_enable
|--     |-- type
|-- card1
    |-- HDMI_DP_pcm_5_Jack
    |-- |-- jackin_inject
    |-- |-- kctl_id
    |-- |-- mask_bits
    |-- |-- status
    |-- |-- sw_inject_enable
    |-- |-- type
    ...
    |-- Headphone_Jack
    |-- |-- jackin_inject
    |-- |-- kctl_id
    |-- |-- mask_bits
    |-- |-- status
    |-- |-- sw_inject_enable
    |-- |-- type
    |-- Headset_Mic_Jack
        |-- jackin_inject
        |-- kctl_id
        |-- mask_bits
        |-- status
        |-- sw_inject_enable
        |-- type

The Explanation Of The Nodes

kctl_id

read-only, get jack_kctl->kctl's id

sound/card1/Headphone_Jack# cat kctl_id
Headphone Jack
mask_bits

read-only, get jack_kctl's supported events mask_bits

sound/card1/Headphone_Jack# cat mask_bits
0x0001 HEADPHONE(0x0001)
status

read-only, get jack_kctl's current status

  • headphone unplugged:

    sound/card1/Headphone_Jack# cat status
    Unplugged
    
  • headphone plugged:

    sound/card1/Headphone_Jack# cat status
    Plugged
    
type

read-only, get snd_jack's supported events from type (all supported events on the physical audio jack)

sound/card1/Headphone_Jack# cat type
0x7803 HEADPHONE(0x0001) MICROPHONE(0x0002) BTN_3(0x0800) BTN_2(0x1000) BTN_1(0x2000) BTN_0(0x4000)
sw_inject_enable

read-write, enable or disable injection

  • injection disabled:

    sound/card1/Headphone_Jack# cat sw_inject_enable
    Jack: Headphone Jack               Inject Enabled: 0
    
  • injection enabled:

    sound/card1/Headphone_Jack# cat sw_inject_enable
    Jack: Headphone Jack               Inject Enabled: 1
    
  • to enable jack injection:

    sound/card1/Headphone_Jack# echo 1 > sw_inject_enable
    
  • to disable jack injection:

    sound/card1/Headphone_Jack# echo 0 > sw_inject_enable
    
jackin_inject

write-only, inject plugin or plugout

  • to inject plugin:

    sound/card1/Headphone_Jack# echo 1 > jackin_inject
    
  • to inject plugout:

    sound/card1/Headphone_Jack# echo 0 > jackin_inject