2

I am on UBuntu 16.04. I have asked a question here regarding headphones plug unplug event. What I tried didn't work. I want to use acpi_listen command to listen to headphones connected event and display a message using notify-send. How to use acpi_listen in a shell script?

  • I think udev makes more sense than acpi_listen but you may find this thread interesting with many different answers for headphone control: http://askubuntu.com/questions/769593/16-04-headphones-detected-but-not-switched-on-automatically-after-startup – WinEunuuchs2Unix Feb 03 '17 at 01:45

2 Answers2

4

Writing script like that is fairly simple - you need to pipe acpi_listen to while IFS= read -r line ; do ... done structure, and take care of handling the events within that structure. The read shell builtin command will wait for a line of text from acpi_listen and processing will occur when the if statement sees that the line contains appropriate text. Alternatively, one could use case statement for better portability of the script.

Here's the simple script I personally would use. Tested on Ubuntu 16.04 LTS

#!/bin/bash
acpi_listen | while IFS= read -r line;
do
    if [ "$line" = "jack/headphone HEADPHONE plug" ]
    then
       notify-send "headphones connected"
       sleep 1.5 && killall notify-osd
    elif [ "$line" = "jack/headphone HEADPHONE unplug" ]
    then
       notify-send "headphones disconnected"
       sleep 1.5 && killall notify-osd
    fi
done

Note that if you plan to run this from cron job or via /etc/rc.local, you would need to export your DBUS_SESSION_BUS_ADDRESS for notify-send to work.

Sergiy Kolodyazhnyy
  • 105,154
  • 20
  • 279
  • 497
  • Simply elegant! Thanks a lot Serg. You have been helping me since I have migrated to Ubuntu. Thanks a lot! – thewebjackal Feb 03 '17 at 12:39
  • 1
    +1. I read your edit comments on POSIX. So I have to change all my == to = now? – WinEunuuchs2Unix Apr 19 '18 at 00:08
  • 1
    @WinEunuuchs2Unix If you're working only with bash and Ubuntu, then it's OK, no need to change anything. When you work with multiple OS and rely on POSIX /bin/sh then it'd better be POSIX compliant. Choice here is also because of [. When you use [[ and ==, the stuff on the right is treated as regex pattern. You kinda have to be aware of that of there's special characters you're trying to match, like * and ^. Pattern vs literal string, in other words – Sergiy Kolodyazhnyy Apr 19 '18 at 00:54
  • Serge, it's kind of over my head but I only use #!/bin/bash and read single [ invokes test external command so I've been converting stuff to [[ built-in. As far as regex goes, Muru would be the first to tell you it gives me a headache :) – WinEunuuchs2Unix Apr 19 '18 at 01:26
  • @WinEunuuchs2Unix The [ and [[ are tools, and you need right tool for the right job. If you are dealing with simple string comparison, [ is enough. But [[ is more powerful, and when you need that extra pattern matching power in shell scripts, [[ will be your friend. Compare [ "mystring" == *str* ] and [[ "mystring" == *str* ]]. When you have bash, this is your pattern matching friend. Otherwise, if you only have /bin/sh you may need complex case statement. – Sergiy Kolodyazhnyy Apr 19 '18 at 02:08
  • Compare also ( set -x ;[ *.txt == *txt ] && echo "Yes" ) vs ( set -x ;[[ *.txt == *txt ]] && echo "Yes" ) The [[ won't perform filename globbing where you don't want it, i.e. when you are doing pattern and string comparison matching on variable, you don't want * behave as file glob. There are better utilities for that already anyway, like find. – Sergiy Kolodyazhnyy Apr 19 '18 at 02:10
2

I was looking for something similar, but instead of a notification, I wanted to pause when unplugged (and the music was playing) and play when plugged in (and the music was paused).

I know, this is not exactly what the OP asked for, but I can’t comment here (what a pity that Stack Exchange sites don’t accumulate reputation score each other).

Anyway, here’s modified script of the @Sergiy’s one. I don’t say it is optimised or whatever, but it is working. I would be glad if someone (a Basher Pro? ;p) would improve it. :)

Btw, I tried using it with vlc (or cvlc, nvlc), but I couldn’t find a way to toggle play/pause from terminal when vlc was running in background (what I do all the time).

And note that I use audacious player—if you use whatever else, you need to change $state variable and playing/pausing commands.

UPDATE Added control for vlc (based upon this answer, as @BenjaminR has pointed out).

# Play/pause music like in smartphones

# Play when the headphone was plugged in,
# pause when the headphone was unplugged

# As there is no separate option in Audacious
# for playing even if it is already playing
# (or for pausing even if it is already paused),
# only toggles (e.g. play when paused, otherwise pause),
# I was forced to check the state of playback
# from PulseAudio (using `pacmd`).

# Added control for vlc (src: https://stackoverflow.com/a/43156436/3408342)

#!/bin/bash
acpi_listen | while IFS= read -r line; do
    test=$(pacmd list-sink-inputs | grep "application.process.binary\|state" | \sed 's/[="]//g' - | awk '{print $2}')
    if [[ $test ]]; then
        stateAud=$(echo "$test" | grep audacious -B1 | head -1)
        stateVlc=$(echo "$test" | grep vlc -B1 | head -1)

        # Play music when headphone jack has been plugged in AND the stateAud is corked/paused
        if [[ "$line" = "jack/headphone HEADPHONE plug" && $stateAud = "CORKED" ]]; then
            audacious -t
        fi
        if [[ "$line" = "jack/headphone HEADPHONE plug" && $stateVlc = "CORKED" ]]; then
            dbus-send --type=method_call --dest=org.mpris.MediaPlayer2.vlc /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Play
        fi
        if [[ "$line" = "jack/headphone HEADPHONE unplug" && $stateAud = "RUNNING" ]]; then
            audacious -t
        fi
        if [[ "$line" = "jack/headphone HEADPHONE unplug" && $stateVlc = "RUNNING" ]]; then
            dbus-send --type=method_call --dest=org.mpris.MediaPlayer2.vlc /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Pause
        fi
        echo
    fi
done
  • 1
    So this works for audacious, but not for VLC? Is that what you're saying? nb. Once you've got > 200 reputation in one site, you will automatically get 100 reputation on any new SE site you join as a "trusted" user. Ref: https://meta.stackexchange.com/a/79783 – Benjamin R Jan 20 '19 at 16:19
  • @BenjaminR, I would work with vlc if vlc would have a command-line option to toggle play/pause (e.g. vlc --pause). However, I could not find one in vlc --help. Or you know a way around it? I’m interested. :)

    And thank you for info about the reputation. I am just a occasional user of these sites—I search more than I ask (as I believe that ‘everything’ is on the Web).

    – tukusejssirs Jan 20 '19 at 16:54
  • Check this answer out: https://stackoverflow.com/questions/14256193/linux-control-a-running-vlc-process-through-command-line – Benjamin R Jan 21 '19 at 13:12