#!/usr/bin/env bash # This file is part of The RetroPie Project # # The RetroPie Project is the legal property of its developers, whose names are # too numerous to list here. Please refer to the COPYRIGHT.md file distributed with this source. # # See the LICENSE.md file at the top-level directory of this distribution and # at https://raw.githubusercontent.com/RetroPie/RetroPie-Setup/master/LICENSE.md # rp_module_id="audiosettings" rp_module_desc="Configure audio settings" rp_module_section="config" rp_module_flags="!all rpi" function depends_audiosettings() { if [[ "$md_mode" == "install" ]]; then getDepends alsa-utils fi } function gui_audiosettings() { # Check if the internal audio is enabled if [[ `aplay -ql | grep -e bcm2835 -e vc4hdmi | wc -l` < 1 ]]; then printMsgs "dialog" "On-board audio disabled or not present" return fi # The list of ALSA cards/devices depends on the 'snd-bcm2385' module parameter 'enable_compat_alsa' # * enable_compat_alsa: true - single soundcard, output is routed based on the `numid` control # * enable_compat_alsa: false - one soundcard per output type (HDMI/Headphones) # When PulseAudio/PipeWire is enabled, try to configure it and leave ALSA alone if _pa_cmd_audiosettings systemctl -q --user is-enabled {pulseaudio,pipewire-pulse}.service; then _pulseaudio_audiosettings elif aplay -l | grep -q "bcm2835 ALSA"; then _bcm2835_alsa_compat_audiosettings else _bcm2835_alsa_internal_audiosettings fi } function _reset_alsa_audiosettings() { /etc/init.d/alsa-utils reset alsactl store rm -f "$home/.asoundrc" "/etc/alsa/conf.d/99-retropie.conf" printMsgs "dialog" "Audio settings reset to defaults" } function _move_old_config_audiosettings() { if [[ -f "$home/.asoundrc" && ! -f "/etc/alsa/conf.d/99-retropie.conf" ]]; then if dialog --yesno "The ALSA audio configuration for RetroPie has moved from $home/.asoundrc to /etc/alsa/conf.d/99-retropie.conf\n\nYou have a configuration in $home/.asoundrc - do you want to move it to the new location? If $home/.asoundrc contains your own changes you should choose 'No'." 20 76 2>&1 >/dev/tty; then mkdir -p /etc/alsa/conf.d mv "$home/.asoundrc" "/etc/alsa/conf.d/" fi fi } function _bcm2835_alsa_compat_audiosettings() { _move_old_config_audiosettings local cmd=(dialog --backtitle "$__backtitle" --menu "Set audio output (ALSA - compat)" 22 86 16) local hdmi="HDMI" # the Pi 4/5 have 2 HDMI ports, so number them (isPlatform "rpi4" || isPlatform "rpi5") && hdmi="HDMI 1" local options=( 1 "Auto" 2 "Headphones - 3.5mm jack" 3 "$hdmi" ) # add 2nd HDMI port on the Pi 4/5 (isPlatform "rpi4" || isPlatform "rpi5") && options+=(4 "HDMI 2") options+=( M "Mixer - adjust output volume" R "Reset to default" ) # If PulseAudio (PipeWire) is installed, add an option to enable it local sound_server="PulseAudio" if hasPackage "wireplumber"; then options+=(P "Enable PipeWire") else hasPackage "pulseaudio" && options+=(P "Enable PulseAudio") fi choice=$("${cmd[@]}" "${options[@]}" 2>&1 >/dev/tty) if [[ -n "$choice" ]]; then case "$choice" in 1) amixer cset numid=3 0 alsactl store printMsgs "dialog" "Set audio output to Auto" ;; 2) amixer cset numid=3 1 alsactl store printMsgs "dialog" "Set audio output to Headphones - 3.5mm jack" ;; 3) amixer cset numid=3 2 alsactl store printMsgs "dialog" "Set audio output to $hdmi" ;; 4) amixer cset numid=3 3 alsactl store printMsgs "dialog" "Set audio output to HDMI 2" ;; M) alsamixer >/dev/tty &1 >/dev/tty) if [[ -n "$choice" ]]; then case "$choice" in [0-9]) _asoundrc_save_audiosettings $choice ${options[$((choice*2+1))]} printMsgs "dialog" "Set audio output to ${options[$((choice*2+1))]}" ;; M) alsamixer >/dev/tty "$tmpfile" pcm.hdmi${card_index} { type asym playback.pcm { type plug slave.pcm "hdmi:${card_name}" } } ctl.!default { type hw card $card_index } pcm.softvolume { type softvol slave.pcm "hdmi${card_index}" control.name "HDMI Playback Volume" control.card ${card_index} } pcm.softmute { type softvol slave.pcm "softvolume" control.name "HDMI Playback Switch" control.card ${card_index} resolution 2 } pcm.!default { type plug slave.pcm "softmute" } EOF else cat << EOF > "$tmpfile" pcm.!default { type asym playback.pcm { type plug slave.pcm "output" } } pcm.output { type hw card $card_index } ctl.!default { type hw card $card_index } EOF fi local dest="/etc/alsa/conf.d/99-retropie.conf" mkdir -p /etc/alsa/conf.d mv "$tmpfile" "$dest" chmod 644 "$dest" } function _pulseaudio_audiosettings() { local options=() local sinks=() local sink_index local sink_label local sound_server="PulseAudio" # Check if PulseAudio is running, otherwise 'pactl' will not work if ! _pa_cmd_audiosettings pactl info >/dev/null; then printMsgs "dialog" "PulseAudio is present, but not running.\nAudio settings cannot be set right now." return fi while read sink_index sink_label sink_id; do options+=("$sink_index" "$sink_label") sinks[$sink_index]=$sink_id done < <(_pa_cmd_audiosettings pactl list sinks | \ awk -F [:=#] 'BEGIN {idx=0} /Sink/ { ctl_index=$2 do {getline} while($0 !~ /card.name/ && $0 !~ /Formats/); if ( $2 != "" ) { gsub(/"|bcm2835[^a-zA-Z]+/, "", $2); # strip bcm2835 suffix on analog output gsub(/vc4[-]?/ , "", $2); # strip the vc4 suffix on HDMI output(s) if ( $2 ~ /hdmi/ ) $2=toupper($2) print idx,$2,ctl_index idx++ } }' ) _pa_cmd_audiosettings pactl info | grep -i pipewire >/dev/null && sound_server="PipeWire" local cmd=(dialog --backtitle "$__backtitle" --menu "Set audio output ($sound_server)" 22 86 16) options+=( M "Mixer - adjust output volume" R "Reset to default" P "Disable $sound_server" ) choice=$("${cmd[@]}" "${options[@]}" 2>&1 >/dev/tty) if [[ -n "$choice" ]]; then case "$choice" in [0-9]*) _pa_cmd_audiosettings pactl set-default-sink ${sinks[$choice]} rm -f "/etc/alsa/conf.d/99-retropie.conf" printMsgs "dialog" "Set audio output to ${options[$((choice*2+1))]}" ;; M) _pa_cmd_audiosettings alsamixer >/dev/tty /dev/null }