0

I have been trying set up my usb microphone to switch to default and loopback automatically with udev.

My current rules are:

ACTION=="add", ATTR{idVendor}=="046d", ATTR{idProduct}=="0a03", GROUP=="audio" RUN+="/usr/bin/micplug"
ACTION=="remove", ENV{ID_MODEL}=="Logitech_USB_Microphone", RUN+="/usr/bin/micunplug"

The micplug script is:

#!/bin/bash

echo "setting source mic" >> /home/wanderingconfused/test
pacmd set-default-source alsa_input.usb-Logitech_Logitech_USB_Microphone-00.analog-mono
echo "loopback mic" >> /home/wanderingconfused/test
pactl load-module module-loopback latency_msec=1 source=alsa_input.usb-Logitech_Logitech_USB_Microphone-00.analog-mono sink=alsa_output.pci-0000_00_14.2.analog-stereo

Which sets the mic as the default source and loopbacks it.

The micunplug script is:

#!/bin/bash

echo "turn off loopback" >> /home/wanderingconfused/test
pactl unload-module $(pactl list short modules | awk '$2 == "module-loopback" { print $1 }' - )
echo "setting source webcam" >> /home/wanderingconfused/test
pacmd set-default-source alsa_input.usb-046d_081b_4B042590-02.analog-mono

Which turns off the loopback and returns the default source to my webcam.

The scripts work exactly as intended on their own. However, when udev executes them my everything echoes to the test file, but pulseaudio ignores the commands.

I was thinking it had something to do with permissions, which is why I added GROUP. I have tried a couple groups and owners and tried MODE=="0660", but at this point I am stumped.

Edit 3/3/2017 So now my /usr/bin/pulse_events_wrapper is:

#!/bin/bash

# Get UID of user running pulseaudio (uses the first if more than one)
PUID=`ps -C pulseaudio -o ruid= | awk '{print $1}'`

if [ ! -z "$PUID" ]; then
  # environment variables to export
  export PULSE_RUNTIME_PATH="/var/run/user/$PUID/pulse"
  export HOME=`getent passwd $PUID | cut -d: -f6`

  if [ -x "$HOME/.pulse_events" ]; then
    # Pass single command line arg to user script
    nohup sudo -u "#$PUID" -E $HOME/.pulse_events $1 >/dev/null 2>&1 &
  fi
fi

and the home/.pulse_events script is

!/bin/bash

case $1 in
    micplug)
      echo "setting source mic" >> /home/wanderingconfused/test
      pacmd set-default-source alsa_input.usb-Logitech_Logitech_USB_Microphone-00.analog-mono >>/home/wanderingconfused/test 2>&1
      echo "loopback mic" >> /home/wanderingconfused/test
      pactl load-module module-loopback latency_msec=1 source=alsa_input.usb-Logitech_Logitech_USB_Microphone-00.analog-mono sink=alsa_output.pci-0000_00_14.2.analog-stereo$
    ;;

    micunplug)
      echo "turn off loopback" >> /home/wanderingconfused/test
      pactl unload-module $(pactl list short modules | awk '$2 == "module-loopback" { print $1 }' - ) >>/home/wanderingconfused/test 2>&1
      echo "setting source webcam" >> /home/wanderingconfused/test
      pacmd set-default-source alsa_input.usb-046d_081b_4B042590-02.analog-mono >>/home/wanderingconfused/test 2>&1
    ;;
esac

It works but I'd rather not be dumping all that into a file. I have tried removing the echos and routing everything to null, but then it stops working.

Also the mic unplug seems to repeat itself when I look at the test file:

setting source mic
loopback mic
68
turn off loopback
setting source webcam
turn off loopback
turn off loopback
You have to specify a module index or name
setting source webcam
You have to specify a module index or name
setting source webcam
Source alsa_input.usb-Logitech_Logitech_USB_Microphone-00.analog-mono does not exist.
70
Failure: No such entity
setting source mic
Source alsa_input.usb-Logitech_Logitech_USB_Microphone-00.analog-mono does not exist.
loopback mic
78
turn off loopback
turn off loopback
setting source webcam
You have to specify a module index or name
setting source webcam
setting source mic
Source alsa_input.usb-Logitech_Logitech_USB_Microphone-00.analog-mono does not exist.
loopback mic
80
turn off loopback
turn off loopback
setting source webcam
Failure: No such entity
setting source webcam
setting source mic
loopback mic
82
turn off loopback
turn off loopback
setting source webcam
You have to specify a module index or name
setting source webcam
setting source mic
Source alsa_input.usb-Logitech_Logitech_USB_Microphone-00.analog-mono does not exist.
loopback mic
84
turn off loopback
turn off loopback
setting source webcam
You have to specify a module index or name
setting source webcam
setting source mic
loopback mic
87
turn off loopback
setting source webcam
turn off loopback
You have to specify a module index or name
setting source webcam

Another weird thing even though it says, "Source alsa_input.usb-Logitech_Logitech_USB_Microphone-00.analog-mono does not exist." It still works.

derHugo
  • 3,356
  • 5
  • 31
  • 51

2 Answers2

2

