diff --git a/README.md b/README.md index 0ce9e7d..d8fcc3b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# pulseaudio-tcp - Redirect PulseAudio to and from Remote Computer +# pulseaudio-tcp - Redirect PulseAudio to Remote Computer ## Requirements @@ -12,10 +12,7 @@ ### Installation on Client Playback Host * pulseaudio-tcp should be installed on a computer running PulseAudio or Pipewire with PulseAudio compatibility. -* The computer pulseaudio-tcp is installed on ("local host") should use use a remote computer ("remote host") for playback. - - This is refered to as "outbound" audio. -* The local host should receive audio from the remote host for recording. - - This is refered to as "inbound" audio. +* The computer pulseaudio-tcp is installed on ("local host") should use use a remote computer that has speakers attached ("remote host") for playback. * The IP address and username of the remote host should be known. ### SSH to User Session on Remote Host @@ -36,7 +33,7 @@ sudo make install ## Usage -### Setup Procedure +### Configuration As regular user on local host: @@ -44,37 +41,19 @@ As regular user on local host: pulseadio-tcp setup ``` -The following questions will be asked: - -* IP address of remote host. -* Name of user on remote host running PulseAudio/Pipewire. -* Enable inbound audio. -* Enable outbound audio. - -### Configuration File - -The setup procedure writes a configuration file `$HOME/.config/pulseaudio-tcp/config.inc.sh`: - -``` -remote_ip="192.168.1.166" -remote_user="remoteuser" -inbound=true -outbound=true -``` - -### Starting the Service +### Start service ```shell pulseadio-tcp start ``` -### Stopping the Service +### Stop service ```shell pulseadio-tcp stop ``` -### Checking if the Service is running +### Check if service is running ```shell pulseadio-tcp status diff --git a/pulseaudio-tcp b/pulseaudio-tcp index fbc14b0..af7fb15 100644 --- a/pulseaudio-tcp +++ b/pulseaudio-tcp @@ -94,70 +94,6 @@ do_setup() { fi done - inbound=${inbound:-true} - - while true ; do - if "$inbound" ; then - prompt="Y/n" - else - prompt="y/N" - fi - - read -r -p "Enable inbound audio ($prompt): " inbound_in - - case "$inbound_in" in - "") - if test -n "$inbound" ; then - inbound_in=$inbound - break 2 - fi - ;; - y|Y) - inbound_in=true - break 2 - ;; - n|N) - inbound_in=false - break 2 - ;; - *) - echo "ERROR: Please type \"y\" or \"n\"." >&2 - ;; - esac - done - - outbound=${outbound:-true} - - while true ; do - if "$outbound" ; then - prompt="Y/n" - else - prompt="y/N" - fi - - read -r -p "Enable outbound audio ($prompt): " outbound_in - - case "$outbound_in" in - "") - if test -n "$outbound" ; then - outbound_in=$outbound - break 2 - fi - ;; - y|Y) - outbound_in=true - break 2 - ;; - n|N) - outbound_in=false - break 2 - ;; - *) - echo "ERROR: Please type \"y\" or \"n\"." >&2 - ;; - esac - done - cat > "$config" << EOF # Configuration file for pulseaudio-tcp # Generated on $(LC_ALL=C date) by $USER using $0 @@ -167,27 +103,15 @@ remote_ip="$remote_ip_in" # Username on remote host remote_user="$remote_user_in" - -# Enable inbound audio from $remote_user @$remote_ip? -inbound=$inbound_in - -# Enable outbound audio to $remote_user @$remote_ip? -outbound=$outbound_in EOF } # Check if SSH port forwarding is running check_pa_ssh() { for pid in $(pidof ssh) ; do - if grep -Fq $USER-pulseaudio /proc/"$pid"/cmdline ; then - grep -Fq -e -L /proc/"$pid"/cmdline || { - echo "ERROR: No SSH port forwarding to remote server is established." >&2 - return 1 ; - } - fi + grep -Fq $USER-pulseaudio /proc/"$pid"/cmdline && return 0 done - echo "ERROR: No SSH is established." >&2 return 1 } @@ -195,32 +119,24 @@ check_pa_ssh() { do_status() { rv=0 - if ! check_pa_ssh ; then - rv=1 - fi - if ! _ssh pactl list modules | grep -Fq "Name: module-native-protocol-tcp" ; then echo "ERROR: PulseAudio module \"module-native-protocol-tcp\" is not loaded on remote_ip=$remote_ip." >&2 rv=1 fi - if "$outbound" ; then - if ! pactl list modules | grep -Fq "Name: module-tunnel-sink" ; then - echo "ERROR: PulseAudio module \"module-tunnel-sink\" is not loaded." >&2 - rv=1 - fi - - if ! pactl get-default-sink | grep -Fq "tunnel-sink.tcp:127.0.0.1" ; then - echo "ERROR: \"tunnel-sink.tcp:127.0.0.1\" is not the default PulseAudio sink." >&2 - rv=1 - fi + if ! check_pa_ssh ; then + echo "ERROR: SSH port forwarding to remote_ip=$remote_ip is not running." >&2 + rv=1 fi - if "$inbound" ; then - if ! pactl list modules | grep -Fq "Name: module-tunnel-source" ; then - echo "ERROR: PulseAudio module \"module-tunnel-source\" is not loaded." >&2 - rv=1 - fi + if ! pactl list modules | grep -Fq "Name: module-tunnel-sink" ; then + echo "ERROR: PulseAudio module \"module-tunnel-sink\" is not loaded." >&2 + rv=1 + fi + + if ! pactl get-default-sink | grep -Fq "tunnel-sink.tcp:127.0.0.1" ; then + echo "ERROR: \"tunnel-sink.tcp:127.0.0.1\" is not the default PulseAudio sink." >&2 + rv=1 fi if test "$rv" -eq 0 ; then @@ -241,13 +157,8 @@ sync_pa_cookie() { fi } -# Establish SSH port forwarding to PulseAudio TCP server on remote host -establish_ssh_portforward() { - _ssh -fNT -L 127.0.0.1:4713:127.0.0.1:4713 -} - # Enable PulseAudio TCP tunnel server on remote host -enable_remote_pa_tunnel_server() { +enable_pa_tunnel_server() { if _ssh pactl list modules | grep -Fq "Name: module-native-protocol-tcp" ; then echo "INFO: PulseAudio module \"module-native-protocol-tcp\" already loaded on remote_ip=$remote_ip." >&2 return 0 @@ -260,8 +171,13 @@ enable_remote_pa_tunnel_server() { fi } +# Establish SSH port forwarding to PulseAudio TCP server on remote host +establish_ssh_portforward() { + _ssh -fNT -L 127.0.0.1:4713:127.0.0.1:4713 +} + # Enable tunnel sink on local host -enable_local_pa_tunnel_sink() { +enable_pa_tunnel_sink() { if pactl list modules | grep -Fq "Name: module-tunnel-sink" ; then echo "INFO: PulseAudio module \"module-tunnel-sink\" already loaded." >&2 return 0 @@ -274,22 +190,8 @@ enable_local_pa_tunnel_sink() { fi } -# Enable tunnel source on local host -enable_local_pa_tunnel_source() { - if pactl list modules | grep -Fq "Name: module-tunnel-source" ; then - echo "INFO: PulseAudio module \"module-tunnel-source\" already loaded." >&2 - return 0 - elif pactl load-module module-tunnel-source server=tcp:127.0.0.1 ; then - echo "INFO: Loaded PulseAudio module \"module-tunnel-source\"." >&2 - return 0 - else - echo "ERROR: Unable to load PulseAudio module \"module-tunnel-source\"." >&2 - return 1 - fi -} - # Set tunnel sink as default sink on local host -set_local_pa_tunnel_sink_as_default() { +set_pa_tunnel_sink_as_default() { if pactl set-default-sink tunnel-sink.tcp:127.0.0.1 ; then echo "INFO: Set \"tunnel-sink.tcp:127.0.0.1\" as default PulseAudio sink." >&2 return 0 @@ -302,23 +204,16 @@ set_local_pa_tunnel_sink_as_default() { # Perform start operation do_start() { sync_pa_cookie || return 1 + enable_pa_tunnel_server || return 1 establish_ssh_portforward || return 1 - enable_remote_pa_tunnel_server || return 1 - - if "$outbound" ; then - enable_local_pa_tunnel_sink || return 1 - set_local_pa_tunnel_sink_as_default || return 1 - fi - - if "$inbound" ; then - enable_local_pa_tunnel_source || return 1 - fi + enable_pa_tunnel_sink || return 1 + set_pa_tunnel_sink_as_default || return 1 return 0 } # Remove PulseAudio TCP tunnel sink on local host -remove_local_pa_tunnel_sink() { +remove_pa_tunnel_sink() { if ! pactl list modules | grep -Fq "Name: module-tunnel-sink" ; then echo "INFO: PulseAudio module \"module-tunnel-sink\" is not loaded." >&2 return 0 @@ -341,32 +236,17 @@ remove_local_pa_tunnel_sink() { fi } -# Remove PulseAudio TCP tunnel source on local host -remove_local_pa_tunnel_source() { - if ! pactl list modules | grep -Fq "Name: module-tunnel-source" ; then - echo "INFO: PulseAudio module \"module-tunnel-source\" is not loaded." >&2 - return 0 - elif ! pactl list sources | grep -Fq "tunnel-source.tcp:127.0.0.1" ; then - echo "INFO: No PulseAudio tunnel source from 127.0.0.1 exists." >&2 - return 0 - else - owner_module=$( - pactl --format json list sources 2>/dev/null | \ - jq '.[] | select(.name=="tunnel-source.tcp:127.0.0.1") | .owner_module' -r - ) - - if ! pactl unload-module "$owner_module" ; then - echo "ERROR: Could not unload owner module $owner_module of PulseAudio source \"tunnel-source.tcp:127.0.0.1\"." >&2 - return 1 - else - echo "INFO: Unloaded owner module $owner_module of PulseAudio source \"tunnel-source.tcp:127.0.0.1\"." >&2 - return 0 +# Terminate SSH portforwarding session +terminate_ssh_portforward() { + for pid in $(pidof ssh) ; do + if grep -Fq $USER-pulseaudio /proc/"$pid"/cmdline ; then + kill -TERM "$pid" fi - fi + done } # Stop PulseAudio TCP tunnel server on remote host. -disable_remote_pa_tunnel_server() { +disable_pa_tunnel_server() { if ! _ssh pactl list modules | grep -Fq "Name: module-native-protocol-tcp" ; then echo "INFO: PulseAudio module \"module-native-protocol-tcp\" not loaded on remote_ip=$remote_ip." >&2 return 0 @@ -379,27 +259,11 @@ disable_remote_pa_tunnel_server() { fi } -# Terminate SSH portforwarding session -terminate_ssh_portforward() { - for pid in $(pidof ssh) ; do - if grep -Fq $USER-pulseaudio /proc/"$pid"/cmdline ; then - kill -TERM "$pid" - fi - done -} - # Perform stop operation do_stop() { - if "$outbound" ; then - remove_local_pa_tunnel_sink || return 1 - fi - - if "$inbound" ; then - remove_local_pa_tunnel_source || return 1 - fi - - disable_remote_pa_tunnel_server || return 1 + remove_pa_tunnel_sink || return 1 terminate_ssh_portforward || return 1 + disable_pa_tunnel_server || return 1 return 0 } @@ -452,7 +316,7 @@ else ""|-h|--help) cat << EOF Setup and run encrypted connection to remote PulseAudio/Pipewire server -Usage: $0 restart|setup|start|status|stop +Usage: $0 setup|start|stop|status EOF rv=0 ;; @@ -468,17 +332,12 @@ EOF do_stop rv=$? ;; - restart) - do_stop - do_start - rv=$? - ;; status) do_status rv=$? ;; *) - echo "ERROR: Usage: $0 restart|setup|start|status|stop" >&2 + echo "ERROR: Usage: $0 setup|start|stop|status" >&2 rv=1 ;; esac