Blame SOURCES/alsa-delay

9e0ebc
#!/bin/bash
9e0ebc
9e0ebc
version=0.1.0
9e0ebc
tmpdir=$TMPDIR
9e0ebc
if test -z "$tmpdir"; then
9e0ebc
	tmpdir="/tmp"
9e0ebc
fi
9e0ebc
tmpdir=$tmpdir/alsa-delay-script
9e0ebc
9e0ebc
delay=
9e0ebc
pcard=
9e0ebc
pdev=
9e0ebc
ccard=
9e0ebc
cdev=
9e0ebc
9e0ebc
yes=
9e0ebc
quiet=
9e0ebc
clean=
9e0ebc
remove=
9e0ebc
9e0ebc
pdevice="default:%s"
9e0ebc
pdevice_set=
9e0ebc
cdevice="plughw:%s,%s,%s"
9e0ebc
pctl=
9e0ebc
cctl=
9e0ebc
one=
9e0ebc
arg=
9e0ebc
mix=
9e0ebc
pa=
9e0ebc
9e0ebc
useprocfs=yes
9e0ebc
9e0ebc
fuser_prg=fuser
9e0ebc
insmod_prg=insmod
9e0ebc
rmmod_prg=rmmod
9e0ebc
lsmod_prg=lsmod
9e0ebc
modprobe_prg=modprobe
9e0ebc
chkconfig_prg=chkconfig
9e0ebc
systemctl_prg=systemctl
9e0ebc
pidof_prg=pidof
9e0ebc
alsaloop_prg=alsaloop
9e0ebc
amixer_prg=amixer
9e0ebc
test -x /sbin/fuser && fuser_prg=/sbin/fuser
9e0ebc
test -x /sbin/insmod && insmod_prg=/sbin/insmod
9e0ebc
test -x /sbin/rmmod && rmmod_prg=/sbin/rmmod
9e0ebc
test -x /sbin/lsmod && lsmod_prg=/sbin/lsmod
9e0ebc
test -x /sbin/modprobe && modprobe_prg=/sbin/modprobe
9e0ebc
test -x /sbin/chkconfig && chkconfig_prg=/sbin/chkconfig
9e0ebc
test -x /bin/systemctl && systemctl_prg=/bin/systemctl
9e0ebc
test -x /sbin/pidof && pidof_prg=/sbin/pidof
9e0ebc
test -x /usr/bin/alsaloop && alsaloop_prg=/usr/bin/alsaloop
9e0ebc
test -x /usr/local/bin/alsaloop && alsaloop_prg=/usr/local/bin/alsaloop
9e0ebc
test -x /usr/bin/amixer && amixer_prg=/usr/bin/amixer
9e0ebc
9e0ebc
modprobeconf=/etc/modprobe.d/alsa.conf
9e0ebc
test -r /etc/modprobe.conf && modprobeconf=/etc/modprobe.conf && useprocfs=""
9e0ebc
alsaloopconf=/etc/alsaloop.conf
9e0ebc
9e0ebc
test -r modprobe.work && modprobeconf=modprobe.work
9e0ebc
test -r modprobe.work && alsaloopconf=alsaloop.conf
9e0ebc
9e0ebc
usage() {
9e0ebc
	echo "Usage: $0 [OPTION]... <requested_delay_in_ms> [<output_card>[,<device>]]"
9e0ebc
	cat <
9e0ebc
9e0ebc
This is a delay utility version $version. The snd-aloop ALSA driver is
9e0ebc
used to send all PCM streams back to the user space and the alsaloop
9e0ebc
utility is used to send this stream to a real hardware.
9e0ebc
9e0ebc
<output_card> is ALSA card index (number) or string card identifier
9e0ebc
<device> is ALSA device number
9e0ebc
9e0ebc
Use 'aplay -l' to list available cards and devices.
9e0ebc
9e0ebc
Operation modes:
9e0ebc
  -h, --help		print this help, then exit
9e0ebc
  -q, --quiet		quiet mode
9e0ebc
  -y, --yes		do not ask any questions - answer is always yes
9e0ebc
  -c, --clean           clean temporary directory and exit
9e0ebc
  -r, --remove          remove the alsa-delay config modifications and exit
9e0ebc
  --tmpdir=<DIR>        set temporary directory
9e0ebc
Alsaloop options:
9e0ebc
  --pdevice=<DEV>       force playback device
9e0ebc
  --cdevice=<DEV>       force capture device
9e0ebc
  --pctl=<DEV>          force playback ctl device
9e0ebc
  --cctl=<DEV>          force capture ctl device
9e0ebc
  --one=<ARG>           pass this argument to last thread
9e0ebc
  --arg=<ARG>           pass this argument to all threads
9e0ebc
  --mix=<ARG>           redirect ALSA mixer controls to OSS mixer
9e0ebc
			(default is Master)
9e0ebc
  --pa			Redirect PA to alsaloop
9e0ebc
9e0ebc
Note: For devices, the string %s is replaced with the card index
9e0ebc
      and second string %s is replaced with the device index
9e0ebc
      and third string %s is replaced the substream index (0-7).
9e0ebc
      Example: hw:%s,%s,%s    (card, device, substream)
9e0ebc
EOF
9e0ebc
}
9e0ebc
9e0ebc
while :
9e0ebc
do
9e0ebc
	case "$1" in
9e0ebc
	-h|--help)
9e0ebc
		usage
9e0ebc
		exit 0
9e0ebc
		;;
9e0ebc
	-q|--quiet)
9e0ebc
		quiet=true ;;
9e0ebc
	-y|--yes)
9e0ebc
		yes=true ;;
9e0ebc
	-c|--clean)
9e0ebc
		clean="full" ;;
9e0ebc
	-r|--remove)
9e0ebc
		remove="full" ;;
9e0ebc
	--tmpdir*)
9e0ebc
		case "$#,$1" in
9e0ebc
		*,*=*)
9e0ebc
			tmpdir=`expr "z$1" : 'z-[^=]*=\(.*\)'` ;;
9e0ebc
		1,*)
9e0ebc
			usage ;;
9e0ebc
		*)
9e0ebc
			tmpdir="$2"
9e0ebc
			shift ;;
9e0ebc
		esac
9e0ebc
		tmpdir="$tmpdir/alsa-compile-script"
9e0ebc
		;;
9e0ebc
	--pdevice*)
9e0ebc
		case "$#,$1" in
9e0ebc
		*,*=*)
9e0ebc
			pdevice=`expr "z$1" : 'z-[^=]*=\(.*\)'`
9e0ebc
			pdevice_set=yes ;;
9e0ebc
		1,*)
9e0ebc
			usage ;;
9e0ebc
		*)
9e0ebc
			pdevice="$2"
9e0ebc
			pdevice_set=yes
9e0ebc
			shift ;;
9e0ebc
		esac
9e0ebc
		;;
9e0ebc
	--cdevice*)
9e0ebc
		case "$#,$1" in
9e0ebc
		*,*=*)
9e0ebc
			cdevice=`expr "z$1" : 'z-[^=]*=\(.*\)'` ;;
9e0ebc
		1,*)
9e0ebc
			usage ;;
9e0ebc
		*)
9e0ebc
			cdevice="$2"
9e0ebc
			shift ;;
9e0ebc
		esac
9e0ebc
		;;
9e0ebc
	--pctl*)
9e0ebc
		case "$#,$1" in
9e0ebc
		*,*=*)
9e0ebc
			pctl=`expr "z$1" : 'z-[^=]*=\(.*\)'` ;;
9e0ebc
		1,*)
9e0ebc
			usage ;;
9e0ebc
		*)
9e0ebc
			pctl="$2"
9e0ebc
			shift ;;
9e0ebc
		esac
9e0ebc
		;;
9e0ebc
	--cctl*)
9e0ebc
		case "$#,$1" in
9e0ebc
		*,*=*)
9e0ebc
			cctl=`expr "z$1" : 'z-[^=]*=\(.*\)'` ;;
9e0ebc
		1,*)
9e0ebc
			usage ;;
9e0ebc
		*)
9e0ebc
			cctl="$2"
9e0ebc
			shift ;;
9e0ebc
		esac
9e0ebc
		;;
9e0ebc
	--one*)
9e0ebc
		case "$#,$1" in
9e0ebc
		*,*=*)
9e0ebc
			one1=`expr "z$1" : 'z-[^=]*=\(.*\)'` ;;
9e0ebc
		1,*)
9e0ebc
			usage ;;
9e0ebc
		*)
9e0ebc
			one1="$2"
9e0ebc
			shift ;;
9e0ebc
		esac
9e0ebc
		one="$one $one1"
9e0ebc
		;;
9e0ebc
	--arg*)
9e0ebc
		case "$#,$1" in
9e0ebc
		*,*=*)
9e0ebc
			arg1=`expr "z$1" : 'z-[^=]*=\(.*\)'` ;;
9e0ebc
		1,*)
9e0ebc
			usage ;;
9e0ebc
		*)
9e0ebc
			arg1="$2"
9e0ebc
			shift ;;
9e0ebc
		esac
9e0ebc
		arg="$arg $arg1"
9e0ebc
		;;
9e0ebc
	--mix*)
9e0ebc
		case "$#,$1" in
9e0ebc
		*,*=*)
9e0ebc
			mix=`expr "z$1" : 'z-[^=]*=\(.*\)'` ;;
9e0ebc
		1,*)
9e0ebc
			usage ;;
9e0ebc
		*)
9e0ebc
			mix="$2"
9e0ebc
			shift ;;
9e0ebc
		esac
9e0ebc
		arg="$arg $arg1"
9e0ebc
		;;
9e0ebc
	--pa)
9e0ebc
		pa=true
9e0ebc
		;;
9e0ebc
	*)
9e0ebc
		if test -n "$1"; then
9e0ebc
			ok=
9e0ebc
			if test -z "$delay"; then
9e0ebc
				delay="$1"
9e0ebc
				if test "$delay" -lt 1000; then
9e0ebc
					delay=$[$delay * 1000]
9e0ebc
				fi
9e0ebc
				ok=true
9e0ebc
			fi
9e0ebc
			if test -z "$ok" -a -z "$pcard"; then
9e0ebc
				pcard="$1"
9e0ebc
				ok=true
9e0ebc
			fi
9e0ebc
			if test -z "$ok"; then
9e0ebc
				echo "Unknown parameter '$1'"
9e0ebc
				break
9e0ebc
			fi
9e0ebc
		else
9e0ebc
			break
9e0ebc
		fi
9e0ebc
		;;
9e0ebc
	esac
9e0ebc
	shift
