From add4f6394a69489c12ca1ca4952f9591e89220d1 Mon Sep 17 00:00:00 2001 From: houston Date: Sat, 19 May 2018 15:04:06 +0200 Subject: [PATCH 1/4] modify cadence-pulse2jack to accept playback or capture channel number args, and to load/unload source/sink if needed --- data/cadence-pulse2jack | 211 +++++++++++++++++++++++++++++----------- 1 file changed, 155 insertions(+), 56 deletions(-) diff --git a/data/cadence-pulse2jack b/data/cadence-pulse2jack index 5266cb9..50ceef0 100755 --- a/data/cadence-pulse2jack +++ b/data/cadence-pulse2jack @@ -1,7 +1,7 @@ #!/bin/bash # Script to bridge/start pulseaudio into JACK mode -INSTALL_PREFIX="X-PREFIX-X" +INSTALL_PREFIX="/usr" # ---------------------------------------------- @@ -43,38 +43,66 @@ else fi # ---------------------------------------------- +wanted_capture_ports=0 # -1 means default +wanted_playback_ports=0 # -1 means default + +arg_is_for="" + +for arg in "$@";do + case "$arg" in + -h|--h|--help) + echo "usage: $0 [command] + + -p Playback only with default number of channels + -p Number of playback channels + -c Capture only with default number of channels + -c Number of capture channels + + -h, --help Show this help menu + --dummy Don't do anything, just create the needed files + + NOTE: + When runned with no arguments, pulse2jack will + activate PulseAudio with both playback and record modes with default number of channels. + " + exit + ;; + --dummy) + exit + ;; + -c|--capture) + arg_is_for="capture" + wanted_capture_ports=-1 # -1 means default, if no (correct) argument is given. + ;; + -p|--play|--playback) + arg_is_for="playback" + wanted_playback_ports=-1 + ;; + * ) + case "$arg_is_for" in + "capture") + [ "$arg" -ge 0 ] 2>/dev/null && wanted_capture_ports="$arg" + ;; + "playback") + [ "$arg" -ge 0 ] 2>/dev/null && wanted_playback_ports="$arg" + ;; + esac + ;; + esac +done + + +if [ $wanted_capture_ports == 0 ] && [ $wanted_playback_ports == 0 ];then + #no sense to want to start/bridge pulseaudio without ports, set as default + capture_ports=-1 # -1 means default + playback_ports=-1 # -1 means default +fi -PLAY_ONLY="no" - -case $1 in - -h|--h|--help) -echo "usage: $0 [command] - - -p, --play Playback mode only - - -h, --help Show this help menu - --dummy Don't do anything, just create the needed files - -NOTE: - When runned with no arguments, pulse2jack will - activate PulseAudio with both playback and record modes. -" -exit - ;; - - --dummy) -exit - ;; - - -p|--p|--play) -PLAY_ONLY="yes" -FILE=$INSTALL_PREFIX/share/cadence/pulse2jack/play.pa - ;; +str_capture="channels=$wanted_capture_ports" #used for pulseaudio commands +str_playback="channels=$wanted_playback_ports" ## - *) -FILE=$INSTALL_PREFIX/share/cadence/pulse2jack/play+rec.pa - ;; -esac +[ $wanted_capture_ports == -1 ] && str_capture="" # -1 means default, no command channels=n +[ $wanted_playback_ports == -1 ] && str_playback="" ## # ---------------------------------------------- @@ -87,38 +115,109 @@ IsPulseAudioRunning() true fi } - + if (IsPulseAudioRunning); then -{ - if (`jack_lsp | grep "PulseAudio JACK Sink:" > /dev/null`); then - { - echo "PulseAudio is already running and bridged to JACK" - } - else - { - echo "PulseAudio is already running, bridge it..." - - if [ "$PLAY_ONLY" == "yes" ]; then - { - pactl load-module module-jack-sink > /dev/null - pacmd set-default-source jack_in > /dev/null - } - else - { - pactl load-module module-jack-sink > /dev/null - pactl load-module module-jack-source > /dev/null - pacmd set-default-sink jack_out > /dev/null +{ + #count all Jack Audio Physical ports + all_jack_lsp=$(jack_lsp -p -t) + output_physical_lines=$(echo "$all_jack_lsp"|grep -n "output,physical,"|cut -d':' -f1) + input_physical_lines=$( echo "$all_jack_lsp"|grep -n "input,physical," |cut -d':' -f1) + audio_lines=$(echo "$all_jack_lsp" |grep -n " audio"|cut -d':' -f1) + + capture_physical_ports=0 + playback_physical_ports=0 + + for out_phy_line in $output_physical_lines;do + if echo "$audio_lines"|grep -q $(($out_phy_line + 1));then + ((capture_physical_ports++)) + fi + done + + for in_phy_line in $input_physical_lines;do + if echo "$audio_lines"|grep -q $(($in_phy_line + 1));then + ((playback_physical_ports++)) + fi + done + + #count PulseAudio jack ports + current_playback_ports=$(echo "$all_jack_lsp"|grep ^"PulseAudio JACK Sink:" |wc -l) + current_capture_ports=$( echo "$all_jack_lsp"|grep ^"PulseAudio JACK Source:"|wc -l) + + #if number of pulseaudio ports equal to physical ports, consider pulseaudio module is running the default mode (no channels=n) + [ $current_capture_ports == $capture_physical_ports ] && current_capture_ports=-1 + [ $current_playback_ports == $playback_physical_ports ] && current_playback_ports=-1 + [ $wanted_capture_ports == $capture_physical_ports ] && wanted_capture_ports=-1 + [ $wanted_playback_ports == $playback_physical_ports ] && wanted_playback_ports=-1 + + if [ $wanted_capture_ports == $current_capture_ports ] && [ $wanted_playback_ports == $current_playback_ports ];then + echo "PulseAudio is already started and bridged to Jack, nothing to do !" + exit + fi + + if [ $current_capture_ports != $wanted_capture_ports ];then + if [ $current_capture_ports != 0 ];then + echo "unload PulseAudio JACK Source" + pactl unload-module module-jack-source > /dev/null + fi + + if [ $wanted_capture_ports != 0 ];then + echo "load PulseAudio JACK Source $str_capture" + + pactl load-module module-jack-source $str_capture > /dev/null pacmd set-default-source jack_in > /dev/null - } fi - - echo "Done" - } + fi + + if [ $current_playback_ports != $wanted_playback_ports ];then + if [ $current_playback_ports != 0 ];then + echo "unload PulseAudio JACK Sink" + pactl unload-module module-jack-sink > /dev/null + fi + + if [ $wanted_playback_ports != 0 ];then + echo "load PulseAudio JACK Sink $str_playback" + + pactl load-module module-jack-sink $str_playback > /dev/null + pactl set-default-sink jack_out > /dev/null + fi fi } else { - if (`pulseaudio --daemonize --high-priority --realtime --exit-idle-time=-1 --file=$FILE -n`); then + #write pulseaudio config file in a tmp file + pa_file=$(mktemp --suffix .pa) + echo .fail > $pa_file + + ### Automatically restore the volume of streams and devices + echo load-module module-device-restore >> $pa_file + echo load-module module-stream-restore >> $pa_file + echo load-module module-card-restore >> $pa_file + + ### Load Jack modules + [ $wanted_capture_ports != 0 ] && echo load-module module-jack-source $str_capture >> $pa_file + [ $wanted_playback_ports != 0 ] && echo load-module module-jack-sink $str_playback >> $pa_file + + ### Load unix protocol + echo load-module module-native-protocol-unix >> $pa_file + + ### Automatically restore the default sink/source when changed by the user + ### during runtime + ### NOTE: This should be loaded as early as possible so that subsequent modules + ### that look up the default sink/source get the right value + echo load-module module-default-device-restore >> $pa_file + + ### Automatically move streams to the default sink if the sink they are + ### connected to dies, similar for sources + echo load-module module-rescue-streams >> $pa_file + + ### Make sure we always have a sink around, even if it is a null sink. + echo load-module module-always-sink >> $pa_file + + ### Make Jack default + [ $wanted_capture_ports != 0 ] && echo set-default-source jack_in >> $pa_file + [ $wanted_playback_ports != 0 ] && echo set-default-sink jack_out >> $pa_file + + if (`pulseaudio --daemonize --high-priority --realtime --exit-idle-time=-1 --file=$pa_file -n`); then echo "Initiated PulseAudio successfully!" else echo "Failed to initialize PulseAudio!" From 09e58c01f79d0aef5edf66ae83e2393df22fd751 Mon Sep 17 00:00:00 2001 From: houston Date: Sat, 19 May 2018 16:04:23 +0200 Subject: [PATCH 2/4] gives 2 spinboxs in pulseaudio jack settings dialog to choose number of channels, and all to make it works --- resources/ui/cadence.ui | 91 ++++++++++++++++++++++++++--------- resources/ui/cadence_tb_pa.ui | 63 +++++++++++++++++++++--- src/cadence.py | 70 +++++++++++++++++---------- 3 files changed, 167 insertions(+), 57 deletions(-) diff --git a/resources/ui/cadence.ui b/resources/ui/cadence.ui index b0e1c63..007806f 100644 --- a/resources/ui/cadence.ui +++ b/resources/ui/cadence.ui @@ -7,7 +7,7 @@ 0 0 740 - 564 + 680 @@ -544,7 +544,16 @@ JACK Bridges - + + 2 + + + 2 + + + 2 + + 2 @@ -572,8 +581,8 @@ 0 0 - 360 - 100 + 435 + 130 @@ -720,8 +729,8 @@ 0 0 - 360 - 97 + 310 + 110 @@ -861,8 +870,8 @@ 0 0 - 360 - 97 + 435 + 130 @@ -909,6 +918,13 @@ + + + + Update Channels + + + @@ -1579,7 +1595,7 @@ Audio Plugins PATH - AlignHCenter|AlignVCenter|AlignCenter + AlignCenter ItemIsSelectable|ItemIsEnabled @@ -1590,7 +1606,7 @@ Default Applications - AlignHCenter|AlignVCenter|AlignCenter + AlignCenter ItemIsSelectable|ItemIsEnabled @@ -1601,7 +1617,7 @@ WineASIO - AlignHCenter|AlignVCenter|AlignCenter + AlignCenter ItemIsSelectable|ItemIsEnabled @@ -1620,7 +1636,16 @@ - + + 0 + + + 0 + + + 0 + + 0 @@ -1688,8 +1713,8 @@ 0 0 - 416 - 334 + 96 + 86 @@ -1718,8 +1743,8 @@ 0 0 - 94 - 66 + 96 + 86 @@ -1748,8 +1773,8 @@ 0 0 - 94 - 66 + 96 + 86 @@ -1778,8 +1803,8 @@ 0 0 - 94 - 66 + 96 + 86 @@ -1839,12 +1864,21 @@ - - 20 + + 0 + + + 0 + + + 0 - + 0 + + 20 + @@ -2070,7 +2104,16 @@ - + + 0 + + + 0 + + + 0 + + 0 diff --git a/resources/ui/cadence_tb_pa.ui b/resources/ui/cadence_tb_pa.ui index ed31ef4..b2d76c1 100644 --- a/resources/ui/cadence_tb_pa.ui +++ b/resources/ui/cadence_tb_pa.ui @@ -6,8 +6,8 @@ 0 0 - 317 - 72 + 218 + 124 @@ -15,11 +15,60 @@ - - - Playback Mode only - - + + + + + Input Channels : + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Output Channels : + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Default + + + -1 + + + 10 + + + -1 + + + + + + + Default + + + -1 + + + 10 + + + -1 + + + + diff --git a/src/cadence.py b/src/cadence.py index 88816d9..81160db 100755 --- a/src/cadence.py +++ b/src/cadence.py @@ -126,9 +126,10 @@ WINEASIO_PREFIX = "HKEY_CURRENT_USER\Software\Wine\WineASIO" # --------------------------------------------------------------------- -global jackClientIdALSA, jackClientIdPulse -jackClientIdALSA = -1 -jackClientIdPulse = -1 +global jackClientIdALSA, jackClientIdPulseCapture, jackClientIdPulsePlayback +jackClientIdALSA = -1 +jackClientIdPulseCapture = -1 +jackClientIdPulsePlayback = -1 # jackdbus indexes iGraphVersion = 0 @@ -342,8 +343,8 @@ def isPulseAudioStarted(): return bool("pulseaudio" in getProcList()) def isPulseAudioBridged(): - global jackClientIdPulse - return bool(jackClientIdPulse != -1) + global jackClientIdPulseCapture, jackClientIdPulsePlayback + return bool(jackClientIdPulseCapture != -1 or jackClientIdPulsePlayback != -1) def isDesktopFileInstalled(desktop): for X_PATH in XDG_APPLICATIONS_PATH: @@ -591,10 +592,10 @@ class ForceRestartThread(QThread): # PulseAudio if GlobalSettings.value("Pulse2JACK/AutoStart", True, type=bool) and not isPulseAudioBridged(): - if GlobalSettings.value("Pulse2JACK/PlaybackModeOnly", False, type=bool): - os.system("cadence-pulse2jack -p") - else: - os.system("cadence-pulse2jack") + inputs = GlobalSettings.value("Pulse2JACK/CaptureChannels", -1, type=int) + outputs = GlobalSettings.value("Pulse2JACK/PlaybackChannels", -1, type=int) + + os.system("cadence-pulse2jack -c %s -p %s" % (str(inputs), str(outputs))) self.progressChanged.emit(100) @@ -750,14 +751,16 @@ class ToolBarPADialog(QDialog, ui_cadence_tb_pa.Ui_Dialog): def __init__(self, parent): QDialog.__init__(self, parent) self.setupUi(self) - - self.cb_playback_only.setChecked(GlobalSettings.value("Pulse2JACK/PlaybackModeOnly", False, type=bool)) + + self.spinBoxPulseInputs.setValue(GlobalSettings.value("Pulse2JACK/CaptureChannels", 2, type=int)) + self.spinBoxPulseOutputs.setValue(GlobalSettings.value("Pulse2JACK/PlaybackChannels", 2, type=int)) self.accepted.connect(self.slot_setOptions) @pyqtSlot() def slot_setOptions(self): - GlobalSettings.setValue("Pulse2JACK/PlaybackModeOnly", self.cb_playback_only.isChecked()) + GlobalSettings.setValue("Pulse2JACK/CaptureChannels", self.spinBoxPulseInputs.value()) + GlobalSettings.setValue("Pulse2JACK/PlaybackChannels", self.spinBoxPulseOutputs.value()) def done(self, r): QDialog.done(self, r) @@ -1161,6 +1164,7 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): self.b_a2j_export_hw.clicked.connect(self.slot_A2JBridgeExportHW) self.tb_a2j_options.clicked.connect(self.slot_A2JBridgeOptions) + self.b_pulse_update.clicked.connect(self.slot_PulseAudioBridgeStart) self.b_pulse_start.clicked.connect(self.slot_PulseAudioBridgeStart) self.b_pulse_stop.clicked.connect(self.slot_PulseAudioBridgeStop) self.tb_pulse_options.clicked.connect(self.slot_PulseAudioBridgeOptions) @@ -1262,9 +1266,12 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): if group_name == "alsa2jack": global jackClientIdALSA jackClientIdALSA = group_id + elif group_name == "PulseAudio JACK Source": + global jackClientIdPulseCapture + jackClientIdPulseCapture = group_id elif group_name == "PulseAudio JACK Sink": - global jackClientIdPulse - jackClientIdPulse = group_id + global jackClientIdPulsePlayback + jackClientIdPulsePlayback = group_id self.jackStarted() @@ -1403,9 +1410,10 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): self.b_a2j_start.setEnabled(False) self.systray.setActionEnabled("a2j_start", False) - global jackClientIdALSA, jackClientIdPulse - jackClientIdALSA = -1 - jackClientIdPulse = -1 + global jackClientIdALSA, jackClientIdPulseCapture, jackClientIdPulsePlayback + jackClientIdALSA = -1 + jackClientIdPulseCapture = -1 + jackClientIdPulsePlayback = -1 if haveDBus: self.checkAlsaAudio() @@ -1505,6 +1513,7 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): if isPulseAudioStarted(): if isPulseAudioBridged(): + self.b_pulse_update.setEnabled(True) self.b_pulse_start.setEnabled(False) self.b_pulse_stop.setEnabled(True) self.systray.setActionEnabled("pulse_start", False) @@ -1512,6 +1521,7 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): self.label_bridge_pulse.setText(self.tr("PulseAudio is started and bridged to JACK")) else: jackRunning = bool(gDBus.jack and gDBus.jack.IsStarted()) + self.b_pulse_update.setEnabled(jackRunning) self.b_pulse_start.setEnabled(jackRunning) self.b_pulse_stop.setEnabled(False) self.systray.setActionEnabled("pulse_start", jackRunning) @@ -1519,6 +1529,7 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): self.label_bridge_pulse.setText(self.tr("PulseAudio is started but not bridged")) else: jackRunning = bool(gDBus.jack and gDBus.jack.IsStarted()) + self.b_pulse_update.setEnabled(False) self.b_pulse_start.setEnabled(jackRunning) self.b_pulse_stop.setEnabled(False) self.systray.setActionEnabled("pulse_start", jackRunning) @@ -1645,19 +1656,26 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): global jackClientIdALSA jackClientIdALSA = group_id self.checkAlsaAudio() + elif group_name == "PulseAudio JACK Source": + global jackClientIdPulseCapture + jackClientIdPulseCapture = group_id + self.checkPulseAudio() elif group_name == "PulseAudio JACK Sink": - global jackClientIdPulse - jackClientIdPulse = group_id + global jackClientIdPulsePlayback + jackClientIdPulsePlayback = group_id self.checkPulseAudio() @pyqtSlot(int) def slot_DBusJackClientDisappearedCallback(self, group_id): - global jackClientIdALSA, jackClientIdPulse + global jackClientIdALSA, jackClientIdPulseCapture, jackClientIdPulsePlayback if group_id == jackClientIdALSA: jackClientIdALSA = -1 self.checkAlsaAudio() - elif group_id == jackClientIdPulse: - jackClientIdPulse = -1 + elif group_id == jackClientIdPulseCapture: + jackClientIdPulseCapture = -1 + self.checkPulseAudio() + elif group_id == jackClientIdPulsePlayback: + jackClientIdPulsePlayback = -1 self.checkPulseAudio() @pyqtSlot() @@ -1812,10 +1830,10 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): @pyqtSlot() def slot_PulseAudioBridgeStart(self): - if GlobalSettings.value("Pulse2JACK/PlaybackModeOnly", False, type=bool): - os.system("cadence-pulse2jack -p") - else: - os.system("cadence-pulse2jack") + inputs = GlobalSettings.value("Pulse2JACK/CaptureChannels", 2, type=int) + outputs = GlobalSettings.value("Pulse2JACK/PlaybackChannels", 2, type=int) + + os.system("cadence-pulse2jack -c %s -p %s" % (str(inputs), str(outputs))) @pyqtSlot() def slot_PulseAudioBridgeStop(self): From 4cdc5696f2f0891eed9ad931d2b36ffd31f10ffe Mon Sep 17 00:00:00 2001 From: houston Date: Tue, 22 May 2018 13:07:09 +0200 Subject: [PATCH 3/4] improve cadence-pulse2jack to prevent errors, move pulseaudio preferences window to 'channels', which directly change channels if accepted --- data/cadence-pulse2jack | 143 +++++++++++++++++++++++++++------------- resources/ui/cadence.ui | 27 +++----- src/cadence.py | 107 +++++++++++++++++++----------- 3 files changed, 179 insertions(+), 98 deletions(-) diff --git a/data/cadence-pulse2jack b/data/cadence-pulse2jack index 50ceef0..4753856 100755 --- a/data/cadence-pulse2jack +++ b/data/cadence-pulse2jack @@ -1,7 +1,7 @@ #!/bin/bash # Script to bridge/start pulseaudio into JACK mode -INSTALL_PREFIX="/usr" +INSTALL_PREFIX="X-PREFIX-X" # ---------------------------------------------- @@ -115,11 +115,65 @@ IsPulseAudioRunning() true fi } + +StartBridged() +{ + #write pulseaudio config file in a tmp file + pa_file=$(mktemp --suffix .pa) + echo .fail > $pa_file + + ### Automatically restore the volume of streams and devices + echo load-module module-device-restore >> $pa_file + echo load-module module-stream-restore >> $pa_file + echo load-module module-card-restore >> $pa_file + + ### Load Jack modules + [ $wanted_capture_ports != 0 ] && echo load-module module-jack-source $str_capture >> $pa_file + [ $wanted_playback_ports != 0 ] && echo load-module module-jack-sink $str_playback >> $pa_file + + ### Load unix protocol + echo load-module module-native-protocol-unix >> $pa_file + ### Automatically restore the default sink/source when changed by the user + ### during runtime + ### NOTE: This should be loaded as early as possible so that subsequent modules + ### that look up the default sink/source get the right value + echo load-module module-default-device-restore >> $pa_file + + ### Automatically move streams to the default sink if the sink they are + ### connected to dies, similar for sources + echo load-module module-rescue-streams >> $pa_file + + ### Make sure we always have a sink around, even if it is a null sink. + echo load-module module-always-sink >> $pa_file + + ### Make Jack default + [ $wanted_capture_ports != 0 ] && echo set-default-source jack_in >> $pa_file + [ $wanted_playback_ports != 0 ] && echo set-default-sink jack_out >> $pa_file + + if (`pulseaudio --daemonize --high-priority --realtime --exit-idle-time=-1 --file=$pa_file -n`); then + echo "Initiated PulseAudio successfully!" + else + echo "Failed to initialize PulseAudio!" + fi +} + +killReStart() +{ + pulseaudio -k && StartBridged + exit +} + +JackNotRunning() +{ + echo "JACK seems not running, start JACK before bridge PulseAudio" + exit 1 +} + if (IsPulseAudioRunning); then { #count all Jack Audio Physical ports - all_jack_lsp=$(jack_lsp -p -t) + all_jack_lsp=$(jack_lsp -p -t) || JackNotRunning output_physical_lines=$(echo "$all_jack_lsp"|grep -n "output,physical,"|cut -d':' -f1) input_physical_lines=$( echo "$all_jack_lsp"|grep -n "input,physical," |cut -d':' -f1) audio_lines=$(echo "$all_jack_lsp" |grep -n " audio"|cut -d':' -f1) @@ -150,14 +204,14 @@ if (IsPulseAudioRunning); then [ $wanted_playback_ports == $playback_physical_ports ] && wanted_playback_ports=-1 if [ $wanted_capture_ports == $current_capture_ports ] && [ $wanted_playback_ports == $current_playback_ports ];then - echo "PulseAudio is already started and bridged to Jack, nothing to do !" + echo "PulseAudio is already started and bridged to Jack with $current_capture_ports inputs and $current_playback_ports outputs, nothing to do !" exit fi if [ $current_capture_ports != $wanted_capture_ports ];then if [ $current_capture_ports != 0 ];then echo "unload PulseAudio JACK Source" - pactl unload-module module-jack-source > /dev/null + pactl unload-module module-jack-source > /dev/null || killReStart fi if [ $wanted_capture_ports != 0 ];then @@ -171,7 +225,7 @@ if (IsPulseAudioRunning); then if [ $current_playback_ports != $wanted_playback_ports ];then if [ $current_playback_ports != 0 ];then echo "unload PulseAudio JACK Sink" - pactl unload-module module-jack-sink > /dev/null + pactl unload-module module-jack-sink > /dev/null || killReStart fi if [ $wanted_playback_ports != 0 ];then @@ -183,44 +237,45 @@ if (IsPulseAudioRunning); then fi } else -{ - #write pulseaudio config file in a tmp file - pa_file=$(mktemp --suffix .pa) - echo .fail > $pa_file - - ### Automatically restore the volume of streams and devices - echo load-module module-device-restore >> $pa_file - echo load-module module-stream-restore >> $pa_file - echo load-module module-card-restore >> $pa_file - - ### Load Jack modules - [ $wanted_capture_ports != 0 ] && echo load-module module-jack-source $str_capture >> $pa_file - [ $wanted_playback_ports != 0 ] && echo load-module module-jack-sink $str_playback >> $pa_file - - ### Load unix protocol - echo load-module module-native-protocol-unix >> $pa_file - - ### Automatically restore the default sink/source when changed by the user - ### during runtime - ### NOTE: This should be loaded as early as possible so that subsequent modules - ### that look up the default sink/source get the right value - echo load-module module-default-device-restore >> $pa_file - - ### Automatically move streams to the default sink if the sink they are - ### connected to dies, similar for sources - echo load-module module-rescue-streams >> $pa_file - - ### Make sure we always have a sink around, even if it is a null sink. - echo load-module module-always-sink >> $pa_file - - ### Make Jack default - [ $wanted_capture_ports != 0 ] && echo set-default-source jack_in >> $pa_file - [ $wanted_playback_ports != 0 ] && echo set-default-sink jack_out >> $pa_file - - if (`pulseaudio --daemonize --high-priority --realtime --exit-idle-time=-1 --file=$pa_file -n`); then - echo "Initiated PulseAudio successfully!" - else - echo "Failed to initialize PulseAudio!" - fi +{ + StartBridged +# #write pulseaudio config file in a tmp file +# pa_file=$(mktemp --suffix .pa) +# echo .fail > $pa_file +# +# ### Automatically restore the volume of streams and devices +# echo load-module module-device-restore >> $pa_file +# echo load-module module-stream-restore >> $pa_file +# echo load-module module-card-restore >> $pa_file +# +# ### Load Jack modules +# [ $wanted_capture_ports != 0 ] && echo load-module module-jack-source $str_capture >> $pa_file +# [ $wanted_playback_ports != 0 ] && echo load-module module-jack-sink $str_playback >> $pa_file +# +# ### Load unix protocol +# echo load-module module-native-protocol-unix >> $pa_file +# +# ### Automatically restore the default sink/source when changed by the user +# ### during runtime +# ### NOTE: This should be loaded as early as possible so that subsequent modules +# ### that look up the default sink/source get the right value +# echo load-module module-default-device-restore >> $pa_file +# +# ### Automatically move streams to the default sink if the sink they are +# ### connected to dies, similar for sources +# echo load-module module-rescue-streams >> $pa_file +# +# ### Make sure we always have a sink around, even if it is a null sink. +# echo load-module module-always-sink >> $pa_file +# +# ### Make Jack default +# [ $wanted_capture_ports != 0 ] && echo set-default-source jack_in >> $pa_file +# [ $wanted_playback_ports != 0 ] && echo set-default-sink jack_out >> $pa_file +# +# if (`pulseaudio --daemonize --high-priority --realtime --exit-idle-time=-1 --file=$pa_file -n`); then +# echo "Initiated PulseAudio successfully!" +# else +# echo "Failed to initialize PulseAudio!" +# fi } fi diff --git a/resources/ui/cadence.ui b/resources/ui/cadence.ui index 007806f..44cb34a 100644 --- a/resources/ui/cadence.ui +++ b/resources/ui/cadence.ui @@ -729,8 +729,8 @@ 0 0 - 310 - 110 + 435 + 130 @@ -919,23 +919,23 @@ - + - Update Channels + Start - + - Start + Stop - + - Stop + Channels @@ -979,13 +979,6 @@ - - - - ... - - - @@ -1713,8 +1706,8 @@ 0 0 - 96 - 86 + 413 + 401 diff --git a/src/cadence.py b/src/cadence.py index 81160db..7f5ec89 100755 --- a/src/cadence.py +++ b/src/cadence.py @@ -125,11 +125,15 @@ XDG_APPLICATIONS_PATH = [ WINEASIO_PREFIX = "HKEY_CURRENT_USER\Software\Wine\WineASIO" # --------------------------------------------------------------------- +class PulseAudioJackBridgeValues(object): + clientIdCapture = -1 + clientIdPlayback = -1 + portCaptureNumber = 0 + portPlaybackNumber = 0 -global jackClientIdALSA, jackClientIdPulseCapture, jackClientIdPulsePlayback -jackClientIdALSA = -1 -jackClientIdPulseCapture = -1 -jackClientIdPulsePlayback = -1 +global jackClientIdALSA +jackClientIdALSA = -1 +pA_bridge_values = PulseAudioJackBridgeValues() # jackdbus indexes iGraphVersion = 0 @@ -343,8 +347,7 @@ def isPulseAudioStarted(): return bool("pulseaudio" in getProcList()) def isPulseAudioBridged(): - global jackClientIdPulseCapture, jackClientIdPulsePlayback - return bool(jackClientIdPulseCapture != -1 or jackClientIdPulsePlayback != -1) + return bool(pA_bridge_values.clientIdCapture != -1 or pA_bridge_values.clientIdPlayback != -1) def isDesktopFileInstalled(desktop): for X_PATH in XDG_APPLICATIONS_PATH: @@ -747,20 +750,24 @@ class ToolBarA2JDialog(QDialog, ui_cadence_tb_a2j.Ui_Dialog): self.close() # Additional PulseAudio options -class ToolBarPADialog(QDialog, ui_cadence_tb_pa.Ui_Dialog): +class PAChannelsDialog(QDialog, ui_cadence_tb_pa.Ui_Dialog): def __init__(self, parent): QDialog.__init__(self, parent) self.setupUi(self) + self.parent = parent self.spinBoxPulseInputs.setValue(GlobalSettings.value("Pulse2JACK/CaptureChannels", 2, type=int)) self.spinBoxPulseOutputs.setValue(GlobalSettings.value("Pulse2JACK/PlaybackChannels", 2, type=int)) - self.accepted.connect(self.slot_setOptions) + self.accepted.connect(self.slot_updateChannels) @pyqtSlot() - def slot_setOptions(self): + def slot_updateChannels(self): GlobalSettings.setValue("Pulse2JACK/CaptureChannels", self.spinBoxPulseInputs.value()) GlobalSettings.setValue("Pulse2JACK/PlaybackChannels", self.spinBoxPulseOutputs.value()) + + if isPulseAudioBridged(): + self.parent.slot_PulseAudioBridgeStart() def done(self, r): QDialog.done(self, r) @@ -770,8 +777,10 @@ class ToolBarPADialog(QDialog, ui_cadence_tb_pa.Ui_Dialog): class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): DBusJackServerStartedCallback = pyqtSignal() DBusJackServerStoppedCallback = pyqtSignal() - DBusJackClientAppearedCallback = pyqtSignal(int, str) + DBusJackClientAppearedCallback = pyqtSignal(int, str) DBusJackClientDisappearedCallback = pyqtSignal(int) + DBusJackPortAppearedCallback = pyqtSignal(int) + DBusJackPortDisappearedCallback = pyqtSignal(int) DBusA2JBridgeStartedCallback = pyqtSignal() DBusA2JBridgeStoppedCallback = pyqtSignal() @@ -1098,6 +1107,7 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): self.systray.addMenu("pulse", self.tr("PulseAudio Bridge")) self.systray.addMenuAction("pulse", "pulse_start", self.tr("Start")) self.systray.addMenuAction("pulse", "pulse_stop", self.tr("Stop")) + self.systray.addMenuAction("pulse", "pulse_channels", self.tr("Channels")) self.systray.setActionIcon("jack_start", "media-playback-start") self.systray.setActionIcon("jack_stop", "media-playback-stop") @@ -1108,6 +1118,7 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): self.systray.setActionIcon("a2j_stop", "media-playback-stop") self.systray.setActionIcon("pulse_start", "media-playback-start") self.systray.setActionIcon("pulse_stop", "media-playback-stop") + self.systray.setActionIcon("pulse_channels", "audio-card") self.systray.connect("jack_start", self.slot_JackServerStart) self.systray.connect("jack_stop", self.slot_JackServerStop) @@ -1119,6 +1130,7 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): self.systray.connect("a2j_export_hw", self.slot_A2JBridgeExportHW) self.systray.connect("pulse_start", self.slot_PulseAudioBridgeStart) self.systray.connect("pulse_stop", self.slot_PulseAudioBridgeStop) + self.systray.connect("pulse_channels", self.slot_PulseAudioBridgeChannels) self.systray.addMenu("tools", self.tr("Tools")) self.systray.addMenuAction("tools", "app_catarina", "Catarina") @@ -1163,11 +1175,10 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): self.b_a2j_stop.clicked.connect(self.slot_A2JBridgeStop) self.b_a2j_export_hw.clicked.connect(self.slot_A2JBridgeExportHW) self.tb_a2j_options.clicked.connect(self.slot_A2JBridgeOptions) - - self.b_pulse_update.clicked.connect(self.slot_PulseAudioBridgeStart) + self.b_pulse_start.clicked.connect(self.slot_PulseAudioBridgeStart) self.b_pulse_stop.clicked.connect(self.slot_PulseAudioBridgeStop) - self.tb_pulse_options.clicked.connect(self.slot_PulseAudioBridgeOptions) + self.b_pulse_channels.clicked.connect(self.slot_PulseAudioBridgeChannels) self.pic_catia.clicked.connect(self.func_start_catia) self.pic_claudia.clicked.connect(self.func_start_claudia) @@ -1219,6 +1230,8 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): # org.jackaudio.JackPatchbay self.DBusJackClientAppearedCallback.connect(self.slot_DBusJackClientAppearedCallback) self.DBusJackClientDisappearedCallback.connect(self.slot_DBusJackClientDisappearedCallback) + self.DBusJackPortAppearedCallback.connect(self.slot_DBusJackPortAppearedCallback) + self.DBusJackPortDisappearedCallback.connect(self.slot_DBusJackPortDisappearedCallback) # org.gna.home.a2jmidid.control self.DBusA2JBridgeStartedCallback.connect(self.slot_DBusA2JBridgeStartedCallback) @@ -1267,11 +1280,11 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): global jackClientIdALSA jackClientIdALSA = group_id elif group_name == "PulseAudio JACK Source": - global jackClientIdPulseCapture - jackClientIdPulseCapture = group_id + pA_bridge_values.clientIdCapture = group_id + pA_bridge_values.portCaptureNumber = len(ports) elif group_name == "PulseAudio JACK Sink": - global jackClientIdPulsePlayback - jackClientIdPulsePlayback = group_id + pA_bridge_values.clientIdPlayback = group_id + pA_bridge_values.portPlaybackNumber = len(ports) self.jackStarted() @@ -1336,6 +1349,10 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): self.DBusJackClientAppearedCallback.emit(args[iJackClientId], args[iJackClientName]) elif kwds['member'] == "ClientDisappeared": self.DBusJackClientDisappearedCallback.emit(args[iJackClientId]) + elif kwds['member'] == "PortAppeared": + self.DBusJackPortAppearedCallback.emit(args[iJackClientId]) + elif kwds['member'] == "PortDisappeared": + self.DBusJackPortDisappearedCallback.emit(args[iJackClientId]) elif kwds['interface'] == "org.gna.home.a2jmidid.control": if DEBUG: print("org.gna.home.a2jmidid.control", kwds['member']) @@ -1409,11 +1426,12 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): if gDBus.a2j: self.b_a2j_start.setEnabled(False) self.systray.setActionEnabled("a2j_start", False) - - global jackClientIdALSA, jackClientIdPulseCapture, jackClientIdPulsePlayback + + global jackClientIdALSA jackClientIdALSA = -1 - jackClientIdPulseCapture = -1 - jackClientIdPulsePlayback = -1 + + pA_bridge_values.clientIdCapture = -1 + pA_bridge_values.clientIdPlayback = -1 if haveDBus: self.checkAlsaAudio() @@ -1513,15 +1531,13 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): if isPulseAudioStarted(): if isPulseAudioBridged(): - self.b_pulse_update.setEnabled(True) self.b_pulse_start.setEnabled(False) self.b_pulse_stop.setEnabled(True) self.systray.setActionEnabled("pulse_start", False) self.systray.setActionEnabled("pulse_stop", True) - self.label_bridge_pulse.setText(self.tr("PulseAudio is started and bridged to JACK")) + self.label_bridge_pulse.setText(self.tr("PulseAudio is started and bridged to JACK with %s inputs/%s outputs") % (pA_bridge_values.portCaptureNumber, pA_bridge_values.portPlaybackNumber)) else: jackRunning = bool(gDBus.jack and gDBus.jack.IsStarted()) - self.b_pulse_update.setEnabled(jackRunning) self.b_pulse_start.setEnabled(jackRunning) self.b_pulse_stop.setEnabled(False) self.systray.setActionEnabled("pulse_start", jackRunning) @@ -1529,7 +1545,6 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): self.label_bridge_pulse.setText(self.tr("PulseAudio is started but not bridged")) else: jackRunning = bool(gDBus.jack and gDBus.jack.IsStarted()) - self.b_pulse_update.setEnabled(False) self.b_pulse_start.setEnabled(jackRunning) self.b_pulse_stop.setEnabled(False) self.systray.setActionEnabled("pulse_start", jackRunning) @@ -1657,27 +1672,45 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): jackClientIdALSA = group_id self.checkAlsaAudio() elif group_name == "PulseAudio JACK Source": - global jackClientIdPulseCapture - jackClientIdPulseCapture = group_id + pA_bridge_values.clientIdCapture = group_id self.checkPulseAudio() elif group_name == "PulseAudio JACK Sink": - global jackClientIdPulsePlayback - jackClientIdPulsePlayback = group_id + pA_bridge_values.clientIdPlayback = group_id self.checkPulseAudio() @pyqtSlot(int) def slot_DBusJackClientDisappearedCallback(self, group_id): - global jackClientIdALSA, jackClientIdPulseCapture, jackClientIdPulsePlayback + global jackClientIdALSA if group_id == jackClientIdALSA: jackClientIdALSA = -1 self.checkAlsaAudio() - elif group_id == jackClientIdPulseCapture: - jackClientIdPulseCapture = -1 + elif group_id == pA_bridge_values.clientIdCapture: + pA_bridge_values.clientIdCapture = -1 + pA_bridge_values.portCaptureNumber = 0 self.checkPulseAudio() - elif group_id == jackClientIdPulsePlayback: - jackClientIdPulsePlayback = -1 + elif group_id == pA_bridge_values.clientIdPlayback: + pA_bridge_values.clientIdPlayback = -1 + pA_bridge_values.portPlaybackNumber = 0 self.checkPulseAudio() - + + @pyqtSlot(int) + def slot_DBusJackPortAppearedCallback(self, group_id): + if group_id == pA_bridge_values.clientIdCapture: + pA_bridge_values.portCaptureNumber+=1 + self.checkPulseAudio() + elif group_id == pA_bridge_values.clientIdPlayback: + pA_bridge_values.portPlaybackNumber+=1 + self.checkPulseAudio() + + @pyqtSlot(int) + def slot_DBusJackPortDisappearedCallback(self, group_id): + if group_id == pA_bridge_values.clientIdCapture: + pA_bridge_values.portCaptureNumber+=1 + self.checkPulseAudio() + elif group_id == pA_bridge_values.clientIdPlayback: + pA_bridge_values.portPlaybackNumber+=1 + self.checkPulseAudio() + @pyqtSlot() def slot_DBusA2JBridgeStartedCallback(self): self.a2jStarted() @@ -1840,8 +1873,8 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): os.system("pulseaudio -k") @pyqtSlot() - def slot_PulseAudioBridgeOptions(self): - ToolBarPADialog(self).exec_() + def slot_PulseAudioBridgeChannels(self): + PAChannelsDialog(self).exec_() @pyqtSlot() def slot_handleCrash_jack(self): From 5a2801b096cc8bfc70c0408dad5b16a61db68d99 Mon Sep 17 00:00:00 2001 From: houston Date: Tue, 22 May 2018 13:12:37 +0200 Subject: [PATCH 4/4] change script name in help --- data/cadence-pulse2jack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/cadence-pulse2jack b/data/cadence-pulse2jack index 4753856..bf667cb 100755 --- a/data/cadence-pulse2jack +++ b/data/cadence-pulse2jack @@ -62,7 +62,7 @@ for arg in "$@";do --dummy Don't do anything, just create the needed files NOTE: - When runned with no arguments, pulse2jack will + When runned with no arguments, $(basename "$0") will activate PulseAudio with both playback and record modes with default number of channels. " exit