#!/bin/bash # SPDX-License-Identifier: Apache-2.0 # Copyright (C) 2020-present Fewtarius . /etc/profile ES_SETTINGS="/storage/.config/emulationstation/es_settings.cfg" SETTINGS_CACHE="/storage/.cache/audio" function save_state() { if [ ! -d "${SETTINGS_CACHE}" ] then mkdir -p ${SETTINGS_CACHE} fi get_audio_device >${SETTINGS_CACHE}/active_device get_es_path >${SETTINGS_CACHE}/active_path cp -f /storage/.config/asound.conf ${SETTINGS_CACHE}/asound.conf cp -f /storage/.config/asound.state ${SETTINGS_CACHE}/asound.state } function restore_state() { if [ -e "${SETTINGS_CACHE}/asound.conf" ] then cp -f ${SETTINGS_CACHE}/asound.conf /storage/.config/ cp -f ${SETTINGS_CACHE}/asound.state /storage/.config/ set-audio esset "$(cat ${SETTINGS_CACHE}/active_path)" set-audio set "$(cat ${SETTINGS_CACHE}/active_device)" rm -f ${SETTINGS_CACHE}/{asound.conf,asound.state,active_path,active_device} fi } function get_audio_device() { MYAUDIODEVICE=$(get_setting system.audiodevice) if [ ! -z "${MYAUDIODEVICE}" ] then echo ${MYAUDIODEVICE} else echo "DEFAULT (SYSTEM PROVIDED)" fi } function get_es_path() { AUDIODEVICE=$(grep AudioDevice ${ES_SETTINGS} | sed -e 's#^.*="##g' -e 's#"\ .*$##g') if [ -z "${AUDIODEVICE}" ] then echo "DEFAULT (SYSTEM PROVIDED)" else echo "${AUDIODEVICE}" fi } # Check if an audio device string corresponds to a bluetooth device function is_bluetooth() { if [[ "$1" =~ ^Device.* ]] then true return else false return fi } function list_audio_controls() { IFS="" ACTIVE_DEVICE=$(get_audio_device) if is_bluetooth "${ACTIVE_DEVICE}" then CONTROLS=$(amixer -D bluealsa controls | awk 'BEGIN {FS="'\''"} {print $2}') else CONTROLS=$(amixer scontrols | awk 'BEGIN {FS="'\''"} {print $2}') fi echo "DEFAULT (SYSTEM PROVIDED)" echo "CUSTOM (UNMANAGED)" for CONTROL in "${CONTROLS[@]}" do echo ${CONTROL} | awk '{print $1}' | grep -v -E 'Mic|Extension|Capture|Differential|Left|Right' | uniq done echo "--------" for CONTROL in "${CONTROLS[@]}" do echo ${CONTROL} done } function list_audio_devices() { echo "DEFAULT (SYSTEM PROVIDED)" echo "DEFAULT HDMI" echo "BLUETOOTH DEVICE" echo "CUSTOM (UNMANAGED)" echo "--------" BTACTIVE=$(systemctl is-active bluetooth) if [ "${BTACTIVE}" == "active" ] then BTDEVICES=$(bluetoothctl devices Paired) while read -r BTDEV do echo "${BTDEV}" done <<< "${BTDEVICES}" fi for SDEVICE in $(find /proc/asound/card*/pcm*/info) do TYPE=$(awk '/^stream:/ {print $2}' ${SDEVICE}) if [[ "${TYPE}" =~ PLAYBACK ]] then CARD=$(awk '/^card:/ {print $2}' ${SDEVICE}) DEVICE=$(awk '/^device:/ {print $2}' ${SDEVICE}) NAME=$(awk '/^name:/ {print $2}' ${SDEVICE}) echo "${NAME} (${CARD}:${DEVICE})" fi done } function set_audio_device() { SELECTION="$1" # When switching from a non-bluetooth to a bluetooth device, # store the last configuration in order to restore it on reboot. if is_bluetooth "${SELECTION}" then ACTIVE_DEVICE=$(get_audio_device) if ! is_bluetooth "${ACTIVE_DEVICE}" then save_state fi fi set_setting system.audiodevice "${SELECTION}" if [ "${SELECTION}" == "DEFAULT (SYSTEM PROVIDED)" ] then CARD="0" HWDEV="hw:${CARD},0" elif [ "${SELECTION}" == "DEFAULT HDMI" ] then CARD="0" HWDEV="hdmi" elif [ "${SELECTION}" == "BLUETOOTH DEVICE" ] then HWDEV="bluealsa" elif [ "${SELECTION}" == "CUSTOM (UNMANAGED)" ] then exit 0 elif is_bluetooth "${SELECTION}" then MAC=$(echo "${SELECTION}" | awk '/^Device/ {print $2}') # Reconnect device in case it auto-connected. # This doesn't seem necessary anymore, re-activate in case of issues. # bluetoothctl disconnect ${MAC} if bluetoothctl connect ${MAC} then HWDEV="bluealsa" fi exit 0 else if [ "${SELECTION}" == "--------" ] then exit 0 fi for SDEVICE in $(find /proc/asound/card*/pcm*/info) do TYPE=$(awk '/^stream:/ {print $2}' ${SDEVICE}) if [[ "${TYPE}" =~ PLAYBACK ]] then CARD=$(awk '/^card:/ {print $2}' ${SDEVICE}) DEVICE=$(awk '/^device:/ {print $2}' ${SDEVICE}) NAME=$(awk '/^name:/ {print $2}' ${SDEVICE}) if [ "${SELECTION}" == "${NAME} (${CARD}:${DEVICE})" ] then HWDEV="hw:${CARD},${DEVICE}" fi fi done fi if [[ "${HWDEV}" =~ ^hw ]] then cat </storage/.config/asound.conf ctl.!default { type hw card ${CARD} } pcm.!default { type plug slave.pcm "softvol" } pcm.softvol { type softvol slave.pcm "dmixer" control { name "Pre-Amp" card ${CARD} } min_dB -5.0 max_dB 20.0 resolution 6 } pcm.dmixer { type dmix ipc_key 1024 slave { pcm "${HWDEV}" period_time 0 period_size 4096 buffer_size 131072 rate 176400 } bindings { 0 0 1 1 } } EOF elif [[ "${HWDEV}" =~ bluealsa ]] then cat </storage/.config/asound.conf ctl.!default { type hw card 0 } pcm.!default { type plug slave.pcm "softvol" } pcm.softvol { type softvol slave.pcm "dmixer" control { name "Pre-Amp" card 0 } min_dB -5.0 max_dB 20.0 resolution 6 } pcm.dmixer { type asym capture.pcm cards.pcm.default playback.pcm bluealsa hint.description "Bluetooth Audio Device" } EOF else cat </storage/.config/asound.conf pcm.!default { type plug slave { pcm "softvol" } } pcm.softvol { type softvol slave.pcm "dmixer" control { name "Pre-Amp" card ${CARD} } min_dB -5.0 max_dB 20.0 resolution 6 } ctl.!default { type hw card ${CARD} } EOF fi set-audio esset $(set-audio firstcontrol) } function set_es_path() { AUDIODEVICE=${1} if [ "${AUDIODEVICE}" == "CUSTOM (UNMANAGED)" ] || \ [ "${AUDIODEVICE}" == "--------" ] then exit 0 fi AUDIOTEST=$(grep "AudioDevice" ${ES_SETTINGS} 2>/dev/null) sed -i '/^.*' ${ES_SETTINGS} echo "DEVICE_AUDIO_MIXER=\"${AUDIODEVICE}\"" >/storage/.config/profile.d/99-mixer if [ "${DEVICE_VOLUMECTL}" = true ] then systemctl restart volume fi fi } function assumed_control() { ACTIVE_DEVICE=$(get_audio_device) if is_bluetooth "${ACTIVE_DEVICE}" then ACONTROLS=$(amixer -D bluealsa controls | awk 'BEGIN {FS="'\''"} {print $2}') else ACONTROLS=$(amixer scontrols | awk 'BEGIN {FS="'\''"} {print $2}') fi echo ${ACONTROLS} | awk '{print $1}' } case $1 in controls) list_audio_controls ;; list) list_audio_devices ;; set) set_audio_device "$2" ;; esset) set_es_path "$2" ;; get) get_audio_device ;; firstcontrol) assumed_control ;; esget) get_es_path ;; save) save_state ;; restore) restore_state ;; esac