9e0ebc
done
9e0ebc
9e0ebc
test -z "$pdevice_set" -a -n "$pa" && pdevice="plug:dmix:%s"
9e0ebc
test -z "$delay" && delay="50000"
9e0ebc
test -z "$pcard" && pcard="1"
9e0ebc
pdev=$(echo $pcard | cut -s -d , -f 2)
9e0ebc
pcard=$(echo $pcard | cut -d , -f 1)
9e0ebc
test -z "$pdev" && pdev="0"
9e0ebc
test -z "$ccard" && ccard="Loopback,1"
9e0ebc
cdev=$(echo $ccard | cut -s -d , -f 2)
9e0ebc
ccard=$(echo $ccard | cut -d , -f 1)
9e0ebc
test -z "$cdev" && cdev="0"
9e0ebc
9e0ebc
# Echo "true" or "false", depending on $yes and user response to prompt
9e0ebc
# $1 is prompt message
9e0ebc
question_bool() {
9e0ebc
	if test "$yes" = "yes"; then
9e0ebc
		echo "true"
9e0ebc
	else
9e0ebc
		echo >&2 -n "$1 (Y/ ) "
9e0ebc
		read i
9e0ebc
		local i=${i:0:1}
9e0ebc
		if test "$i" = "Y" -o "$i" = "y"; then
9e0ebc
			echo "true"
9e0ebc
		else
9e0ebc
			echo "false"
9e0ebc
		fi
9e0ebc
	fi
9e0ebc
}
9e0ebc
9e0ebc
# Safe exit
9e0ebc
safe_exit() {
9e0ebc
	if test -r /etc/pulse/client.conf ; then
9e0ebc
		if grep "# alsa-delay-line-to-be-removed-1234" /etc/pulse/client.conf 2> /dev/null > /dev/null ; then
9e0ebc
			grep -v alsa-delay-line-to-be-removed-1234 /etc/pulse/client.conf > /etc/pulse/client.conf.new
9e0ebc
			if test -s /etc/pulse/client.conf.new; then
9e0ebc
				mv /etc/pulse/client.conf.new /etc/pulse/client.conf
9e0ebc
			fi
9e0ebc
		fi
9e0ebc
	fi
9e0ebc
	exit $1
9e0ebc
}
9e0ebc
9e0ebc
# Log and execute $@ and check success
9e0ebc
do_cmd() {
9e0ebc
	if test -z "$quiet"; then
9e0ebc
		echo "> $@"
9e0ebc
	fi
9e0ebc
	$@ || safe_exit 1
9e0ebc
}
9e0ebc
9e0ebc
# Cache or restore $protocol and $url and $package in $tmpdir
9e0ebc
check_environment() {
9e0ebc
	if ! test -d $tmpdir ; then
9e0ebc
		mkdir -p $tmpdir
9e0ebc
		if ! test -d $tmpdir; then
9e0ebc
			echo >&2 "Unable to create directory $tmpdir."
9e0ebc
			exit 1
9e0ebc
		fi
9e0ebc
	fi
9e0ebc
	echo "Using temporary tree: $tmpdir"
9e0ebc
	test -x /bin/depmod && depmodbin=/bin/depmod
9e0ebc
	test -x /sbin/depmod && depmodbin=/sbin/depmod
9e0ebc
	if test -z "$depmodbin"; then
9e0ebc
		echo >&2 "Unable to find depmod utility."
9e0ebc
		exit 1
9e0ebc
	fi
9e0ebc
	test -x /bin/modinfo && modinfobin=/bin/modinfo
9e0ebc
	test -x /sbin/modinfo && modinfobin=/sbin/modinfo
9e0ebc
	if test -z "$modinfobin"; then
9e0ebc
		echo >&2 "Unable to find modinfo utility."
9e0ebc
		exit 1
9e0ebc
	fi
9e0ebc
}
9e0ebc
9e0ebc
# Kill processes currently accessing the audio devices
9e0ebc
kill_audio_apps() {
9e0ebc
	local pids0=$($fuser_prg /dev/snd/* 2> /dev/null)
9e0ebc
	local pids1=$($fuser_prg /dev/mixer* 2> /dev/null)
9e0ebc
	local pids2=$($fuser_prg /dev/sequencer* 2> /dev/null)
9e0ebc
	local pids=
9e0ebc
	for pid in $pids0 $pids1 $pids2; do
9e0ebc
		local pids="$pids $pid"
9e0ebc
	done
9e0ebc
	if ! test -z "$pids"; then
9e0ebc
		echo
9e0ebc
		echo "WARNING! An audio application uses ALSA driver:"
9e0ebc
		echo
9e0ebc
		for pid in $pids; do
9e0ebc
			ps --no-headers -p $pids || safe_exit 1
9e0ebc
		done
9e0ebc
		echo
9e0ebc
		if test $(question_bool "Would you like to kill these apps?") = "true"; then
9e0ebc
			if test -w /etc/pulse/client.conf ; then
9e0ebc
				echo "autospawn = no # alsa-delay-line-to-be-removed-1234" >> /etc/pulse/client.conf
9e0ebc
			fi
9e0ebc
			for pid in $pids; do
9e0ebc
				do_cmd kill $pid
9e0ebc
			done
9e0ebc
			sleep 2
9e0ebc
			local killed=
9e0ebc
			for pid in $pids; do
9e0ebc
				local a=$(ps --no-headers -p $pids)
9e0ebc
				if test -n "$a"; then
9e0ebc
					do_cmd kill -9 $pid
9e0ebc
					local killed="true"
9e0ebc
				fi
9e0ebc
			done
9e0ebc
			if test "$killed" = "true"; then
9e0ebc
				sleep 2
9e0ebc
				for pid in $pids; do
9e0ebc
					local a=$(ps --no-headers -p $pids)
9e0ebc
					if test -n "$a"; then
9e0ebc
						echo >&2 "Unable to kill application:"
9e0ebc
						echo >&2 "  $a"
9e0ebc
						safe_exit 1
9e0ebc
					fi
9e0ebc
				done
9e0ebc
			fi
9e0ebc
		else
9e0ebc
			echo >&2 "Cannot continue with running audio applications."
9e0ebc
			safe_exit 1
9e0ebc
		fi
9e0ebc
	fi
9e0ebc
}
9e0ebc
9e0ebc
# Echo the list of configured sound modules
9e0ebc
configured_modules() {
9e0ebc
	if test -z "$useprocfs"; then
9e0ebc
		cat $modprobeconf | grep -E "^alias snd-card-" | cut -d ' ' -f 3
9e0ebc
	else
9e0ebc
		cat /proc/asound/modules | colrm 1 3
9e0ebc
	fi
9e0ebc
}
9e0ebc
9e0ebc
# Echo the list of loaded sound modules
9e0ebc
current_modules() {
9e0ebc
	$lsmod_prg | cut -d ' ' -f 1 | grep -E "^(snd[_-])"
9e0ebc
}
9e0ebc
9e0ebc
# The loopback kernel driver detection
9e0ebc
aloop_present() {
9e0ebc
	if test -r /proc/asound/card0/id; then
9e0ebc
		local id=$(cat /proc/asound/card0/id)
9e0ebc
	else
9e0ebc
		local id=""
9e0ebc
	fi
9e0ebc
	if test "$id" = "Loopback"; then
9e0ebc
		echo "yes"
9e0ebc
	fi
9e0ebc
}
9e0ebc
9e0ebc
# Remove kernel modules, using two phases
9e0ebc
# $@ is module names
9e0ebc
my_rmmod() {
9e0ebc
	local phase2=
9e0ebc
	while test -n "$1"; do
9e0ebc
		if ! $rmmod_prg $1 2> /dev/null > /dev/null; then
9e0ebc
			local phase2="$phase2 $1"
9e0ebc
		else
9e0ebc
			echo "> rmmod $1"
9e0ebc
		fi
9e0ebc
		shift
9e0ebc
	done
9e0ebc
	for mod in $phase2; do
9e0ebc
		echo "> rmmod $mod"
9e0ebc
		if ! $rmmod_prg $mod ; then
9e0ebc
			echo >&2 "Unable to remove kernel module $mod."
9e0ebc
			safe_exit 1
9e0ebc
		fi
9e0ebc
	done
9e0ebc
}
9e0ebc
9e0ebc
# Reload kernel modules
9e0ebc
kernel_modules() {
9e0ebc
	kill_audio_apps
9e0ebc
	if test "$1" = "unload"; then
9e0ebc
		local present=$(aloop_present)
9e0ebc
		if test "$present" = "yes"; then
9e0ebc
			if ! $rmmod_prg snd-aloop; then
9e0ebc
				echo >&2 "Unable to remove kernel module snd-aloop."
9e0ebc
				safe_exit 1
9e0ebc
			fi
9e0ebc
		fi
9e0ebc
	fi
9e0ebc
	local curmods=$(current_modules)
9e0ebc
	local usermods=$(configured_modules)
9e0ebc
	my_rmmod $curmods
9e0ebc
	$modprobe_prg soundcore || safe_exit 1
9e0ebc
	if test "$1" = "load"; then
9e0ebc
		if ! $modprobe_prg snd-aloop; then
9e0ebc
			echo >&2 "Unable to install kernel module snd-aloop."
9e0ebc
			safe_exit 1
9e0ebc
		fi
9e0ebc
	fi
9e0ebc
	for mod in $usermods; do
9e0ebc
		if ! $modprobe_prg $mod; then
9e0ebc
			echo >&2 "Unable to install kernel module $mod."
9e0ebc
			safe_exit 1
9e0ebc
		fi
9e0ebc
	done
9e0ebc
	echo "Kernel modules ready:"
9e0ebc
	cat /proc/asound/cards
9e0ebc
	sleep 0.5
9e0ebc
}
9e0ebc
9e0ebc
# If $package is alsa-driver then remove current modules
9e0ebc
kernel_modules_remove() {
9e0ebc
	local curmods=$(current_modules)
9e0ebc
	if test -z "$curmods"; then
9e0ebc
		echo "No ALSA kernel modules to remove."
9e0ebc
		safe_exit 0
9e0ebc
	fi
9e0ebc
	kill_audio_apps
9e0ebc
	my_rmmod $curmods
9e0ebc
	echo "ALSA kernel modules removed."
9e0ebc
}
9e0ebc
9e0ebc
function clean() {
9e0ebc
	echo -n "Removing tree $tmpdir:"
9e0ebc
	if test -d "$tmpdir"; then
9e0ebc
		if ! rm -rf "$tmpdir"; then
9e0ebc
			echo " failed"
9e0ebc
			safe_exit 1
9e0ebc
		fi
9e0ebc
	fi
9e0ebc
	echo " success"
9e0ebc
}
9e0ebc
9e0ebc
function reindex_modprobe_conf() {
9e0ebc
	if test -z "$useprocfs"; then
9e0ebc
		cat > $tmpdir/run.awk <
9e0ebc
function rewrite_line(line,   res, c, i, j) {
9e0ebc
	split(line, l, " ")
9e0ebc
	if (l[1] == "alias") {
9e0ebc
		printf(l[1])
9e0ebc
		c = int(substr(l[2], 9)) + 1
9e0ebc
		printf(" snd-card-%i %s\n", c, l[3])
9e0ebc
	} else if (l[1] == "options") {
9e0ebc
		printf(l[1])
9e0ebc
		for (i = 2; i <= length(l); i++) {
9e0ebc
			c = substr(l[i], 0, 9)
9e0ebc
			if (c == "snd-card-") {
9e0ebc
				c = int(substr(l[i], 9)) + 1
9e0ebc
				printf(" snd-card-%i", c)
9e0ebc
				continue
9e0ebc
			}
9e0ebc
			c = substr(l[i], 0, 6)
9e0ebc
			if (c == "index=") {
9e0ebc
				printf(" index=")
9e0ebc
				c = substr(l[i], 6)
9e0ebc
				split(c, y, ",")
9e0ebc
				for (j = 1; j <= length(y); j++) {
9e0ebc
					c = int(y[j]) + 1
9e0ebc
					if (j > 1)
9e0ebc
						printf(",")
9e0ebc
					printf("%i", c)
9e0ebc
				}
9e0ebc
				continue
9e0ebc
			}
9e0ebc
			printf(" %s", l[i])
9e0ebc
		}
9e0ebc
		printf("\n")
9e0ebc
	} else if (l[1] == "remove") {
9e0ebc
		printf(l[1])
9e0ebc
		flag = 0
9e0ebc
		for (i = 2; i <= length(l); i++) {
9e0ebc
			if (l[i] == "/usr/sbin/alsactl" || l[i] == "store") {
9e0ebc
				flag++;
9e0ebc
				printf(" %s", l[i]);
9e0ebc
				continue;
9e0ebc
			}
9e0ebc
			if (flag == 2) {
9e0ebc
				c = int(l[i]) + 1;
9e0ebc
				printf(" %i", c);
9e0ebc
				flag = 0;
9e0ebc
				continue;
9e0ebc
			}
9e0ebc
			flag = 0;
9e0ebc
			printf(" %s", l[i]);
9e0ebc
		}
9e0ebc
		printf("\n")
9e0ebc
	} else {
9e0ebc
		print line
9e0ebc
	}
9e0ebc
}
9e0ebc
9e0ebc
BEGIN			{ aloop=0; }
9e0ebc
/alias snd-card-0 snd-aloop/ { aloop=1; next; }
9e0ebc
/options snd-card-0 index=0/ { if (aloop) next; }
9e0ebc
/options snd-aloop/	{ next; }
9e0ebc
/alias snd-card-/	{ rewrite_line(\$0); next; }
9e0ebc
/options snd-/		{ rewrite_line(\$0); next; }
9e0ebc
/remove snd-/		{ rewrite_line(\$0); next; }
9e0ebc
			{ print \$0; }
9e0ebc
EOF
9e0ebc
		cat $modprobeconf | awk -f $tmpdir/run.awk > $modprobeconf.new
9e0ebc
		rm $tmpdir/run.awk || safe_exit 1
9e0ebc
	else
9e0ebc
		local index=1
9e0ebc
		echo -n "" > $modprobeconf.new
9e0ebc
		declare -a modules printed
9e0ebc
		for mod in $(cat /proc/asound/modules | grep -Ev "^2[6789]" | colrm 1 3); do
9e0ebc
			if test "$mod" != "snd_aloop" -a "$mod" != "snd-aloop"; then
9e0ebc
				if test -z ${modules[$mod]}; then
9e0ebc
					modules[$mod]=$index
9e0ebc
				else
9e0ebc
					modules[$mod]="${modules[mod]},$index"
9e0ebc
				fi
9e0ebc
				echo "alias snd-card-$index $mod" >> $modprobeconf.new
9e0ebc
				echo "options snd-card-$index index=$index" >> $modprobeconf.new
9e0ebc
			fi
9e0ebc
			index=$(expr $index + 1)
9e0ebc
		done
9e0ebc
		for mod in $(cat /proc/asound/modules | grep -Ev "^2[6789]" | colrm 1 3); do
9e0ebc
			if test "$mod" != "snd_aloop" -a "$mod" != "snd-aloop"; then
9e0ebc
				if test -z ${printed[$mod]}; then
9e0ebc
					echo "options $mod index=${modules[$mod]}" >> $modprobeconf.new
9e0ebc
					printed[$mod]=yes
9e0ebc
				fi
9e0ebc
			fi
9e0ebc
		done
9e0ebc
	fi
9e0ebc
cat >> $modprobeconf.new <
9e0ebc
alias snd-card-0 snd-aloop
9e0ebc
options snd-card-0 index=0
9e0ebc
options snd-aloop index=0
9e0ebc
EOF
9e0ebc
	if ! test -f $modprobeconf.alsa-delay.save ; then
9e0ebc
		if ! test -f $modprobeconf ; then
9e0ebc
			touch $modprobeconf.alsa-delay.save
9e0ebc
		else
9e0ebc
			cp $modprobeconf $modprobeconf.alsa-delay.save
9e0ebc
		fi
9e0ebc
	fi
9e0ebc
	mv $modprobeconf.new $modprobeconf || safe_exit 1
9e0ebc
}
9e0ebc
9e0ebc
function modify_modprobe_conf() {
9e0ebc
	local check=$(cat $modprobeconf 2> /dev/null | grep -E "^alias snd-card-0 snd-aloop")
9e0ebc
	local present=$(aloop_present)
9e0ebc
	if test -n "$check"; then
9e0ebc
		echo "Module snd-aloop is already installed."
9e0ebc
		if ! test "$present" = "yes"; then
9e0ebc
			kernel_modules load
9e0ebc
		fi
9e0ebc
	else
9e0ebc
		reindex_modprobe_conf
9e0ebc
		if ! test "$present" = "yes"; then
9e0ebc
			kernel_modules load
9e0ebc
		else
9e0ebc
			kernel_modules
9e0ebc
		fi
9e0ebc
	fi
9e0ebc
}
9e0ebc
9e0ebc
function myprintf() {
9e0ebc
	local cnt=$(echo "$1" | grep -o "%" | wc -l)
9e0ebc
	if test $cnt -eq 1; then
9e0ebc
		printf "$1" "$2"
9e0ebc
	else if test $cnt -eq 2; then
9e0ebc
		printf "$1" "$2" "$3"
9e0ebc
	else
9e0ebc
		printf "$1" "$2" "$3" "$4"
9e0ebc
	fi
9e0ebc
	fi
9e0ebc
}
9e0ebc
9e0ebc
function check_ctl_name() {
9e0ebc
	$amixer_prg -D "$1" contents | grep "name='$2'"
9e0ebc
}
9e0ebc
9e0ebc
function check_oss_mixer() {
9e0ebc
	grep ": mixer" /proc/asound/oss/devices
9e0ebc
}
9e0ebc
9e0ebc
function get_card_id() {
9e0ebc
	$amixer_prg -D "$1" info | head -1 | cut -d '/' -f 1 | cut -d ' ' -f 3- | awk '{ print substr($0, 2, length($0)-2) }'
9e0ebc
}
9e0ebc
9e0ebc
function generate_alsaloop_line() {
9e0ebc
	local file="$1"
9e0ebc
	local idx="$2"
9e0ebc
	local carg=$(myprintf "$cdevice" $ccard $cdev $idx)
9e0ebc
	local parg=$(myprintf "$pdevice" $pcard $pdev $idx)
9e0ebc
	local res="-C $carg -P $parg -T $idx -t $delay"
9e0ebc
	if test -n "$cctl"; then
9e0ebc
		local carg=$(myprintf "$cctl" $pcard $cdev $idx)
9e0ebc
		local res="$res -Y $carg"
9e0ebc
	fi
9e0ebc
	if test -n "$pctl"; then
9e0ebc
		local parg=$(myprintf "$pctl" $pcard $pdev $idx)
9e0ebc
		local res="$res -X $parg"
9e0ebc
	fi
9e0ebc
	if test -n "$arg"; then
9e0ebc
		local res="$res $arg"
9e0ebc
	fi
9e0ebc
	if test $idx -eq 7; then
9e0ebc
		if test -n "$one"; then
9e0ebc
			local res="$res $one"
9e0ebc
		fi
9e0ebc
		if test -z "$pctl"; then
9e0ebc
			local res="$res -X hw:$pcard"
9e0ebc
		fi
9e0ebc
		local mymix="$mix"
9e0ebc
		if test -z "$mymix"; then
9e0ebc
			local mymix="Master"
9e0ebc
			for mymix in Master "Master Mono" Headphone Headphone2 PCM Speaker \
9e0ebc
				     "Desktop Speaker" Beep Front Rear Center LFE Side \
9e0ebc
				     Surround ; do
9e0ebc
				local check=$(check_ctl_name hw:$pcard "$mymix Playback Switch")
9e0ebc
				if test -n "$check"; then
9e0ebc
					local res="$res -m \"name='$mymix Playback Switch'\""
9e0ebc
				fi
9e0ebc
				local check=$(check_ctl_name hw:$pcard "$mymix Playback Volume")
9e0ebc
				if test -n "$check"; then
9e0ebc
					local res="$res -m \"name='$mymix Playback Volume'\""
9e0ebc
				fi
9e0ebc
			done
9e0ebc
		else
9e0ebc
			local check=$(check_ctl_name hw:$pcard "$mymix Playback Switch")
9e0ebc
			if test -n "$check"; then
9e0ebc
				local res="$res -m \"name='$mymix Playback Switch'\""
9e0ebc
			fi
9e0ebc
			local check=$(check_ctl_name hw:$pcard "$mymix Playback Volume")
9e0ebc
			if test -n "$check"; then
9e0ebc
				local res="$res -m \"name='$mymix Playback Volume'\""
9e0ebc
			fi
9e0ebc
		fi
9e0ebc
		local check=$(check_oss_mixer)
9e0ebc
		if test -n "$check"; then
9e0ebc
			local res="$res -O \"$mymix@VOLUME\""
9e0ebc
		fi
9e0ebc
	fi
9e0ebc
	echo $res >> $file
9e0ebc
}
9e0ebc
9e0ebc
function generate_alsaloop_conf() {
9e0ebc
	local idx=0
9e0ebc
	rm -f $alsaloopconf.new
9e0ebc
	while test $idx -lt 8; do
9e0ebc
		generate_alsaloop_line $alsaloopconf.new $idx
9e0ebc
		idx=$(expr $idx + 1)
9e0ebc
	done
9e0ebc
	mv $alsaloopconf.new $alsaloopconf || safe_exit 1
9e0ebc
}
9e0ebc
9e0ebc
function kill_alsaloop() {
9e0ebc
	local pid=$($pidof_prg alsaloop)
9e0ebc
	if test -n "$pid"; then
9e0ebc
		echo "Killing alsaloop..."
9e0ebc
	fi
9e0ebc
	while test -n "$pid"; do
9e0ebc
		kill $pid
9e0ebc
		sleep 0.01
9e0ebc
		pid=$($pidof_prg alsaloop)
9e0ebc
	done
9e0ebc
}
9e0ebc
9e0ebc
function restart_alsaloop() {
9e0ebc
	echo "Restarting alsaloop: delay $delay us."
9e0ebc
	if test -d /etc/systemd/system; then
9e0ebc
		systemctl start alsaloop.service
9e0ebc
	else
9e0ebc
		/etc/init.d/alsaloop start
9e0ebc
	fi
9e0ebc
	sleep 0.4
9e0ebc
	local pid=$($pidof_prg alsaloop)
9e0ebc
	if test -z "$pid"; then
9e0ebc
		echo "ERROR: Not started, check /var/log/messages for details"
9e0ebc
	else
9e0ebc
		if test -d /etc/systemd/system; then
9e0ebc
			systemctl status alsaloop.service
9e0ebc
		else
9e0ebc
			ps -p $pid
9e0ebc
		fi
9e0ebc
	fi
9e0ebc
}
9e0ebc
9e0ebc
function create_systemd_service() {
9e0ebc
	if test -r /etc/systemd/system/alsaloop.service; then
9e0ebc
		echo "/etc/systemd/system/alsaloop.service exists"
9e0ebc
	else
9e0ebc
		cat >> /etc/systemd/system/alsaloop.service <
9e0ebc
# This file was created by the alsa-delay utility
9e0ebc
9e0ebc
[Unit]
9e0ebc
Description=The alsaloop daemon service
9e0ebc
After=alsa-restore.service
9e0ebc
Before=shutdown.target
9e0ebc
Conflicts=shutdown.target
9e0ebc
9e0ebc
[Service]
9e0ebc
Type=simple
9e0ebc
ExecPre=-/sbin/modprobe snd-aloop
9e0ebc
ExecStart=-/usr/bin/alsaloop --syslog --config $alsaloopconf
9e0ebc
EOF
9e0ebc
		ln -sf ../alsaloop.service /etc/systemd/system/basic.target.wants/alsaloop.service
9e0ebc
	fi
9e0ebc
}
9e0ebc
9e0ebc
function create_initd() {
9e0ebc
	if test -x /etc/init.d/alsaloop; then
9e0ebc
		echo "/etc/init.d/alsaloop exists"
9e0ebc
	else
9e0ebc
		cat >> /etc/init.d/alsaloop <
9e0ebc
#! /bin/sh
9e0ebc
9e0ebc
# alsaloop init file
9e0ebc
# Copyright (C) 2010 Jaroslav Kysela <jkysela@redhat.com>
9e0ebc
9e0ebc
# For RedHat and cousins:
9e0ebc
# chkconfig: 2345 99 01
9e0ebc
# description: Start alsaloop daemon
9e0ebc
# processname: alsaloop
9e0ebc
9e0ebc
### BEGIN INIT INFO
9e0ebc
# Provides: alsaloop
9e0ebc
# Required-Start: \$local_fs
9e0ebc
# Required-Stop: \$local_fs
9e0ebc
# Should-Start:
9e0ebc
# Short-Description: ALSALOOP
9e0ebc
# Description: ALSALOOP
9e0ebc
### END INIT INFO
9e0ebc
9e0ebc
# This program is free software; you can redistribute it and/or modify it
9e0ebc
# under the terms of the GNU General Public License as published by the Free
9e0ebc
# Software Foundation; either version 2, or (at your option) any later
9e0ebc
# version.
9e0ebc
# You should have received a copy of the GNU General Public License (for
9e0ebc
# example COPYING); if not, write to the Free Software Foundation, Inc., 675
9e0ebc
# Mass Ave, Cambridge, MA 02139, USA.
9e0ebc
# This code was originally developed as a Senior Thesis by Michael Cornwell
9e0ebc
# at the Concurrent Systems Laboratory (now part of the Storage Systems
9e0ebc
# Research Center), Jack Baskin School of Engineering, University of
9e0ebc
# California, Santa Cruz. http://ssrc.soe.ucsc.edu/.
9e0ebc
9e0ebc
alsaloop_opts="--daemonize --workaround serialopen --config $alsaloopconf"
9e0ebc
9e0ebc
ALSALOOP_BIN=/usr/bin/alsaloop
9e0ebc
test -x /usr/local/bin/alsaloop && ALSALOOP_BIN=/usr/local/bin/alsaloop
9e0ebc
9e0ebc
# Source function library
9e0ebc
. /etc/rc.d/init.d/functions
9e0ebc
9e0ebc
RETVAL=0
9e0ebc
prog=alsaloop
9e0ebc
pidfile=/var/lock/subsys/alsaloop
9e0ebc
9e0ebc
start()
9e0ebc
{
9e0ebc
	modprobe snd-aloop
9e0ebc
	echo -n \$"Starting \$prog: "
9e0ebc
	daemon \$ALSALOOP_BIN \$alsaloop_opts
9e0ebc
	RETVAL=\$?
9e0ebc
	echo
9e0ebc
	[ \$RETVAL = 0 ] && touch \$pidfile
9e0ebc
	return \$RETVAL
9e0ebc
}
9e0ebc
9e0ebc
stop()
9e0ebc
{
9e0ebc
	echo -n \$"Shutting down \$prog: "
9e0ebc
	killproc \$ALSALOOP_BIN
9e0ebc
	RETVAL=\$?
9e0ebc
	echo
9e0ebc
	rm -f \$pidfile
9e0ebc
	return \$RETVAL
9e0ebc
}
9e0ebc
9e0ebc
case "\$1" in
9e0ebc
	start)
9e0ebc
		start
9e0ebc
		;;
9e0ebc
	stop)
9e0ebc
		stop
9e0ebc
		;;
9e0ebc
	restart)
9e0ebc
		stop
9e0ebc
		start
9e0ebc
		;;
9e0ebc
	try-restart)
9e0ebc
		if [ -f \$pidfile ]; then
9e0ebc
			stop
9e0ebc
			start
9e0ebc
		fi
9e0ebc
		;;
9e0ebc
	status)
9e0ebc
		status $prog
9e0ebc
		RETVAL=$?
9e0ebc
		;;
9e0ebc
	*)
9e0ebc
		echo \$"Usage: \$0 {start|stop|restart|try-restart}"
9e0ebc
		RETVAL=3
9e0ebc
esac
9e0ebc
9e0ebc
exit \$RETVAL
9e0ebc
EOF
9e0ebc
		chmod 755 /etc/init.d/alsaloop || safe_exit 1
9e0ebc
		$chkconfig_prg --add alsaloop
9e0ebc
		$chkconfig_prg alsaloop on
9e0ebc
	fi
9e0ebc
}
9e0ebc
9e0ebc
function modify_pa_conf() {
9e0ebc
9e0ebc
	if grep Loopback /etc/pulse/default.pa > /dev/null; then
9e0ebc
		echo "/etc/pulse/default.pa already modified"
9e0ebc
	else
9e0ebc
		if test -f /etc/pulse/default.pa; then
9e0ebc
			local pcardid=$(get_card_id "hw:$pcard")
9e0ebc
			if ! test -f /etc/pulse/default.pa.alsa-delay.save ; then
9e0ebc
				cp /etc/pulse/default.pa /etc/pulse/default.pa.alsa-delay.save
9e0ebc
			fi
9e0ebc
			cat /etc/pulse/default.pa | \
9e0ebc
				sed -e 's/^load-module module-udev-detect/#load-module module-udev-detect # commented by alsa-delay/' \
9e0ebc
				    -e 's/^load-module module-detect/#load-module module-detect # commented by alsa-delay/' \
9e0ebc
				    -e "s/^### Automatically load driver modules for Bluetooth hardware/load-module module-alsa-card device_id=Loopback\nload-module module-alsa-card device_id=$pcardid\n\n### Automatically load driver modules for Bluetooth hardware/" > /etc/pulse/default.pa.new
9e0ebc
			if test -s /etc/pulse/default.pa.new; then
9e0ebc
				mv /etc/pulse/default.pa.new /etc/pulse/default.pa
9e0ebc
				echo "/etc/pulse/default.pa changed"
9e0ebc
			fi
9e0ebc
		fi
9e0ebc
	fi
9e0ebc
9e0ebc
	local file=
9e0ebc
	local asoundconf=
9e0ebc
	if test -d /etc/alsa -a -f /etc/alsa/pulse-default.conf; then
9e0ebc
		file=/etc/alsa/alsaloop-default.conf
9e0ebc
		asoundconf=yes
9e0ebc
	fi
9e0ebc
	if test -f /usr/share/alsa/alsa.conf.d/99-pulseaudio-default.conf ; then
9e0ebc
		file=/usr/share/alsa/alsa.conf.d/A0-alsaloop-default.conf
9e0ebc
	fi
9e0ebc
	if test -z "$file"; then
9e0ebc
		echo "unknown PulseAudio setup (asound.conf)"
9e0ebc
	elif test -f $file; then
9e0ebc
		echo "$file exists"
9e0ebc
	else
9e0ebc
		cat >> $file <
9e0ebc
pcm.!default {
9e0ebc
	@args [ CARD ]
9e0ebc
	@args.CARD {
9e0ebc
		type string
9e0ebc
	}
9e0ebc
	type asym
9e0ebc
	playback.pcm "plughw:Loopback"
9e0ebc
	capture.pcm {
9e0ebc
		type pulse
9e0ebc
	}
9e0ebc
}
9e0ebc
EOF
9e0ebc
		if test -n "$asoundconf"; then
9e0ebc
			cat /etc/asound.conf | sed 's/pulse-default.conf/alsaloop-default.conf/g' > /etc/asound.conf.new
9e0ebc
			if test -s /etc/asound.conf.new; then
9e0ebc
				mv /etc/asound.conf.new /etc/asound.conf
9e0ebc
			fi
9e0ebc
		fi
9e0ebc
	fi
9e0ebc
}
9e0ebc
9e0ebc
function remove() {
9e0ebc
	if test -f /etc/pulse/default.pa.alsa-delay.save ; then
9e0ebc
		echo "Restoring /etc/pulse/default.pa"
9e0ebc
		mv /etc/pulse/default.pa.alsa-delay.save /etc/pulse/default.pa
9e0ebc
	fi
9e0ebc
	if test -f /etc/init.d/alsaloop ; then
9e0ebc
		echo "Removing /etc/init.d/alsaloop service"
9e0ebc
		$chkconfig_prg alsaloop off
9e0ebc
		$chkconfig_prg --del alsaloop
9e0ebc
		rm /etc/init.d/alsaloop
9e0ebc
	fi
9e0ebc
	if test -f /etc/systemd/system/alsaloop.service ; then
9e0ebc
		echo "Removing /etc/systemd/system/alsaloop.service"
9e0ebc
		$systemctl_prg disable alsaloop.service
9e0ebc
		rm /etc/systemd/system/alsaloop.service
9e0ebc
	fi
9e0ebc
	if test -f $alsaloopconf ; then
9e0ebc
		echo "Removing $alsaloopconf"
9e0ebc
		rm $alsaloopconf
9e0ebc
	fi
9e0ebc
	if test -f /etc/alsa/alsaloop-default.conf ; then
9e0ebc
		echo "Removing /etc/alsa/alsaloop-default.conf"
9e0ebc
		rm /etc/alsa/alsaloop-default.conf
9e0ebc
	fi
9e0ebc
	if test -f /usr/share/alsa/alsa.conf.d/A0-alsaloop-default.conf ; then
9e0ebc
		echo "Removing /usr/share/alsa/alsa.conf.d/A0-alsaloop-default.conf"
9e0ebc
		rm /usr/share/alsa/alsa.conf.d/A0-alsaloop-default.conf
9e0ebc
	fi
9e0ebc
	if grep "alsaloop-default.conf" /etc/asound.conf > /dev/null 2> /dev/null ; then
9e0ebc
		echo "Modifying /etc/asound.conf"
9e0ebc
		cat /etc/asound.conf | sed 's/alsaloop-default.conf/pulse-default.conf/g' > /etc/asound.conf.new
9e0ebc
		if test -s /etc/asound.conf.new; then
9e0ebc
			mv /etc/asound.conf.new /etc/asound.conf
9e0ebc
		fi
9e0ebc
	fi
9e0ebc
	if test -f $modprobeconf.alsa-delay.save ; then
9e0ebc
		echo "Restoring $modprobeconf"
9e0ebc
		if test -s $modprobeconf.alsa-delay.save ; then
9e0ebc
			mv $modprobeconf.alsa-delay.save $modprobeconf
9e0ebc
		else
9e0ebc
			rm $modprobeconf.alsa-delay.save
9e0ebc
			rm $modprobeconf
9e0ebc
		fi
9e0ebc
	fi
9e0ebc
	if test $(aloop_present) = "yes"; then
9e0ebc
		kernel_modules unload
9e0ebc
	fi
9e0ebc
}
9e0ebc
9e0ebc
rundir=$(pwd)
9e0ebc
export LC_ALL=C
9e0ebc
export LANGUAGE=C
9e0ebc
9e0ebc
check_environment
9e0ebc
9e0ebc
if test -n "$clean"; then
9e0ebc
	clean
9e0ebc
	safe_exit 0
9e0ebc
fi
9e0ebc
9e0ebc
if test -n "$remove"; then
9e0ebc
	kill_alsaloop
9e0ebc
	remove
9e0ebc
	clean
9e0ebc
	safe_exit 0
9e0ebc
fi
9e0ebc
9e0ebc
kill_alsaloop
9e0ebc
if test -d /etc/systemd/system ; then
9e0ebc
  create_systemd_service
9e0ebc
else
9e0ebc
  create_initd
9e0ebc
fi
9e0ebc
modify_modprobe_conf
9e0ebc
generate_alsaloop_conf
9e0ebc
if test -n "$pa"; then
9e0ebc
  modify_pa_conf
9e0ebc
fi
9e0ebc
restart_alsaloop
9e0ebc
9e0ebc
clean
9e0ebc
9e0ebc
safe_exit 0