我遇到了一个问题,使用 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 身份运行。