The pulseaudio server normally runs as your regular user (at least on 16.10 that I'm typing this from), however udev runs your script as root, without the normal environment variables that your regular user has. You could probably run pulseaudio system wide (I've never done this but https://community.linuxmint.com/tutorial/view/1137 implies it can be done), or you'll need to modify your script to run the pacmd as the user in question.

Perhaps change your script into a wrapper to run a per user script like:

/usr/bin/pulse_event_wrapper:

#!/bin/bash

# Get UID of user running pulseaudio (uses the first if more than one)
PUID=`ps -C pulseaudio -o ruid= | awk '{print $1}'`

if [ ! -z "$PUID" ]; then
  # environment variables to export
  export PULSE_RUNTIME_PATH="/var/run/user/$PUID/pulse"
  export HOME=`getent passwd $PUID | cut -d: -f6`

  if [ -x "$HOME/.pulse_events" ]; then
    # Pass single command line arg to user script
    sudo -u "#$PUID" -E "$HOME/.pulse_events $1" >/dev/null 2>&1
  fi
fi

then place your script in .pulse_events in your home directory (be sure to make it executable, e.g. chmod 755 /home/wanderingconfused/.pulse_events )

/home/wanderingconfused/.pulse_events:

#!/bin/bash

case $1 in
    micplug)
      echo "setting source mic" >> /home/wanderingconfused/test
      pacmd set-default-source alsa_input.usb Logitech_Logitech_USB_Microphone-00.analog-mono
      echo "loopback mic" >> /home/wanderingconfused/test
      pactl load-module module-loopback latency_msec=1 source=alsa_input.usb-Logitech_Logitech_USB_Microphone-00.analog-mono sink=alsa_output.pci-0000_00_14.2.analog-stereo
    ;;

    micunplug)
      echo "turn off loopback" >> /home/wanderingconfused/test
      pactl unload-module $(pactl list short modules | awk '$2 == "module-loopback" { print $1 }' - )
      echo "setting source webcam" >> /home/wanderingconfused/test
      pacmd set-default-source alsa_input.usb-046d_081b_4B042590-02.analog-mono
    ;;
esac

finally, have udev call the wrapper with the event argument you require:

ACTION=="add", ATTR{idVendor}=="046d", ATTR{idProduct}=="0a03", GROUP=="audio" RUN+="/usr/bin/pulse_event_wrapper micplug"
ACTION=="remove", ENV{ID_MODEL}=="Logitech_USB_Microphone", RUN+="/usr/bin/pulse_event_wrapper micunplug"
derHugo
  • 3,356
  • 5
  • 31
  • 51
  • 1
    I had to change "sudo -u "#$PUID" -E "$HOME/.pulse_events $1" >/dev/null 2>&" to "sudo -u "#$PUID" -E $HOME/.pulse_events $1 >/dev/null 2>&1" to get it to run the script.

    I assume it thought the space was part of the name of the file.

    – wanderingconfused Mar 02 '17 at 16:01
  • However it still isn't running the pulseaudio commands. I redirected the stderr and stdout of those commands to the test file and it tells me, "Source alsa_input.usb-Logitech_Logitech_USB_Microphone-00.analog-mono does not e xist." I am guessing it does not add the device until everything is finished. So I tried moving it to the backgroud with "sudo -u "#$PUID" -E $HOME/.pulse_events $1 &>/dev/null 2>&1" and it is still giving the same error. – wanderingconfused Mar 02 '17 at 16:06
  • One can also nowadasy use systemd to achieve calling pulseaudio or pipewire from a udev triggered script as per: https://askubuntu.com/a/1386206/16234 – sup Jan 09 '22 at 19:52
0

My final mostly working solution.

Udev rules:

ACTION=="add", ATTR{idVendor}=="046d", ATTR{idProduct}=="0a03", GROUP=="audio" RUN+="/usr/bin/pulse_event_wrapper micplug"
ACTION=="remove", ENV{ID_MODEL}=="Logitech_USB_Microphone", RUN+="/usr/bin/pulse_event_wrapper micunplug"

/usr/bin/pulse_events_wrapper

#!/bin/bash

# Get UID of user running pulseaudio (uses the first if more than one)
PUID=`ps -C pulseaudio -o ruid= | awk '{print $1}'`

if [ ! -z "$PUID" ]; then
  # environment variables to export
  export PULSE_RUNTIME_PATH="/var/run/user/$PUID/pulse"
  export HOME=`getent passwd $PUID | cut -d: -f6`

  if [ -x "$HOME/.pulse_events" ]; then
    # Pass single command line arg to user script
    nohup sudo -u "#$PUID" -E $HOME/.pulse_events $1 >/dev/null 2>&1 &
  fi

fi

home/.pulse_events

#!/bin/bash
n=0
case $1 in
    micplug)
      while ! $(pactl list sources|grep -q 'Logitech USB Microphone Analog Mono')
        do let "n += 1"
        sleep 1
        if [ "$n" -eq 10 ]
          then break
        fi
      done
      pacmd set-default-source alsa_input.usb-Logitech_Logitech_USB_Microphone-00.analog-mono
      pactl load-module module-loopback latency_msec=1 source=alsa_input.usb-Logitech_Logitech_USB_Microphone-00.analog-mono sink=alsa_output.pci-0000_00_14.2.analog-stereo
    ;;

    micunplug)
      pactl unload-module $(pactl list short modules | awk '$2 == "module-loopback" { print $1 }' - )
      pacmd set-default-source alsa_input.usb-046d_081b_4B042590-02.analog-mono
    ;;
esac

I added a while loop to check for my mic in the pulseaudio sources list and everything works fine without filling up my test file. The remove rule still triggers twice I have tried watching the udev events to find a unique set IDs that only match 1 event, but the ones I tried break the rule. While that event only needs to be run once running it twice won't hurt anything and I am glad it doesn't run more than that. So... for now... I am done.

derHugo
  • 3,356
  • 5
  • 31
  • 51