使用 alsa.name 将 pactl 名称存储到变量

使用 alsa.name 将 pactl 名称存储到变量

我遇到了一个问题,使用 ubuntu 20.04 接收器卡的 RPI 在启动之间更改了卡号。我想解决这个问题,我可以创建一个 bash 脚本来获取每张卡的名称及其关联的名称,然后将使用 alsa.name“bcm2835 Headphones”的名称存储到一个变量中,我可以使用该变量使用 systemd 设置默认值。我无法获取 alsa.name,也无法弄清楚是什么导致它出错。

我的 pactl list sink 输出是:

Sink #0
        State: SUSPENDED
        Name: alsa_output.platform-bcm2835_audio.stereo-fallback
        Description: Built-in Audio Stereo
        Driver: module-alsa-card.c
        Sample Specification: s16le 2ch 44100Hz
        Channel Map: front-left,front-right
        Owner Module: 7
        Mute: no
        Volume: front-left: 65536 / 100% / 0.00 dB,   front-right: 65536 / 100% / 0.00 dB
                balance 0.00
        Base Volume: 65536 / 100% / 0.00 dB
        Monitor Source: alsa_output.platform-bcm2835_audio.stereo-fallback.monitor
        Latency: 0 usec, configured 0 usec
        Flags: HARDWARE DECIBEL_VOLUME LATENCY 
        Properties:
                alsa.resolution_bits = "16"
                device.api = "alsa"
                device.class = "sound"
                alsa.class = "generic"
                alsa.subclass = "generic-mix"
                alsa.name = "bcm2835 HDMI 1"
                alsa.id = "bcm2835 HDMI 1"
                alsa.subdevice = "0"
                alsa.subdevice_name = "subdevice #0"
                alsa.device = "0"
                alsa.card = "0"
                alsa.card_name = "bcm2835 HDMI 1"
                alsa.long_card_name = "bcm2835 HDMI 1"
                alsa.driver_name = "snd_bcm2835"
                device.bus_path = "platform-bcm2835_audio"
                sysfs.path = "/devices/platform/soc/fe00b840.mailbox/bcm2835_audio/sound/card0"
                device.form_factor = "internal"
                device.string = "hw:0"
                device.buffering.buffer_size = "131072"
                device.buffering.fragment_size = "131072"
                device.access_mode = "mmap+timer"
                device.profile.name = "stereo-fallback"
                device.profile.description = "Stereo"
                device.description = "Built-in Audio Stereo"
                module-udev-detect.discovered = "1"
                device.icon_name = "audio-card"
        Ports:
                analog-output: Analog Output (priority: 9900)
        Active Port: analog-output
        Formats:
                pcm

Sink #1
        State: RUNNING
        Name: alsa_output.platform-bcm2835_audio.stereo-fallback.2
        Description: Built-in Audio Stereo
        Driver: module-alsa-card.c
        Sample Specification: s16le 2ch 44100Hz
        Channel Map: front-left,front-right
        Owner Module: 8
        Mute: no
        Volume: front-left: 32770 /  50% / -18.06 dB,   front-right: 32770 /  50% / -18.06 dB
                balance 0.00
        Base Volume: 56210 /  86% / -4.00 dB
        Monitor Source: alsa_output.platform-bcm2835_audio.stereo-fallback.2.monitor
        Latency: 28157 usec, configured 36000 usec
        Flags: HARDWARE HW_MUTE_CTRL HW_VOLUME_CTRL DECIBEL_VOLUME LATENCY 
        Properties:
                alsa.resolution_bits = "16"
                device.api = "alsa"
                device.class = "sound"
                alsa.class = "generic"
                alsa.subclass = "generic-mix"
                alsa.name = "bcm2835 Headphones"
                alsa.id = "bcm2835 Headphones"
                alsa.subdevice = "0"
                alsa.subdevice_name = "subdevice #0"
                alsa.device = "0"
                alsa.card = "1"
                alsa.card_name = "bcm2835 Headphones"
                alsa.long_card_name = "bcm2835 Headphones"
                alsa.driver_name = "snd_bcm2835"
                device.bus_path = "platform-bcm2835_audio"
                sysfs.path = "/devices/platform/soc/fe00b840.mailbox/bcm2835_audio/sound/card1"
                device.form_factor = "internal"
                device.string = "hw:1"
                device.buffering.buffer_size = "131072"
                device.buffering.fragment_size = "131072"
                device.access_mode = "mmap+timer"
                device.profile.name = "stereo-fallback"
                device.profile.description = "Stereo"
                device.description = "Built-in Audio Stereo"
                module-udev-detect.discovered = "1"
                device.icon_name = "audio-card"
        Ports:
                analog-output-headphones: Headphones (priority: 9900)
        Active Port: analog-output-headphones
        Formats:
                pcm

我当前的脚本是

#!/bin/bash

# Get the output of pactl list sinks
output=$(pactl list sinks)

# Split the output into an array of lines
lines=($output)

# Initialize variables
card_num=0
name=""
also_name=""

