42

I'm running audio over HDMI to my receiver, which has a full 7.1 setup connected to it. However, most of the stuff that I listen to has far fewer channels—some is mono, most is stereo, a bit is 5.1. When the receiver is fed with the right number of channels, it has various DSP effects which work fairly well (e.g. in splitting out a center channel, in sending base to the subwoofer, auto-detecting Dolby matrix surround, etc.). This ceases working if you send it a full 7.1 signal with a bunch of silent channels.

The number of output channels in PulseAudio is configured, per-card/sink, by the profile assigned to the card. You can change the assigned profile with pacmd, pactl, and various GUI programs.

How can I set it up to automatically change the profile based on the channel usage in the input stream(s)? E.g., if the input streams are only using front-left and front-right, switch to the stereo profile. If they're using back-left and back-right as well, switch to quadrophonic, etc.

10
  • 3
    Maybe I'm wrong, but I don't think it is feasible at all. Pulseaudio manages multiple streams at once: which profile would be correct if different streams with different channel numbers are playing together? Aug 26, 2015 at 10:14
  • @meden The one with the highest number of channels, I guess.
    – derobert
    Aug 26, 2015 at 15:14
  • Yes, of course, but still there will be cases in which you could not achieve your goal. BTW, I do not think there is a way in Pulseaudio to conditionally switch a profile. Maybe the Kodi guide to Pulseaudio [kodi.wiki/view/PulseAudio] could be useful to have some hint (i.e. using passthrough and let your receiver do all the work, provided it supports all formats you use). Aug 27, 2015 at 9:25
  • This is an interesting question. I don't have the audio setup available to test this, but as a work around, if you were to create profiles for each instance you envision, setup a script to analyze the streams in advance (perhaps by grepping the output of mediainfo or ffmpeg or avconv) and then use pacmd to select the appropriate profile prior to launching your player, From a logical standpoint I would expect it to work provided you were playing one audio at a time.
    – Elder Geek
    Dec 15, 2016 at 22:42
  • 4
    It might be worth submitting this question as a feature request at launchpad.net/bugs/bugtrackers/pulseaudio-bugs if it has not already been submitted there. It would be an interesting feature and pulse audio could probably solve this better internally than by using an external script.
    – Alexander
    Jan 13, 2017 at 14:07

2 Answers 2

3

This is just a concept and no complete solution:

You may be able to do your own handling of events with patcl subscribe if you can assign configurations to pulsaudio clients (e.g., if the movie player connects, you switch to 7.1 configuration, otherwise you use the stereo configuratioin). You will get a constant stream of events from patcl subscribe, which you can handle by observing client connections. Then you can just call pactl/pacmd to change the profile.

Example output of pactl subscribe:

$ pactl subscribe 
Event 'change' on sink #0
Event 'remove' on sink-input #93
Event 'change' on sink #0
Event 'change' on source #0
Event 'change' on sink #0
Event 'change' on source #0
Event 'new' on sink-input #98
Event 'change' on sink-input #98

Please note, that you still have the problem to handle cases in which you have multiple clients with a different number of channels.

Furthermore, the above approach is rather limited. The per application settings are not sufficient to detect the real number of used channels of the application (e.g. vlc might play a 5.1 or 7.1 video). I have not found a way to get the number actually used channels of an pulseaudio client over pactl, but I might have missed some options here. Alternatively, you might be also able to hook into the video player application itself and get the missing bits form there.

2
  • With pactl list | grep format.channels you should be able to find out the max. # of channels used (and more information as well). Using that information in a script triggered by subscribed events could lead to a solution.
    – ridgy
    Jan 7, 2018 at 17:43
  • This works for me! I posted it as a separate answer below because comments are limited in characters. Sep 4, 2021 at 21:11
0

I worked the pactl subscribe idea into a solution - the first solution that worked for me, finally!

In .xsessionrc I have

pkill --signal 9 -f auto-switch.rb
~/.auto-switch.rb &

And in ~/.auto-switch.rb

#!/usr/bin/env ruby

require 'open3'

RE = /^Event 'new' on sink #(\d+)$/

Open3.popen2('pactl', 'subscribe') do |_stdin, stdout, _status_thread|
  stdout.each_line do |line|
    match = RE.match(line)
    system('pactl', 'set-default-sink', match.captures.first) if match
  end
end

(And chmod +x ~/.auto-switch.rb)

This listens to pactl subscribe and runs pactl set... commands as you like whenever pactl subscribe reports some change in your setup. You could modify this with extra logic for your situation if you pleased. You could write it in some other language besides Ruby too, if you preferred.

I just wanted to come here to report that this has been working perfectly for me for weeks now and is a vastly simpler solution to all the others I could find on StackOverflow related websites. Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.