37

What I want is the following:

  • When I plug in my headphones, I want the sound to be un-muted and set to a specific volume level.
  • When I unplug my headphones, I want the sound to be muted (or set to a specific volume level).

Setting the volume levels isn't the problem, but I somehow need to do this when un-/plugging the headphones, so I'm looking for a way to get notified of those events.

I quickly found /proc/asound/card0/codec#0 to indicate whether headphones are plugged in or not, so I tried to monitor it using inotifywait and change the volume level based on modified notifications. Unfortunately inotifywait failed because proc isn't an ordinary filesystem.

Are there other ways to do this (maybe via PulseAudio)?

Audio device: Intel HDA, audio codec: Conexant CX20585.


To summarize what I've tried so far:

  • Ear Candy: didn't run at all on my system. Seems to be an abandoned project?
  • The code posted by Karl Bielefeldt might work on some hardware, it doesn't on mine.
  • The idea from StephenPaulger fails due to the lack of a 'Speaker' channel.
  • Motivated by aking1012 I made it work by hacking around in the kernel code (after finding the jack sensing code of the codec), but that's a rather cumbersome solution.

So, I'm still looking for an easy way to do this.

4
  • Excellent question, I want to do this too! Feb 3, 2011 at 17:32
  • nice...but i think a patch to alsa will be necessary for the desired "instant" response on plug/unplug. otherwise it would work or seem to work, but under load or other conditions, the response could lag. think you have to get in between the plug event and the output toggle. probably possible, but sooooo not worth an individual patch basis unless an alsa dev says it will be committed to trunk. Feb 6, 2011 at 5:37
  • one approach would be to load the module up in gdb, wait for the "normal" sound events to stop, use the record option, plug and unplug the head phones, and see what happened in the debug recording. Feb 8, 2011 at 17:38
  • how much delay are you comfortable with? Feb 8, 2011 at 23:30

9 Answers 9

4

During the UDS for Oneiric there has been a session about jack detection. See the blueprint for details. It sounds like this will exactly do what I'm looking for: different volume levels for different devices - just not on every hardware:

<htorque> something i'm curious about: will i be able to have different volume levels for different devices (eg., internal sound muted, headphones 75%) anytime soon?

<coling> this will be supported (on some h/w) yes. Timescales are "soonish" :p
<coling> (I'd also expect OSD to be shown (with current volume) when jacks are plugged/unplugged)

Update for 11.10

This should now be working in Oneiric - unfortunately my ThinkPad T510 seems to be one of the systems that's currently not supported.

Another follow-up from David Henningsson:

Long story short, it’s a desirable feature, and we’re moving in that direction, but slowly, as the feature is more complex than it seems like at first glance.

The good news: in the upcoming Ubuntu Oneiric (11.10), this is actually working. The bad news: it isn’t working for everyone.

More here.

Update for 12.04

It's now working with my ThinkPad T510 (and many other models) in Ubuntu 12.04 (development version).

1
  • Is there anything tracking which hardware is currently supported, or something to that effect?
    – Mu Mind
    Oct 5, 2012 at 23:15
3

To set volume level from console use the command amixer. For example:

amixer sset Master playback 0%

Will set your level to 0%

I don't know how to change this when you plug in your headphones... but maybe someone can help you with that

2

Ear Candy has some functionality for dealing with headphone insertion/removal.

1
  • 1
    Looks like this is just for USB headphones... is that correct?
    – Mu Mind
    Oct 5, 2012 at 22:55
2

I don't know how much coding experience you have, but you mentioned inotifywait so I'm going to assume you're at least comfortable with shell scripting. The following C program, based on this article, should be able to detect your headphones being plugged or unplugged, after which you can perform whatever actions you want.

#include <linux/input.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>

int main(int argc, char* argv[])
{
    int fd = -1;
    char name[256]= "Unknown";
    struct input_event event;

    if ((fd = open(argv[1], O_RDONLY)) < 0) {
        perror("evdev open");
        exit(1);
    }

    if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) {
        perror("evdev ioctl");
    }

    printf("The device on %s says its name is %s\n",
            argv[1], name);

    read(fd, &event, sizeof(struct input_event));
    printf("Event type is %d\n", event.type);
    printf("Event code is %d\n", event.code);
    printf("Event value is %d\n", event.value);

    close(fd);
    return 0;
}

The program takes one argument, which should be a path to the input event device for your headphones. This is /dev/input/event7 for me, but you may have to try a few to find which it is on your system. You will need read permissions on that device. The program will print the name of the device, and the type, code, and value of the first event before exiting.

3
  • Unfortunately none of the event* turned out to be connected to my headphone. Anyways, +1 - maybe it is of help to other users.
    – htorque
    Feb 3, 2011 at 19:53
  • +1, works for me, event.value is indeed switched ... but the read operation only returns when the value changes ... maybe you know how to make it not blocking? thanks anyway!
    – Kevin
    Jun 28, 2013 at 15:57
  • You add O_NONBLOCK when you open the device, and check the return value of the read. If it's negative, the read either would have blocked, or some other error occurred. There are other more complicated ways to do it without polling if you are incorporating this into a larger program. Jun 28, 2013 at 16:29
1

Check dmesg and other log files. Probably plugging in/out fires some particular messages.

Then, you could use a daemon to parse that log file and detect the events. I think you know what to do from this point :)

1

If you do

amixer sset 'Speaker' playback 0%

the speaker volume will be muted but headphones will carry on working. Unplugging the headphones means no sound. Which is almost what you want...

However...

If you alter the volume control the 'Speaker' volume setting will be set up again. This is because pulseaudio tries to be clever with setting volumes (See http://pulseaudio.org/wiki/PulseAudioStoleMyVolumes for more information). We can stop it from messing with the volumes though.

Open /etc/pulse/default.pa

and find the line

load-module module-udev-detect

and change it to

load-module module-udev-detect ignore_dB=1

Restart pulseaudio.

killall pulseaudio

Now if you mute the speaker volume changing the master volume will not affect it. So headphones will work but the speaker will remain silent.

1
  • Would be a different approach, but unfortunately I don't have a Speaker volume channel, only Master and PCM.
    – htorque
    Feb 8, 2011 at 18:59
1

I think you might achieve what you need using this: https://bbs.archlinux.org/viewtopic.php?pid=1105458#p1105458

1
  • Welcome to Ask Ubuntu! Whilst this may theoretically answer the question, it would be preferable to include the essential parts of the answer here, and provide the link for reference. Jun 5, 2013 at 1:53
1

Check the ACPID socket for changes, can be done with the help of python or C or shell script, (Python code for controlling the earphone plugin play and pause on rhythmbox). Check for the changes in ACPID voltage to detect earphone plugin and earphone plug out. A seconds delay can be expected though.

0

Pulseaudio has a module shipped by default that is designed to achieve exactly this:

http://pulseaudio.org/wiki/Modules#module-device-restore

1
  • I don't see how this module is supposed to help me.
    – htorque
    Feb 10, 2011 at 10:45

You must log in to answer this question.

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