Advertisement
Guest User

alsa multiseat script

a guest
Apr 19th, 2014
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 8.54 KB | None | 0 0
  1. #!/bin/bash
  2.  
  3. # Copyright 2014 Dagg Stompler <daggs@gmx.com>
  4. #
  5. # This script manages sound card selection for non PulseAudio based systems.
  6. #
  7. # This program is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation, either version 2 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19.  
  20. PREFIX="ms_alsa_"
  21. INSTANCE="$(basename $0)"
  22. SERVED=0
  23. CONF_FILE_PATH="/etc/conf.d/multiseat_alsa_sound.conf"
  24. LINKS_PATH="/usr/local/bin"
  25. GROUP="users"
  26. INT_REGEX='^[0-9]+$'
  27. LABELS_DB_PATH="/usr/share/misc"
  28.  
  29. # entry 0 must be install.
  30. declare -a CONNECTORS=("${LINKS_PATH}/install" "${LINKS_PATH}/uninstall" "/etc/profile.d/update_asoundrc" "${LINKS_PATH}/list_seats")
  31. declare -a ASOUNDRC_ADDONS=("defaults.pcm.card" "defaults.ctl.card" "defaults.pcm.device" "defaults.ctl.device")
  32. declare cards_info=()
  33. declare assignments=()
  34.  
  35. populate_cards()
  36. {
  37.     OLDIFS=${IFS}
  38.     IFS=$'\n'
  39.     i=0
  40.  
  41.     for card in $(egrep -lR "^id: " /proc/asound/card* | egrep "pcm[0-9]{1,}p" | egrep -v "sub[0-9]{1,}"); do
  42.         local line=""
  43.         local folder="$(realpath $(dirname ${card})/..)"
  44.         local card_path_id="$(basename ${folder})"
  45.         local vendor=""
  46.         local device=""
  47.         local type_usb=0
  48.  
  49.         if [ -f "${folder}/usbid" ]; then
  50.             vendor=$(cat ${folder}/usbid | cut -f1 -d:)
  51.             device=$(cat ${folder}/usbid | cut -f2 -d:)
  52.             type_usb=1
  53.         else
  54.             vendor=$(cat /sys/class/sound/${card_path_id}/device/vendor | sed 's/0x//g')
  55.             device=$(cat /sys/class/sound/${card_path_id}/device/device | sed 's/0x//g')
  56.         fi
  57.         line+="${vendor};${device}"
  58.         line+=";$(grep "^name: " ${card} | sed 's/^name: //g');${type_usb}"
  59.         cards_info[${i}]=${line}
  60.         i=$((i+1))
  61.     done
  62.     IFS=${OLDIFS}
  63. }
  64.  
  65. get_card_label()
  66. {
  67.     local vid="$1"
  68.     local did="$2"
  69.     local type_usb="$3"
  70.     local db_file=${LABELS_DB_PATH}
  71.  
  72.     if [ ${type_usb} -eq 1 ]; then
  73.         db_file+="/usb.ids"
  74.     else
  75.         db_file+="/pci.ids"
  76.     fi
  77.     local sline=$(egrep -n "^[0-9a-f]{4} " ${db_file} | grep -A1 ${vid} | head -1 | cut -f 1 -d ':')
  78.     local eline=$(egrep -n "^[0-9a-f]{4} " ${db_file} | grep -A1 ${vid} | tail -1 | cut -f 1 -d ':')
  79.     local label="$(sed -n "${sline},${eline}p" ${db_file} | grep ${did} | head -1 | cut -d' ' -f2- | sed 's/^\s*//g')"
  80.  
  81.     echo "${label}"
  82. }
  83.  
  84. install_files()
  85. {
  86.     echo "installing..."
  87.     rm ${CONF_FILE_PATH} -rf
  88.     for i in $(seq 0 $((${#assignments[@]}-1))); do
  89.         echo "${assignments[${i}]}" >> ${CONF_FILE_PATH}
  90.     done
  91.  
  92.     local link_path="$(realpath $0)"
  93.     local target_path
  94.     for option in "${CONNECTORS[@]}"; do
  95.         target_path="$(dirname ${option})/${PREFIX}$(basename ${option})"
  96.         if [ ! -h "${target_path}" ]; then
  97.             echo "creating link ${target_path}..."
  98.             ln -s ${link_path} ${target_path}
  99.         fi
  100.     done
  101.     chown root:${GROUP} $0 ${CONF_FILE_PATH}
  102.     chmod 754 $0 ${CONF_FILE_PATH}
  103.     IFS=$'\n'
  104.     for entry in $(getent passwd); do
  105.         username="$(echo ${entry} | cut -d: -f1)"
  106.         if [ $(groups ${username} | grep -c users) -eq 1 ]; then
  107.             local home="$(getent passwd ${username} | cut -d: -f6)"
  108.             rm -rf ${home}/.asoundrc
  109.             for option in "${ASOUNDRC_ADDONS[@]}"; do
  110.                 echo "${option} 0" >> ${home}/.asoundrc
  111.             done
  112.         fi
  113.     done
  114.     unset IFS
  115. }
  116.  
  117. get_seat_id()
  118. {
  119.     local seat=$(echo ${DISPLAY} | sed 's/^://g')
  120.  
  121.     if ! [[ ${seat} =~ ${INT_REGEX} ]]; then
  122.         echo "invalid seat id"
  123.         exit 1
  124.     fi
  125.     echo ${seat}
  126. }
  127. #
  128. get_data_from_entry()
  129. {
  130.     local entry="$*"
  131.     local vid=$(echo ${entry} | cut -f 1 -d ';')
  132.     local did=$(echo ${entry} | cut -f 2 -d ';')
  133.     local hdr=$(echo ${entry} | cut -f 3 -d ';')
  134.     local is_type_usb=$(echo ${entry} | cut -f 4 -d ';')
  135.     local line=""
  136.  
  137.     for card in $(egrep -lR "^id: " /proc/asound/card* | egrep "pcm[0-9]{1,}p" | egrep -v "sub[0-9]{1,}"); do
  138.         local folder="$(realpath $(dirname ${card})/..)"
  139.         local card_path_id="$(basename ${folder})"
  140.         local vendor=""
  141.         local device=""
  142.         local header=""
  143.         local type_usb=0
  144.  
  145.         if [ -f "${folder}/usbid" ]; then
  146.             vendor=$(cat ${folder}/usbid | cut -f1 -d:)
  147.             device=$(cat ${folder}/usbid | cut -f2 -d:)
  148.             type_usb=1
  149.         else
  150.             vendor=$(cat /sys/class/sound/${card_path_id}/device/vendor | sed 's/0x//g')
  151.             device=$(cat /sys/class/sound/${card_path_id}/device/device | sed 's/0x//g')
  152.         fi
  153.         header="$(grep "^name: " ${card} | sed 's/^name: //g')"
  154.         if [ "${vid}" == "${vendor}" -a "${did}" == "${device}" -a  "${hdr}" == "${header}" -a ${is_type_usb} -eq ${type_usb} ]; then
  155.             line="${card}"
  156.             break
  157.         fi
  158.     done
  159.     echo "${line}"
  160.  }
  161.  
  162. get_card_id()
  163. {
  164.     local path_to_file=$(get_data_from_entry $*)
  165.  
  166.     if [ -z "${path_to_file}" ]; then
  167.         echo ""
  168.     else
  169.         echo "$(egrep "^card: " ${path_to_file} | cut -f 2 -d ':' | sed 's/ //g')"
  170.     fi
  171. }
  172.  
  173. get_dev_id()
  174. {
  175.     local path_to_file=$(get_data_from_entry $*)
  176.  
  177.     if [ -z "${path_to_file}" ]; then
  178.         echo ""
  179.     else
  180.         echo "$(egrep "^device: " ${path_to_file} | cut -f 2 -d ':' | sed 's/ //g')"
  181.     fi
  182. }
  183.  
  184. list_seats()
  185. {
  186.     IFS=$'\n'
  187.     echo "Seats sound config:"
  188.     for entry in $(cat ${CONF_FILE_PATH}); do
  189.         local key=$(echo ${entry} | cut -f1 -d=)
  190.         local value=$(echo ${entry} | cut -f2 -d=)
  191.         local vid=$(echo ${value} | cut -f 1 -d ';')
  192.         local did=$(echo ${value} | cut -f 2 -d ';')
  193.         local type_usb=$(echo ${value} | cut -f 4 -d ';')
  194.         local label="$(get_card_label ${vid} ${did} ${type_usb})"
  195.         echo -n "    - $(echo ${key} | sed 's/t/t /g')) Vendor ID ${vid}, Device ID ${did}: ${label}, type: "
  196.         if [ ${type_usb} -eq 1 ]; then
  197.             echo "usb."
  198.         else
  199.             echo "pci."
  200.         fi
  201.     done
  202.     unset IFS
  203. }
  204.  
  205. install()
  206. {
  207.     if [ "$(whoami)" != "root" ]; then
  208.         echo "this program must be run as root"
  209.         exit 1
  210.     fi
  211.     local i=0
  212.     populate_cards
  213.  
  214.     avail_enteries=("${cards_info[@]}")
  215.     local selection=""
  216.     local seat_id=0
  217.     local avail_card
  218.  
  219.     while [ 1 ]; do
  220.         echo "Available cards:"
  221.         avail_card=0
  222.         while [ ${#avail_enteries[@]} -gt ${avail_card} ]; do
  223.             local vid=$(echo ${avail_enteries[${avail_card}]} | cut -f 1 -d ';')
  224.             local did=$(echo ${avail_enteries[${avail_card}]} | cut -f 2 -d ';')
  225.             local type_usb=$(echo ${avail_enteries[${avail_card}]} | cut -f 4 -d ';')
  226.             local label="$(get_card_label ${vid} ${did} ${type_usb})"
  227.             echo $((avail_card+1)). ${vid}:${did}, Label: ${label}, type $(echo ${avail_enteries[${avail_card}]} | cut -f 3 -d ';')"
  228.             avail_card=$((${avail_card} + 1))
  229.         done
  230.  
  231.         echo -n "please select card for seat ${seat_id}, I to install or q to quit: "
  232.         read selection
  233.         if [ "${selection}" = "I" -o "${selection}" = "q" ]; then
  234.             break
  235.         fi
  236.         if ! [[ ${selection} =~ ${INT_REGEX} ]]; then
  237.             echo "invalid seletion, please select again."
  238.             continue
  239.         elif [ ${selection} -lt 1 -o ${selection} -gt ${#avail_enteries[@]} ]; then
  240.             echo "invalid seletion, please select again."
  241.             continue
  242.         fi
  243.         local pos=$((${selection} - 1))
  244.         assignments=("${assignments[@]}" "Seat${seat_id}=$(echo ${avail_enteries[${pos}]})")
  245.         seat_id=$((seat_id + 1))
  246.         local last_entry_idx=${#avail_enteries[@]}
  247.         last_entry_idx=$((last_entry_idx-1))
  248.         avail_enteries[${pos}]=${avail_enteries[${last_entry_idx}]}
  249.         unset avail_enteries[${last_entry_idx}]
  250.     done
  251.     if [ "${selection}" = "I" ]; then
  252.         install_files
  253.     fi
  254.  }
  255.  
  256. uninstall()
  257. {
  258.     for option in "${CONNECTORS[@]}"; do
  259.         target_path="$(dirname ${option})/${PREFIX}$(basename ${option})"
  260.         if [ -h "${target_path}" ]; then
  261.             rm -f ${target_path}
  262.         fi
  263.     done
  264. }
  265.  
  266. update_asoundrc()
  267. {
  268.     if [ "$(whoami)" != "root" -a -f ~/.asoundrc -a $(who | grep "${USER}" | grep -cv "pts") -eq 1 ]; then
  269.         local entry=$(grep "^Seat$(get_seat_id)=" ${CONF_FILE_PATH} | cut -f 2 -d '=')
  270.         sed -i "s/\.card [0-9]*/\.card $(get_card_id ${entry})/g" ~/.asoundrc
  271.         sed -i "s/\.device [0-9]*/\.device $(get_dev_id ${entry} )/g" ~/.asoundrc
  272.     fi
  273. }
  274.  
  275. for option in "${CONNECTORS[@]}"; do
  276.     cmd="${PREFIX}$(basename ${option})"
  277.     if [ "$(basename ${INSTANCE})" = "${cmd}" ]; then
  278.         $(basename ${option}) $*
  279.         SERVED=1
  280.     fi
  281. done
  282.  
  283. if [ ${SERVED} -eq 0 ]; then
  284.     entry=${CONNECTORS[0]}
  285.     if [ ! -h "$(dirname ${entry})/${PREFIX}$(basename ${entry})" ]; then
  286.         $(basename ${entry}) $*
  287.     else
  288.         echo -n "possible commands: "
  289.         line=""
  290.         for option in "${CONNECTORS[@]}"; do
  291.             line="${line} ${PREFIX}$(basename ${option}), "
  292.         done
  293.         echo "$(echo ${line} | sed 's/,$/./g')"
  294.     fi
  295. fi
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement