使用键盘快捷键切换音频接收器/输出

使用键盘快捷键切换音频接收器/输出

我想使用快捷方式在 Ubuntu 上切换声音接收器/输出。我希望该解决方案能够适用于任意数量的设备,并在此过程中切换所有接收器输入。

答案1

我希望提供我的解决方案供任何人使用和改进,因为令我非常沮丧的是,没有一个解决方案(即音频输出设备,快速切换?) 在任何条件下都能正常工作。

因此我创建了一个python脚本来完成这个工作,但是有些过度(以及糟糕而丑陋的正则表达式):

#!/usr/bin/env python3
#this little script switches the sound sink on ubuntu
# https://askubuntu.com/questions/156895/how-to-switch-sound-output-with-key-shortcut/1203350#1203350 and https://askubuntu.com/questions/1011806/how-do-i-switch-the-audio-outputs-of-an-audio-device-from-cli?noredirect=1&lq=1 were helpful
import argparse
import logging
import subprocess
import re

#a simple representation of all relevant info of an audio sink for this script
class Sink:
    def __init__(self, index, name, state):
        self.index = index
        self.name = name
        self.state = state
        if state in ["RUNNING", "IDLE"]:
            self.selected = True
        else:
            self.selected = False

    def __str__(self):
        return 'sink\nindex: {self.index}\nname: {self.name}\nstate: {self.state}\nselected: {self.selected}\n'.format(self=self)

#a simple representation of all relevant info of an audio sink-input for this script
class Sink_Input:
    def __init__(self, index, application_name, sink, state):
        self.index = index
        self.application_name = application_name
        self.sink = sink
        self.state = state

    def __str__(self):
        return 'sink-input\nindex: {self.index}\napplication_name: {self.application_name}\nsink: {self.sink}\nstate: {self.state}\n'.format(self=self)

        
def get_sinks():
    pacmd_output = str(subprocess.check_output(["pacmd", "list-sinks"]))
    sinks_raw = pacmd_output.split("index: ")
    sinks = []
    for sink_raw in sinks_raw[1:]:
        index = int(re.findall("^\d+", sink_raw)[0])
        name = re.findall("device.description = \"[^\"]*\"", sink_raw)[0][22:-1]
        state = re.findall("state: [A-Z]*", sink_raw)[0][7:]
        sink = Sink(index, name, state)
        sinks.append(sink)
    return sinks

def get_sink_inputs():
    sink_inputs = []
    pacmd_output = str(subprocess.check_output(["pacmd", "list-sink-inputs"]))
    inputs_raw = pacmd_output.split("index: ")
    for input_raw in inputs_raw[1:]:
        index = int(re.findall("^\d+", input_raw)[0])
        sink = int(re.findall("sink: \d*", input_raw)[0][5:])
        application_name = re.findall("application.name = \"[^\"]*\"", input_raw)[0][20:-1]
        state = re.findall("state: [A-Z]*", input_raw)[0][7:]
        sink_input = Sink_Input(index, application_name, sink, state)
        sink_inputs.append(sink_input)
    return sink_inputs

def switch_to_next_sink(sinks, notify):
    current_sink = None
    next_sink = sinks[0]
    for i in range(len(sinks)):
        if sinks[i].selected:
            current_sink = sinks[i]
            if i == len(sinks) -1:
                next_sink = sinks[0]
            else:
                next_sink = sinks[i+1]
    #switch default sink to next sink
    subprocess.call(["pacmd", "set-default-sink", str(next_sink.index)])
    #move all apps to next sink
    for sink_input in get_sink_inputs():
        subprocess.call(["pacmd", "move-sink-input", str(sink_input.index), str(next_sink.index)])
    if notify:
        subprocess.call(["notify-send", "Changed audio sink", "new audio sink is " + next_sink.name])

def main():
    parser = argparse.ArgumentParser(description='''Switches to the 'next' audio sink on Ubuntu and can provide additional info on sound sinks.
    If no arguments are passed only the next audio sink is selected.
    For ease of use add /usr/bin/python3 /home/sebi/misc/switch_sound_sink.py as keyboard shortcut i.e. Super+Shift+S (Super+O somehow not working) ''')
    parser.add_argument('-s', '--state',
                        help='boiled down output of pacmd list-sinks and list-sink-inputs', action='store_true')
    parser.add_argument('-n', '--notify', help='send notification to the desktop', action='store_true')
    
    logLevelsRange = [logging.NOTSET, logging.DEBUG, logging.INFO, logging.WARN, logging.ERROR, logging.CRITICAL]
    parser.add_argument('-l', '--logLevel', help='the log level', type=int, choices=logLevelsRange,
                        default=logging.INFO)

    args = parser.parse_args()

    if args.state:
        sinks = get_sinks()
        for sink in sinks:
            print(sink)
        sink_inputs = get_sink_inputs()
        for sink_input in sink_inputs:
            print(sink_input)
    else:
        sinks = get_sinks()
        switch_to_next_sink(sinks, args.notify)
        
main()

我添加了可选的桌面通知但没有使用它们,因为它们不能暂时显示。(如何发送自定义桌面通知?

相关内容