39

I am trying to detect a signal when a headphone is connected or disconnected from the system. What is the best way to do this?

If there is a special board with drivers, that will be my preferred way.

7
  • I'm not sure I understand the last part - do you intend to do this by connecting an additional hardware to your computer? Nov 30, 2011 at 14:56
  • @rozcietrzewiacz - I have an java app that needs to get notified if the headphone is plugged or unplugged. That is my goal. I am open to any suggestions/recommendation with or without using additional hardware.
    – user775633
    Nov 30, 2011 at 16:03
  • @Gilles - No, typical hardware does provide notification to software. I know this is U&L, but you're likely familiar with the classic annoying Windows notification: "You've plugged a device into the audio jack!" i51.tinypic.com/2w2hogw.jpg. Linux, thankfully, doesn't do this, but the information should be available from the hardware you've got. The question is how the OS makes this information available. Dec 1, 2011 at 14:44
  • @KevinVermeer I don't happen to be familiar with this particular Windows annoyance, no. Good to know that modern hardware does provide notification, thank you. Linux would typically provide the information through /sys then, and perhaps notifications via dbus. Dec 1, 2011 at 15:30
  • This is not on a windows system. This issue is for LINUX os. I should have been more explicit. Sorry! Anyway looks like by default there is no easy way to trap that notification.. That is why I am even thinking of looking out if there is any custom cards that has a driver that will trap and make this signal available for apps running on linux.
    – user775633
    Dec 1, 2011 at 17:26

7 Answers 7

23

In my linux (Debian GNU/Linux 3.12.0 x86_64) this is know by acpi system so calling acpi_listen shows:

jack/microphone MICROPHONE plug
jack/headphone HEADPHONE plug
jack/microphone MICROPHONE unplug
jack/headphone HEADPHONE unplug

this seems to depend of a selected option in the kernel config CONFIG_SND_HDA_INPUT_JACK

If this is your case you can populate /etc/acpi/events/ with scripts to fire anyting you want.

Check acpid man page http://linux.die.net/man/8/acpid

1
  • This works perfectly on my Ubuntu 15.10 system with HDA Intel PCH, ALC892 Analog, as reported by Alsa. CONFIG_SND_HDA_INPUT_JACK=y is set.
    – Kevin
    Jun 14, 2016 at 18:00
16

This information is available in /proc/asound/card0/codec#0 and depends on the hardware. For my computer, it is in the section which captures this information:

Headphone connected:

[...]
Node 0x0d [Pin Complex] wcaps 0x400181: Stereo
  Control: name="Speaker Phantom Jack", index=0, device=0
  Pincap 0x00000014: OUT Detect
  Pin Default 0x90170110: [Fixed] Speaker at Int N/A
    Conn = Analog, Color = Unknown
    DefAssociation = 0x1, Sequence = 0x0
    Misc = NO_PRESENCE
  Pin-ctls: 0x00:
[...]

Headphone disconnected (see Pin-ctls):

[...]
Node 0x0d [Pin Complex] wcaps 0x400181: Stereo
  Control: name="Speaker Phantom Jack", index=0, device=0
  Pincap 0x00000014: OUT Detect
  Pin Default 0x90170110: [Fixed] Speaker at Int N/A
    Conn = Analog, Color = Unknown
    DefAssociation = 0x1, Sequence = 0x0
    Misc = NO_PRESENCE
  Pin-ctls: 0x40: OUT
[...]

You could use inotify to check if the file was modified and grep the information.

See also https://askubuntu.com/questions/133809/mute-sound-on-headphone-unplug.

