#!/usr/bin/env bash # # SPDX-License-Identifier: GPL-3.0-or-later usage() { cat <<-_EOF_ live cd sound helper script. Usage: livecdsound [OPTION] OPTIONS -u, --unmute unmute all sound cards -p, --pick select a card for speetch output -h, --help Show this usage message _EOF_ } bugout () { printf "/usr/local/bin/livecd-sound: programming error" stat_fail } echo_card_indices() { if [[ -f /proc/asound/cards ]]; then sed -n -e's/^[[:space:]]*\([0-7]\)[[:space:]].*/\1/p' /proc/asound/cards fi } # The following functions try to set many controls. # No card has all the controls and so some of the attempts are bound to fail. # Because of this, the functions can't return useful status values. # $1 # $2 # $3 unmute_and_set_level() { [[ -n "$3" && -n "$2" && -n "$1" ]] || bugout systemd-cat -t "livecdsound" printf "Setting: %s on card: %s to %s\n" "$2" "$1" "$3" systemd-cat -t "livecdsound" amixer -c "$1" set "$2" "$3" unmute return 0 } # $1 # $2 mute_and_zero_level() { [[ -n "$1" && -n "$2" ]] || bugout systemd-cat -t "livecdsound" printf "Muting control: %s on card: %s\n" "$2" "$1" systemd-cat -t "livecdsound" amixer -c "$1" set "$2" "0%" mute return 0 } # $1 # $2 # $3 "on" | "off" switch_control() { [[ -n "$3" && -n "$1" ]] || bugout systemd-cat -t "livecdsound" printf "Switching control: %s on card: %s to %s\n" "$2" "$1" "$3" systemd-cat -t "livecdsound" amixer -c "$1" set "$2" "$3" return 0 } # $1 sanify_levels_on_card() { unmute_and_set_level "$1" "Front" "80%" unmute_and_set_level "$1" "Master" "80%" unmute_and_set_level "$1" "Master Mono" "80%" unmute_and_set_level "$1" "Master Digital" "80%" # E.g., cs4237B unmute_and_set_level "$1" "Playback" "80%" unmute_and_set_level "$1" "Headphone" "100%" unmute_and_set_level "$1" "PCM" "80%" unmute_and_set_level "$1" "PCM,1" "80%" # E.g., ess1969 unmute_and_set_level "$1" "DAC" "80%" # E.g., envy24, cs46xx unmute_and_set_level "$1" "DAC,0" "80%" # E.g., envy24 unmute_and_set_level "$1" "DAC,1" "80%" # E.g., envy24 unmute_and_set_level "$1" "Synth" "80%" unmute_and_set_level "$1" "CD" "80%" unmute_and_set_level "$1" "PC Speaker" "100%" mute_and_zero_level "$1" "Mic" mute_and_zero_level "$1" "IEC958" # Ubuntu #19648 # Intel P4P800-MX switch_control "$1" "Master Playback Switch" on switch_control "$1" "Master Surround" on # Trident/YMFPCI/emu10k1: unmute_and_set_level "$1" "Wave" "80%" unmute_and_set_level "$1" "Music" "80%" unmute_and_set_level "$1" "AC97" "80%" # DRC: unmute_and_set_level "$1" "Dynamic Range Compression" "80%" # Required for HDA Intel (hda-intel): unmute_and_set_level "$1" "Front" "80%" # Required for SB Live 7.1/24-bit (ca0106): unmute_and_set_level "$1" "Analog Front" "80%" # Required at least for Via 823x hardware on DFI K8M800-MLVF Motherboard switch_control "$1" "IEC958 Capture Monitor" off # Required for hardware allowing toggles for AC97 through IEC958, # valid values are 0, 1, 2, 3. Needs to be set to 0 for PCM1. unmute_and_set_level "$1" "IEC958 Playback AC97-SPSA" "0" # Required for newer Via hardware unmute_and_set_level "$1" "VIA DXS,0" "80%" unmute_and_set_level "$1" "VIA DXS,1" "80%" unmute_and_set_level "$1" "VIA DXS,2" "80%" unmute_and_set_level "$1" "VIA DXS,3" "80%" # Required on some notebooks with ICH4: switch_control "$1" "Headphone Jack Sense" off switch_control "$1" "Line Jack Sense" off # Some machines need one or more of these to be on; # others need one or more of these to be off: switch_control "$1" "Audigy Analog/Digital Output Jack" on switch_control "$1" "SB Live Analog/Digital Output Jack" on # D1984 -- Thinkpad T61/X61 switch_control "$1" "Speaker" on switch_control "$1" "Headphone" on # HDA-Intel w/ "Digital" capture mixer (See Ubuntu #193823) unmute_and_set_level "$1" "Digital" "80%" return 0 } # $1 | "all" sanify_levels() { local ttsdml_returnstatus=0 local card case "$1" in all) for card in $(echo_card_indices); do sanify_levels_on_card "$card" || ttsdml_returnstatus=1 done ;; *) sanify_levels_on_card "$1" || ttsdml_returnstatus=1 ;; esac return "$ttsdml_returnstatus" } # List all cards that *should* be usable for PCM audio. In my experience, # the console speaker (handled by the pcsp driver) isn't a suitable playback # device, so we'll exclude it. list_non_pcsp_cards() { for card in $(echo_card_indices); do local cardfile="/proc/asound/card${card}/id" if [[ -r "$cardfile" && -f "$cardfile" && "$(cat "$cardfile")" != pcsp ]]; then echo "$card" fi done } # Properly initialize the sound card so that we have audio at boot. unmute_all_cards() { sanify_levels all } is_numeric() { local str="$1" [[ "$str" =~ ^[0-9]+$ ]] } set_default_card() { local card="$1" sed -e "s/%card%/$card/g" /etc/asound.conf } play_on_card() { local card="$1" file="$2" aplay -q "-Dplughw:$card,0" "$file" } # If there are multiple usable sound cards, prompt the user to choose one, # using auditory feedback. pick_a_card() { set -f usable_cards="$(list_non_pcsp_cards)" num_usable_cards="$(wc -w <<<"$usable_cards")" if (( num_usable_cards == 1 )); then systemd-cat -t "livecdsound" printf "Only one sound card is detected\n" exit 0 fi systemd-cat -t "livecdsound" printf "multiple sound cards detected\n" for card in "${usable_cards[@]}"; do if ! is_numeric "$card"; then continue fi play_on_card "$card" /usr/share/livecd-sounds/pick-a-card.wav & done wait sleep 1 for card in "${usable_cards[@]}"; do if ! is_numeric "$card"; then continue fi play_on_card "$card" /usr/share/livecd-sounds/beep.wav if read -r -t 10; then systemd-cat -t "livecdsound" printf "Selecting %s sound card as default\n" "$card" set_default_card "$card" break fi done } if (( $# == 0 )); then echo "error: No argument passed." exit 1 fi while [[ "${1}" != "" ]]; do case ${1} in -h|--help) usage exit ;; -u|--unmute) systemd-cat -t "livecdsound" printf "Unmuting all cards" unmute_all_cards ;; -p|--pick) pick_a_card ;; *) echo "error: Unsupported argument" usage exit 1 ;; esac shift done