@@ -43,38 +43,66 @@ else | |||||
fi | fi | ||||
# ---------------------------------------------- | # ---------------------------------------------- | ||||
wanted_capture_ports=0 # -1 means default | |||||
wanted_playback_ports=0 # -1 means default | |||||
PLAY_ONLY="no" | |||||
arg_is_for="" | |||||
case $1 in | |||||
-h|--h|--help) | |||||
echo "usage: $0 [command] | |||||
for arg in "$@";do | |||||
case "$arg" in | |||||
-h|--h|--help) | |||||
echo "usage: $0 [command] | |||||
-p Playback only with default number of channels | |||||
-p <NUMBER> Number of playback channels | |||||
-c Capture only with default number of channels | |||||
-c <NUMBER> Number of capture channels | |||||
-p, --play Playback mode only | |||||
-h, --help Show this help menu | |||||
--dummy Don't do anything, just create the needed files | |||||
-h, --help Show this help menu | |||||
--dummy Don't do anything, just create the needed files | |||||
NOTE: | |||||
When runned with no arguments, $(basename "$0") 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 | |||||
NOTE: | |||||
When runned with no arguments, pulse2jack will | |||||
activate PulseAudio with both playback and record modes. | |||||
" | |||||
exit | |||||
;; | |||||
--dummy) | |||||
exit | |||||
;; | |||||
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 | |||||
-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="" ## | |||||
# ---------------------------------------------- | # ---------------------------------------------- | ||||
@@ -88,40 +116,166 @@ IsPulseAudioRunning() | |||||
fi | fi | ||||
} | } | ||||
if (IsPulseAudioRunning); then | |||||
StartBridged() | |||||
{ | { | ||||
if (`jack_lsp | grep "PulseAudio JACK Sink:" > /dev/null`); then | |||||
{ | |||||
echo "PulseAudio is already running and bridged to JACK" | |||||
} | |||||
#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 | else | ||||
{ | |||||
echo "PulseAudio is already running, bridge it..." | |||||
echo "Failed to initialize PulseAudio!" | |||||
fi | |||||
} | |||||
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 | |||||
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) || 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) | |||||
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 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 || killReStart | |||||
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 | pacmd set-default-source jack_in > /dev/null | ||||
} | |||||
fi | 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 || killReStart | |||||
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 | fi | ||||
} | } | ||||
else | else | ||||
{ | |||||
if (`pulseaudio --daemonize --high-priority --realtime --exit-idle-time=-1 --file=$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 | fi |
@@ -7,7 +7,7 @@ | |||||
<x>0</x> | <x>0</x> | ||||
<y>0</y> | <y>0</y> | ||||
<width>740</width> | <width>740</width> | ||||
<height>564</height> | |||||
<height>680</height> | |||||
</rect> | </rect> | ||||
</property> | </property> | ||||
<property name="windowTitle"> | <property name="windowTitle"> | ||||
@@ -544,7 +544,16 @@ | |||||
<string>JACK Bridges</string> | <string>JACK Bridges</string> | ||||
</property> | </property> | ||||
<layout class="QGridLayout" name="gridLayout_5"> | <layout class="QGridLayout" name="gridLayout_5"> | ||||
<property name="margin"> | |||||
<property name="leftMargin"> | |||||
<number>2</number> | |||||
</property> | |||||
<property name="topMargin"> | |||||
<number>2</number> | |||||
</property> | |||||
<property name="rightMargin"> | |||||
<number>2</number> | |||||
</property> | |||||
<property name="bottomMargin"> | |||||
<number>2</number> | <number>2</number> | ||||
</property> | </property> | ||||
<item row="0" column="0"> | <item row="0" column="0"> | ||||
@@ -572,8 +581,8 @@ | |||||
<rect> | <rect> | ||||
<x>0</x> | <x>0</x> | ||||
<y>0</y> | <y>0</y> | ||||
<width>360</width> | |||||
<height>100</height> | |||||
<width>435</width> | |||||
<height>130</height> | |||||
</rect> | </rect> | ||||
</property> | </property> | ||||
<attribute name="label"> | <attribute name="label"> | ||||
@@ -720,8 +729,8 @@ | |||||
<rect> | <rect> | ||||
<x>0</x> | <x>0</x> | ||||
<y>0</y> | <y>0</y> | ||||
<width>360</width> | |||||
<height>97</height> | |||||
<width>435</width> | |||||
<height>130</height> | |||||
</rect> | </rect> | ||||
</property> | </property> | ||||
<attribute name="label"> | <attribute name="label"> | ||||
@@ -854,8 +863,8 @@ | |||||
<rect> | <rect> | ||||
<x>0</x> | <x>0</x> | ||||
<y>0</y> | <y>0</y> | ||||
<width>360</width> | |||||
<height>97</height> | |||||
<width>435</width> | |||||
<height>130</height> | |||||
</rect> | </rect> | ||||
</property> | </property> | ||||
<attribute name="label"> | <attribute name="label"> | ||||
@@ -916,6 +925,13 @@ | |||||
</property> | </property> | ||||
</widget> | </widget> | ||||
</item> | </item> | ||||
<item> | |||||
<widget class="QPushButton" name="b_pulse_channels"> | |||||
<property name="text"> | |||||
<string>Channels</string> | |||||
</property> | |||||
</widget> | |||||
</item> | |||||
<item> | <item> | ||||
<spacer name="horizontalSpacer_13"> | <spacer name="horizontalSpacer_13"> | ||||
<property name="orientation"> | <property name="orientation"> | ||||
@@ -956,13 +972,6 @@ | |||||
</property> | </property> | ||||
</widget> | </widget> | ||||
</item> | </item> | ||||
<item> | |||||
<widget class="QToolButton" name="tb_pulse_options"> | |||||
<property name="text"> | |||||
<string>...</string> | |||||
</property> | |||||
</widget> | |||||
</item> | |||||
</layout> | </layout> | ||||
</item> | </item> | ||||
<item> | <item> | ||||
@@ -1572,7 +1581,7 @@ | |||||
<string>Audio Plugins PATH</string> | <string>Audio Plugins PATH</string> | ||||
</property> | </property> | ||||
<property name="textAlignment"> | <property name="textAlignment"> | ||||
<set>AlignHCenter|AlignVCenter|AlignCenter</set> | |||||
<set>AlignCenter</set> | |||||
</property> | </property> | ||||
<property name="flags"> | <property name="flags"> | ||||
<set>ItemIsSelectable|ItemIsEnabled</set> | <set>ItemIsSelectable|ItemIsEnabled</set> | ||||
@@ -1583,7 +1592,7 @@ | |||||
<string>Default Applications</string> | <string>Default Applications</string> | ||||
</property> | </property> | ||||
<property name="textAlignment"> | <property name="textAlignment"> | ||||
<set>AlignHCenter|AlignVCenter|AlignCenter</set> | |||||
<set>AlignCenter</set> | |||||
</property> | </property> | ||||
<property name="flags"> | <property name="flags"> | ||||
<set>ItemIsSelectable|ItemIsEnabled</set> | <set>ItemIsSelectable|ItemIsEnabled</set> | ||||
@@ -1594,7 +1603,7 @@ | |||||
<string>WineASIO</string> | <string>WineASIO</string> | ||||
</property> | </property> | ||||
<property name="textAlignment"> | <property name="textAlignment"> | ||||
<set>AlignHCenter|AlignVCenter|AlignCenter</set> | |||||
<set>AlignCenter</set> | |||||
</property> | </property> | ||||
<property name="flags"> | <property name="flags"> | ||||
<set>ItemIsSelectable|ItemIsEnabled</set> | <set>ItemIsSelectable|ItemIsEnabled</set> | ||||
@@ -1613,7 +1622,16 @@ | |||||
</property> | </property> | ||||
<widget class="QWidget" name="page_plugins"> | <widget class="QWidget" name="page_plugins"> | ||||
<layout class="QGridLayout" name="gridLayout_6"> | <layout class="QGridLayout" name="gridLayout_6"> | ||||
<property name="margin"> | |||||
<property name="leftMargin"> | |||||
<number>0</number> | |||||
</property> | |||||
<property name="topMargin"> | |||||
<number>0</number> | |||||
</property> | |||||
<property name="rightMargin"> | |||||
<number>0</number> | |||||
</property> | |||||
<property name="bottomMargin"> | |||||
<number>0</number> | <number>0</number> | ||||
</property> | </property> | ||||
<item row="3" column="1"> | <item row="3" column="1"> | ||||
@@ -1681,8 +1699,8 @@ | |||||
<rect> | <rect> | ||||
<x>0</x> | <x>0</x> | ||||
<y>0</y> | <y>0</y> | ||||
<width>416</width> | |||||
<height>334</height> | |||||
<width>413</width> | |||||
<height>401</height> | |||||
</rect> | </rect> | ||||
</property> | </property> | ||||
<attribute name="label"> | <attribute name="label"> | ||||
@@ -1711,8 +1729,8 @@ | |||||
<rect> | <rect> | ||||
<x>0</x> | <x>0</x> | ||||
<y>0</y> | <y>0</y> | ||||
<width>94</width> | |||||
<height>66</height> | |||||
<width>96</width> | |||||
<height>86</height> | |||||
</rect> | </rect> | ||||
</property> | </property> | ||||
<attribute name="label"> | <attribute name="label"> | ||||
@@ -1741,8 +1759,8 @@ | |||||
<rect> | <rect> | ||||
<x>0</x> | <x>0</x> | ||||
<y>0</y> | <y>0</y> | ||||
<width>94</width> | |||||
<height>66</height> | |||||
<width>96</width> | |||||
<height>86</height> | |||||
</rect> | </rect> | ||||
</property> | </property> | ||||
<attribute name="label"> | <attribute name="label"> | ||||
@@ -1771,8 +1789,8 @@ | |||||
<rect> | <rect> | ||||
<x>0</x> | <x>0</x> | ||||
<y>0</y> | <y>0</y> | ||||
<width>94</width> | |||||
<height>66</height> | |||||
<width>96</width> | |||||
<height>86</height> | |||||
</rect> | </rect> | ||||
</property> | </property> | ||||
<attribute name="label"> | <attribute name="label"> | ||||
@@ -1832,12 +1850,21 @@ | |||||
</widget> | </widget> | ||||
<widget class="QWidget" name="page_apps"> | <widget class="QWidget" name="page_apps"> | ||||
<layout class="QGridLayout" name="gridLayout_7"> | <layout class="QGridLayout" name="gridLayout_7"> | ||||
<property name="verticalSpacing"> | |||||
<number>20</number> | |||||
<property name="leftMargin"> | |||||
<number>0</number> | |||||
</property> | |||||
<property name="topMargin"> | |||||
<number>0</number> | |||||
</property> | |||||
<property name="rightMargin"> | |||||
<number>0</number> | |||||
</property> | </property> | ||||
<property name="margin"> | |||||
<property name="bottomMargin"> | |||||
<number>0</number> | <number>0</number> | ||||
</property> | </property> | ||||
<property name="verticalSpacing"> | |||||
<number>20</number> | |||||
</property> | |||||
<item row="1" column="0"> | <item row="1" column="0"> | ||||
<widget class="QCheckBox" name="ch_app_image"> | <widget class="QCheckBox" name="ch_app_image"> | ||||
<property name="text"> | <property name="text"> | ||||
@@ -2063,7 +2090,16 @@ | |||||
</widget> | </widget> | ||||
<widget class="QWidget" name="page_wineasio"> | <widget class="QWidget" name="page_wineasio"> | ||||
<layout class="QVBoxLayout" name="verticalLayout_17"> | <layout class="QVBoxLayout" name="verticalLayout_17"> | ||||
<property name="margin"> | |||||
<property name="leftMargin"> | |||||
<number>0</number> | |||||
</property> | |||||
<property name="topMargin"> | |||||
<number>0</number> | |||||
</property> | |||||
<property name="rightMargin"> | |||||
<number>0</number> | |||||
</property> | |||||
<property name="bottomMargin"> | |||||
<number>0</number> | <number>0</number> | ||||
</property> | </property> | ||||
<item> | <item> | ||||
@@ -6,8 +6,8 @@ | |||||
<rect> | <rect> | ||||
<x>0</x> | <x>0</x> | ||||
<y>0</y> | <y>0</y> | ||||
<width>317</width> | |||||
<height>72</height> | |||||
<width>218</width> | |||||
<height>124</height> | |||||
</rect> | </rect> | ||||
</property> | </property> | ||||
<property name="windowTitle"> | <property name="windowTitle"> | ||||
@@ -15,11 +15,60 @@ | |||||
</property> | </property> | ||||
<layout class="QVBoxLayout" name="verticalLayout"> | <layout class="QVBoxLayout" name="verticalLayout"> | ||||
<item> | <item> | ||||
<widget class="QCheckBox" name="cb_playback_only"> | |||||
<property name="text"> | |||||
<string>Playback Mode only</string> | |||||
</property> | |||||
</widget> | |||||
<layout class="QGridLayout" name="gridLayout"> | |||||
<item row="0" column="0"> | |||||
<widget class="QLabel" name="labelPulseInputs"> | |||||
<property name="text"> | |||||
<string>Input Channels :</string> | |||||
</property> | |||||
<property name="alignment"> | |||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> | |||||
</property> | |||||
</widget> | |||||
</item> | |||||
<item row="1" column="0"> | |||||
<widget class="QLabel" name="labelPulseOutputs"> | |||||
<property name="text"> | |||||
<string>Output Channels :</string> | |||||
</property> | |||||
<property name="alignment"> | |||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> | |||||
</property> | |||||
</widget> | |||||
</item> | |||||
<item row="0" column="1"> | |||||
<widget class="QSpinBox" name="spinBoxPulseInputs"> | |||||
<property name="specialValueText"> | |||||
<string>Default</string> | |||||
</property> | |||||
<property name="minimum"> | |||||
<number>-1</number> | |||||
</property> | |||||
<property name="maximum"> | |||||
<number>10</number> | |||||
</property> | |||||
<property name="value"> | |||||
<number>-1</number> | |||||
</property> | |||||
</widget> | |||||
</item> | |||||
<item row="1" column="1"> | |||||
<widget class="QSpinBox" name="spinBoxPulseOutputs"> | |||||
<property name="specialValueText"> | |||||
<string>Default</string> | |||||
</property> | |||||
<property name="minimum"> | |||||
<number>-1</number> | |||||
</property> | |||||
<property name="maximum"> | |||||
<number>10</number> | |||||
</property> | |||||
<property name="value"> | |||||
<number>-1</number> | |||||
</property> | |||||
</widget> | |||||
</item> | |||||
</layout> | |||||
</item> | </item> | ||||
<item> | <item> | ||||
<widget class="QDialogButtonBox" name="buttonBox"> | <widget class="QDialogButtonBox" name="buttonBox"> | ||||
@@ -116,10 +116,15 @@ XDG_APPLICATIONS_PATH = [ | |||||
WINEASIO_PREFIX = "HKEY_CURRENT_USER\Software\Wine\WineASIO" | WINEASIO_PREFIX = "HKEY_CURRENT_USER\Software\Wine\WineASIO" | ||||
# --------------------------------------------------------------------- | # --------------------------------------------------------------------- | ||||
class PulseAudioJackBridgeValues(object): | |||||
clientIdCapture = -1 | |||||
clientIdPlayback = -1 | |||||
portCaptureNumber = 0 | |||||
portPlaybackNumber = 0 | |||||
global jackClientIdALSA, jackClientIdPulse | |||||
jackClientIdALSA = -1 | |||||
jackClientIdPulse = -1 | |||||
global jackClientIdALSA | |||||
jackClientIdALSA = -1 | |||||
pA_bridge_values = PulseAudioJackBridgeValues() | |||||
# jackdbus indexes | # jackdbus indexes | ||||
iGraphVersion = 0 | iGraphVersion = 0 | ||||
@@ -333,8 +338,7 @@ def isPulseAudioStarted(): | |||||
return bool("pulseaudio" in getProcList()) | return bool("pulseaudio" in getProcList()) | ||||
def isPulseAudioBridged(): | def isPulseAudioBridged(): | ||||
global jackClientIdPulse | |||||
return bool(jackClientIdPulse != -1) | |||||
return bool(pA_bridge_values.clientIdCapture != -1 or pA_bridge_values.clientIdPlayback != -1) | |||||
def isDesktopFileInstalled(desktop): | def isDesktopFileInstalled(desktop): | ||||
for X_PATH in XDG_APPLICATIONS_PATH: | for X_PATH in XDG_APPLICATIONS_PATH: | ||||
@@ -581,10 +585,10 @@ class ForceRestartThread(QThread): | |||||
# PulseAudio | # PulseAudio | ||||
if GlobalSettings.value("Pulse2JACK/AutoStart", True, type=bool) and not isPulseAudioBridged(): | 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) | self.progressChanged.emit(100) | ||||
@@ -718,18 +722,24 @@ class ToolBarAlsaAudioDialog(QDialog, ui_cadence_tb_alsa.Ui_Dialog): | |||||
self.close() | self.close() | ||||
# Additional PulseAudio options | # 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): | def __init__(self, parent): | ||||
QDialog.__init__(self, parent) | QDialog.__init__(self, parent) | ||||
self.setupUi(self) | 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.cb_playback_only.setChecked(GlobalSettings.value("Pulse2JACK/PlaybackModeOnly", False, type=bool)) | |||||
self.accepted.connect(self.slot_setOptions) | |||||
self.accepted.connect(self.slot_updateChannels) | |||||
@pyqtSlot() | @pyqtSlot() | ||||
def slot_setOptions(self): | |||||
GlobalSettings.setValue("Pulse2JACK/PlaybackModeOnly", self.cb_playback_only.isChecked()) | |||||
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): | def done(self, r): | ||||
QDialog.done(self, r) | QDialog.done(self, r) | ||||
@@ -739,8 +749,10 @@ class ToolBarPADialog(QDialog, ui_cadence_tb_pa.Ui_Dialog): | |||||
class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | ||||
DBusJackServerStartedCallback = pyqtSignal() | DBusJackServerStartedCallback = pyqtSignal() | ||||
DBusJackServerStoppedCallback = pyqtSignal() | DBusJackServerStoppedCallback = pyqtSignal() | ||||
DBusJackClientAppearedCallback = pyqtSignal(int, str) | |||||
DBusJackClientAppearedCallback = pyqtSignal(int, str) | |||||
DBusJackClientDisappearedCallback = pyqtSignal(int) | DBusJackClientDisappearedCallback = pyqtSignal(int) | ||||
DBusJackPortAppearedCallback = pyqtSignal(int) | |||||
DBusJackPortDisappearedCallback = pyqtSignal(int) | |||||
DBusA2JBridgeStartedCallback = pyqtSignal() | DBusA2JBridgeStartedCallback = pyqtSignal() | ||||
DBusA2JBridgeStoppedCallback = pyqtSignal() | DBusA2JBridgeStoppedCallback = pyqtSignal() | ||||
@@ -1066,6 +1078,7 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
self.systray.addMenu("pulse", self.tr("PulseAudio Bridge")) | self.systray.addMenu("pulse", self.tr("PulseAudio Bridge")) | ||||
self.systray.addMenuAction("pulse", "pulse_start", self.tr("Start")) | self.systray.addMenuAction("pulse", "pulse_start", self.tr("Start")) | ||||
self.systray.addMenuAction("pulse", "pulse_stop", self.tr("Stop")) | 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_start", "media-playback-start") | ||||
self.systray.setActionIcon("jack_stop", "media-playback-stop") | self.systray.setActionIcon("jack_stop", "media-playback-stop") | ||||
@@ -1076,6 +1089,7 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
self.systray.setActionIcon("a2j_stop", "media-playback-stop") | self.systray.setActionIcon("a2j_stop", "media-playback-stop") | ||||
self.systray.setActionIcon("pulse_start", "media-playback-start") | self.systray.setActionIcon("pulse_start", "media-playback-start") | ||||
self.systray.setActionIcon("pulse_stop", "media-playback-stop") | 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_start", self.slot_JackServerStart) | ||||
self.systray.connect("jack_stop", self.slot_JackServerStop) | self.systray.connect("jack_stop", self.slot_JackServerStop) | ||||
@@ -1086,6 +1100,7 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
self.systray.connect("a2j_stop", self.slot_A2JBridgeStop) | self.systray.connect("a2j_stop", self.slot_A2JBridgeStop) | ||||
self.systray.connect("pulse_start", self.slot_PulseAudioBridgeStart) | self.systray.connect("pulse_start", self.slot_PulseAudioBridgeStart) | ||||
self.systray.connect("pulse_stop", self.slot_PulseAudioBridgeStop) | 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.addMenu("tools", self.tr("Tools")) | ||||
self.systray.addMenuAction("tools", "app_catarina", "Catarina") | self.systray.addMenuAction("tools", "app_catarina", "Catarina") | ||||
@@ -1128,9 +1143,10 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
self.b_a2j_start.clicked.connect(self.slot_A2JBridgeStart) | self.b_a2j_start.clicked.connect(self.slot_A2JBridgeStart) | ||||
self.b_a2j_stop.clicked.connect(self.slot_A2JBridgeStop) | self.b_a2j_stop.clicked.connect(self.slot_A2JBridgeStop) | ||||
self.b_pulse_start.clicked.connect(self.slot_PulseAudioBridgeStart) | self.b_pulse_start.clicked.connect(self.slot_PulseAudioBridgeStart) | ||||
self.b_pulse_stop.clicked.connect(self.slot_PulseAudioBridgeStop) | 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_catia.clicked.connect(self.func_start_catia) | ||||
self.pic_claudia.clicked.connect(self.func_start_claudia) | self.pic_claudia.clicked.connect(self.func_start_claudia) | ||||
@@ -1182,6 +1198,8 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
# org.jackaudio.JackPatchbay | # org.jackaudio.JackPatchbay | ||||
self.DBusJackClientAppearedCallback.connect(self.slot_DBusJackClientAppearedCallback) | self.DBusJackClientAppearedCallback.connect(self.slot_DBusJackClientAppearedCallback) | ||||
self.DBusJackClientDisappearedCallback.connect(self.slot_DBusJackClientDisappearedCallback) | self.DBusJackClientDisappearedCallback.connect(self.slot_DBusJackClientDisappearedCallback) | ||||
self.DBusJackPortAppearedCallback.connect(self.slot_DBusJackPortAppearedCallback) | |||||
self.DBusJackPortDisappearedCallback.connect(self.slot_DBusJackPortDisappearedCallback) | |||||
# org.gna.home.a2jmidid.control | # org.gna.home.a2jmidid.control | ||||
self.DBusA2JBridgeStartedCallback.connect(self.slot_DBusA2JBridgeStartedCallback) | self.DBusA2JBridgeStartedCallback.connect(self.slot_DBusA2JBridgeStartedCallback) | ||||
@@ -1230,9 +1248,12 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
if group_name == "alsa2jack": | if group_name == "alsa2jack": | ||||
global jackClientIdALSA | global jackClientIdALSA | ||||
jackClientIdALSA = group_id | jackClientIdALSA = group_id | ||||
elif group_name == "PulseAudio JACK Source": | |||||
pA_bridge_values.clientIdCapture = group_id | |||||
pA_bridge_values.portCaptureNumber = len(ports) | |||||
elif group_name == "PulseAudio JACK Sink": | elif group_name == "PulseAudio JACK Sink": | ||||
global jackClientIdPulse | |||||
jackClientIdPulse = group_id | |||||
pA_bridge_values.clientIdPlayback = group_id | |||||
pA_bridge_values.portPlaybackNumber = len(ports) | |||||
self.jackStarted() | self.jackStarted() | ||||
@@ -1298,6 +1319,10 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
self.DBusJackClientAppearedCallback.emit(args[iJackClientId], args[iJackClientName]) | self.DBusJackClientAppearedCallback.emit(args[iJackClientId], args[iJackClientName]) | ||||
elif kwds['member'] == "ClientDisappeared": | elif kwds['member'] == "ClientDisappeared": | ||||
self.DBusJackClientDisappearedCallback.emit(args[iJackClientId]) | 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": | elif kwds['interface'] == "org.gna.home.a2jmidid.control": | ||||
if DEBUG: print("org.gna.home.a2jmidid.control", kwds['member']) | if DEBUG: print("org.gna.home.a2jmidid.control", kwds['member']) | ||||
@@ -1378,10 +1403,12 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
if gDBus.a2j: | if gDBus.a2j: | ||||
self.b_a2j_start.setEnabled(False) | self.b_a2j_start.setEnabled(False) | ||||
self.systray.setActionEnabled("a2j_start", False) | self.systray.setActionEnabled("a2j_start", False) | ||||
global jackClientIdALSA, jackClientIdPulse | |||||
jackClientIdALSA = -1 | |||||
jackClientIdPulse = -1 | |||||
global jackClientIdALSA | |||||
jackClientIdALSA = -1 | |||||
pA_bridge_values.clientIdCapture = -1 | |||||
pA_bridge_values.clientIdPlayback = -1 | |||||
if haveDBus: | if haveDBus: | ||||
self.checkAlsaAudio() | self.checkAlsaAudio() | ||||
@@ -1484,7 +1511,7 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
self.b_pulse_stop.setEnabled(True) | self.b_pulse_stop.setEnabled(True) | ||||
self.systray.setActionEnabled("pulse_start", False) | self.systray.setActionEnabled("pulse_start", False) | ||||
self.systray.setActionEnabled("pulse_stop", True) | 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: | else: | ||||
jackRunning = bool(gDBus.jack and gDBus.jack.IsStarted()) | jackRunning = bool(gDBus.jack and gDBus.jack.IsStarted()) | ||||
self.b_pulse_start.setEnabled(jackRunning) | self.b_pulse_start.setEnabled(jackRunning) | ||||
@@ -1620,21 +1647,46 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
global jackClientIdALSA | global jackClientIdALSA | ||||
jackClientIdALSA = group_id | jackClientIdALSA = group_id | ||||
self.checkAlsaAudio() | self.checkAlsaAudio() | ||||
elif group_name == "PulseAudio JACK Source": | |||||
pA_bridge_values.clientIdCapture = group_id | |||||
self.checkPulseAudio() | |||||
elif group_name == "PulseAudio JACK Sink": | elif group_name == "PulseAudio JACK Sink": | ||||
global jackClientIdPulse | |||||
jackClientIdPulse = group_id | |||||
pA_bridge_values.clientIdPlayback = group_id | |||||
self.checkPulseAudio() | self.checkPulseAudio() | ||||
@pyqtSlot(int) | @pyqtSlot(int) | ||||
def slot_DBusJackClientDisappearedCallback(self, group_id): | def slot_DBusJackClientDisappearedCallback(self, group_id): | ||||
global jackClientIdALSA, jackClientIdPulse | |||||
global jackClientIdALSA | |||||
if group_id == jackClientIdALSA: | if group_id == jackClientIdALSA: | ||||
jackClientIdALSA = -1 | jackClientIdALSA = -1 | ||||
self.checkAlsaAudio() | self.checkAlsaAudio() | ||||
elif group_id == jackClientIdPulse: | |||||
jackClientIdPulse = -1 | |||||
elif group_id == pA_bridge_values.clientIdCapture: | |||||
pA_bridge_values.clientIdCapture = -1 | |||||
pA_bridge_values.portCaptureNumber = 0 | |||||
self.checkPulseAudio() | self.checkPulseAudio() | ||||
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() | @pyqtSlot() | ||||
def slot_DBusA2JBridgeStartedCallback(self): | def slot_DBusA2JBridgeStartedCallback(self): | ||||
self.a2jStarted() | self.a2jStarted() | ||||
@@ -1788,18 +1840,18 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
@pyqtSlot() | @pyqtSlot() | ||||
def slot_PulseAudioBridgeStart(self): | 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() | @pyqtSlot() | ||||
def slot_PulseAudioBridgeStop(self): | def slot_PulseAudioBridgeStop(self): | ||||
os.system("pulseaudio -k") | os.system("pulseaudio -k") | ||||
@pyqtSlot() | @pyqtSlot() | ||||
def slot_PulseAudioBridgeOptions(self): | |||||
ToolBarPADialog(self).exec_() | |||||
def slot_PulseAudioBridgeChannels(self): | |||||
PAChannelsDialog(self).exec_() | |||||
@pyqtSlot() | @pyqtSlot() | ||||
def slot_handleCrash_jack(self): | def slot_handleCrash_jack(self): | ||||