summaryrefslogtreecommitdiff
path: root/configs/releng/airootfs/usr/local/bin/livecd-sound
blob: baae0d2665e193b3259e94c9e34ec6bd38931dfd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
#!/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/livecdsound: 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 <card id>
# $2 <control>
# $3 <level>
unmute_and_set_level(){
    { [ "$3" ] &&[ "$2" ] && [ "$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 <card id>
# $2 <control>
mute_and_zero_level()
{
    { [ "$1" ] && [ "$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 <card ID>
# $2 <control>
# $3 "on" | "off"
switch_control()
{
    { [ "$3" ] && [ "$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 <card ID>
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 <card ID> | "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" < /usr/local/share/livecd-sound/asound.conf.in \
        > /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" -eq 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 [[  $# -eq 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