# Iterate through the lines of the output
for line in "${lines[@]}"; do
  # Check if the line starts with "Sink #" (indicating a new sink)
  if [[ $line =~ ^Sink\ # ]]; then
    # If we have previously found a sink, print the information for it
    if [[ $card_num -ne 0 ]]; then
      echo "Card #: $card_num"
      echo "Name: $name"
      echo "also.name: $also_name"
      echo ""
    fi
    # Reset the variables for the new sink
    card_num=0
    name=""
    also_name=""
  fi
  # Extract the card number from the "Card:" line
  if [[ $line =~ ^Card: ]]; then
    card_num=$(echo $line | cut -d ' ' -f 2)
  fi
  # Extract the name from the "Name:" line
  if [[ $line =~ ^Name: ]]; then
    name=$(echo $line | cut -d ' ' -f 2-)
  fi
  # Extract the also.name from the "also.name:" line
  if [[ $line =~ ^also.name: ]]; then
    also_name=$(echo $line | cut -d ' ' -f 2-)
  fi
done

# Print the information for the last sink
echo "Card #: $card_num"
echo "Name: $name"
echo "also.name: $also_name"

谢谢 M. Becerra,这太尴尬了。

我今天取得了一些进展。制作了一个服务,它获取并设置默认接收器并将其输出到 txt 文件。

sink=$(pactl list sinks)

#parse for the value of "Name:" to get sink names and store each seperated by a comma   

sink_names=$(echo "$sink" | grep -oP '(?<=Name: ).*' | tr '\n' ',' | sed 's/,$//')

#parse for the value of "alsa.name =" to get alsa names and store each alsa name seperated by a comma

alsa_names=$(echo "$sink" | grep -oP '(?<=alsa.name = ").*(?=")' | tr '\n' ',' | sed 's/,$//')

#Intialize sink1 and add the first sink name and first alsa name to it seperated by a comma

sink1=$(echo "$sink_names" | cut -d ',' -f 1),$(echo "$alsa_names" | cut -d ',' -f 1)

#Intialize sink2 and add the second sink name and second alsa name to it seperated by a comma

sink2=$(echo "$sink_names" | cut -d ',' -f 2),$(echo "$alsa_names" | cut -d ',' -f 2)

#Check if the second valye in sink1 or sink2 matches "bcm2835 Headphones", if yes, then store the value of the sink name into a new variable, defualt_sink

if [[ $(echo "$sink1" | cut -d ',' -f 2) == "bcm2835 Headphones" ]]; then

    default_sink=$(echo "$sink1" | cut -d ',' -f 1)

elif [[ $(echo "$sink2" | cut -d ',' -f 2) == "bcm2835 Headphones" ]]; then

    default_sink=$(echo "$sink2" | cut -d ',' -f 1)

fi

echo $default_sink  > default_sink.txt

#set the default sink to the value of default_sink using pactl set-default-sink

pactl set-default-sink "$default_sink"

#unmute the default sink

pactl set-sink-mute "$default_sink" 0

#set the volume of the default sink to 40%

pactl set-sink-volume "$default_sink" 40%

为了添加一些颜色,我使用 PIR 传感器在不活动时关闭显示器并静音。

import os
import time
from datetime import datetime
from gpiozero import MotionSensor
import logging
import subprocess

# Read the default sink from the default_sink.txt file
with open('default_sink.txt', 'r') as f:
    default_sink = f.read().strip()

os.environ['DISPLAY'] = ':0'
os.environ['PATH'] += ':/usr/bin'

# Create a MotionSensor object on pin 17 (or whatever pin the PIR sensor is connected to)
pir = MotionSensor(4)

# Initialize the monitor state to "off" and audio state to "unmuted"
monitor_on = False
audio_unmuted = False

# Create a timer variable
timer = 0

# Set up logging
logging.basicConfig(filename='motion.log', level=logging.INFO)

while True:**strong text**
    # If the PIR sensor is triggered
    if pir.motion_detected:
        # If the monitor is off, turn it on and unmute the audio
        if not monitor_on:
            os.system("xset dpms force on")
            # Unmute the audio using pactl
            result = subprocess.run(["/usr/bin/pactl", "set-sink-mute", default_sink, "0"])
            # Log the default sink and the exit code of the command
            logging.info("{} - Default sink: {}, pactl set-sink-mute exit code: {}".format(datetime.now().strftime("%Y-%m-%d %H:%M:%S"), default_sink, result))
            monitor_on = True
            audio_unmuted = True
            # Restart the timer
            timer = time.time()
    # If the PIR sensor has been inactive for 1 minute
    elif time.time() - timer > 60:
        # If the monitor is on, turn it off and mute the audio
        if monitor_on:
            os.system("xset dpms force off")
            # Mute the audio using pactl
            result = subprocess.run(["/usr/bin/pactl", "set-sink-mute", default_sink, "1"])
            # Log the default sink and the exit code of the command
            logging.info("{} - Default sink: {}, pactl set-sink-mute exit code: {}".format(datetime.now().strftime("%Y-%m-%d %H:%M:%S"), default_sink, result))
            monitor_on = False
            audio_unmuted = False

    # Sleep for a short period to prevent excessive CPU usage
    time.sleep(0.1)

现在我面临 pactl 命令在脚本中不起作用的问题

INFO:root:2023-01-10 16:05:01 - Default sink: alsa_output.platform-bcm2835_audio.stereo-fallback.2, pactl set-sink-mute exit code: CompletedProcess(args=['/usr/bin/pactl', 'set-sink-mute', 'alsa_output.platform-bcm2835_audio.stereo-fallback.2', '1'], returncode=1)

我的想法是,它是以 root 身份运行的,而不是以用户身份运行的。systemd 服务设置了用户和组属性,如果确实是 root 身份,我不确定为什么 pactl 会以 root 身份运行。

相关内容