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.
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.
Sign up to join this communityIn 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
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.
man inotify
says pseudo-fs like /proc are not monitorable with inotify. is there a workaround?
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.
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.
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 ------------
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.
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
@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.
/sys
then, and perhaps notifications via dbus.