3
  • 2
    man inotify says pseudo-fs like /proc are not monitorable with inotify. is there a workaround?
    – Bibek_G
    Feb 12, 2016 at 11:17
  • 1
    @Bibek_G yes, use acpi_listen (see theist's answer).
    – Don Hatch
    Jun 2, 2018 at 12:19
  • I had to use audio1 instead of audio0 for this to work, even though I just have a simple notebook with a single sound card. so it is /proc/asound/card1/codec#0 for me, it might be yet an other number for you.
    – hoijui
    Dec 8, 2018 at 11:16
3

Find the udev tagger of the jack on the System, connect a client (dbus-monitor) that monitors the bus using DBus for messages on jack connect & disconnections.

1
  • Can you expand this answer? How do I "find the udev tagger of the jack"?
    – sydd
    Feb 7 at 9:39
2

If your kernel has jack inputs configured root@brix:~# grep CONFIG_SND_HDA_INPUT_JACK /boot/config-$(uname -r)

Using Evtest you can list all your input events.

root@brix:/etc/acpi# evtest
No device specified, trying to scan all of /dev/input/event*
Available devices:
/dev/input/event0:  Power Button
/dev/input/event1:  Power Button
/dev/input/event2:  Logitech Logitech BT Mini-Receiver
/dev/input/event3:  CM Storm QuickFire Rapid keyboard
/dev/input/event4:  CM Storm QuickFire Rapid keyboard
/dev/input/event5:  PixArt Microsoft USB Optical Mouse
/dev/input/event6:  Logitech Logitech BT Mini-Receiver
/dev/input/event7:  Video Bus
/dev/input/event8:  HDA Intel HDMI HDMI/DP,pcm=3
/dev/input/event9:  HDA Intel HDMI HDMI/DP,pcm=7
/dev/input/event10: HDA Intel HDMI HDMI/DP,pcm=8
/dev/input/event11: HDA Intel PCH Front Mic
/dev/input/event12: HDA Intel PCH Rear Mic
/dev/input/event13: HDA Intel PCH Line
/dev/input/event14: HDA Intel PCH Line Out
/dev/input/event15: HDA Intel PCH Front Headphone
Select the device event number [0-15]: 14
Input driver version is 1.0.1
Input device ID: bus 0x0 vendor 0x0 product 0x0 version 0x0
Input device name: "HDA Intel PCH Line Out"
Supported events:
  Event type 0 (EV_SYN)
  Event type 5 (EV_SW)
    Event code 6 (SW_LINEOUT_INSERT)
Properties:
Testing ... (interrupt to exit)
Event: time 1465927534.591787, type 5 (EV_SW), code 6 (SW_LINEOUT_INSERT), value 0
Event: time 1465927534.591787, -------------- EV_SYN ------------
Event: time 1465927536.618428, type 5 (EV_SW), code 6 (SW_LINEOUT_INSERT), value 1
Event: time 1465927536.618428, -------------- EV_SYN ------------
2

A tool called hda-verb can enable/disable the headphone jack using pins.

For example,

To enable headphone jack, use:

./hda-verb /dev/snd/hwC0D0 0x0f SET_PIN_WIDGET_CONTROL 0x40

To disable headphone jack, use:

./hda-verb /dev/snd/hwC0D0 0x0f SET_PIN_WIDGET_CONTROL 0

Since you just want to check its status, perhaps you can use some polling mechanism in your java program which can check the status of above pins using hda. For this, your java program should be able to call hda-verb. Alternatively, you can check the source of hda-verb as it is available and see how they have done it.

0

My laptop has a Conexant Intel HDA audio system, but the mic and headphone jack volumes controls never show up inside the many mixers available, even alsamixer. The mic and headphone speakers can only be switched ON or OFF. Here's a tiny script to do just that :

#!/bin/bash
#
# Switching on or off your headphone speaker and mic jacks
# and at the same time switching off or on your laptop front speakers.
# requires hda-verb-0.3-6-mdv2011.0.x86_64
#
# Before putting it in place make sure to test your PIN_WIDGET_CONTROL's
# with su -c 'python2 hda-analyzer.py' available here :
# http://www.alsa-project.org/hda-analyzer.py
#
PIN_CONFIGS=/sys/class/sound/hwC0D0/init_pin_configs
if [ ! -f $PIN_CONFIGS ]; then
    echo "Your kernel is missing CONFIG_SND_HDA_HWDEP=y"
    exit 0
fi
if [ ! -f /usr/sbin/hda-verb ]; then
    echo "This script requires hda-verb-0.3-6-mdv2011.0.x86_64"
    exit 0
fi
PINS_PRESENT=`cat $PIN_CONFIGS | awk '{print $1}'`
if [ `basename $0` = "speakers-off.sh" ]; then
# Headset (Mic (Node 0x1b) + Headphone Drive (Node 0x19)) : ON
# Laptop Speaker (Node 0x1f) : OFF
[ `echo "$PINS_PRESENT" | grep 0x19` ] &&
   /usr/sbin/hda-verb /dev/snd/hwC0D0 0x19 SET_PIN_WIDGET_CONTROL 0x40
[ `echo "$PINS_PRESENT" | grep 0x1f` ] &&
   /usr/sbin/hda-verb /dev/snd/hwC0D0 0x1f SET_PIN_WIDGET_CONTROL 0
[ `echo "$PINS_PRESENT" | grep 0x1b` ] &&
   /usr/sbin/hda-verb /dev/snd/hwC0D0 0x1b SET_PIN_WIDGET_CONTROL 0x64
fi

if [ `basename $0` = "speakers-on.sh" ]; then
# Headset (Mic (Node 0x1b) + Headphone Drive (Node 0x19)) : OFF
# Laptop Speaker (Node 0x1f) : ON
[ `echo "$PINS_PRESENT" | grep 0x19` ] &&
   /usr/sbin/hda-verb /dev/snd/hwC0D0 0x19 SET_PIN_WIDGET_CONTROL 0
[ `echo "$PINS_PRESENT" | grep 0x1f` ] &&
   /usr/sbin/hda-verb /dev/snd/hwC0D0 0x1f SET_PIN_WIDGET_CONTROL 0x40
[ `echo "$PINS_PRESENT" | grep 0x1b` ] &&
   /usr/sbin/hda-verb /dev/snd/hwC0D0 0x1b SET_PIN_WIDGET_CONTROL 0x24
fi

exit 0
0

@kevinf already mentioned the program evtest. There is an answer from another question with a bash-script1. Based on that I created a python program:

#!/usr/bin/env python

# add user to group 'input' to get access to /dev/input/event*
# sudo usermod -a -G input $USER

from re import compile
from os import geteuid
from subprocess import Popen, PIPE, call

if geteuid() == 0:
  print("Must be run as user to receive notifications. Add user to group 'input', `sudo usermod -a -G input $USER`.")
  exit()

# find out the event number with running `sudo evtest` and looking for "HDA Intel PCH Headphone"
p = Popen(["evtest", '/dev/input/event14'], stdout=PIPE)

# reading from process
# https://stackoverflow.com/a/28319191/6040478
mask = compile('SW_HEADPHONE_INSERT.*value 1')
for line in p.stdout:
  if mask.search(line.decode('utf-8')) != None:
    print('plugged in')
    call(['notify-send', 'Headset'])

You'd have to adapt it to Java.

1 https://unix.stackexchange.com/a/472517/218172)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .