Skip to content

Commit

Permalink
Boot - set env vars for pipewire (matching pw-jack's behaviour) (#3349)
Browse files Browse the repository at this point in the history
pw-jack sets the PIPEWIRE_QUANTUM and LD_LIBRARY_PATH env vars before execing a binary. To use this we'd need to run sonic pi from pw-jack (so the exec would do its work correctly). Instead of that we set the env vars within the call to popen2e when starting scsynth to match this behaviour.

It is now also possible to use new change pipewire's buffsize and samplerate with two new audio-settings.toml config options:

```
linux_pipewire_buffsize = 1024
linux_pipewire_samplerate = 4800
```
  • Loading branch information
samaaron authored Nov 1, 2023
1 parent 68edde6 commit 5fbe330
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 5 deletions.
11 changes: 11 additions & 0 deletions app/config/user-examples/audio-settings.toml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,17 @@
# num_random_seeds = 64


## ===============================
## Linux Audio - Pipewire settings
## ===============================
#
# Sonic Pi uses pipewire for Audio on Linux
# You can modify the pipewire parameters here:

# linux_pipewire_buffsize = 1024
# linux_pipewire_samplerate = 48000



## ============
## Escape hatch
Expand Down
49 changes: 44 additions & 5 deletions app/server/ruby/bin/daemon.rb
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,8 @@ def idempotent_exit_cleanup

class ProcessBooter
attr_reader :pid, :args, :cmd, :log
def initialize(cmd, args, log_path, record_log=false)
def initialize(cmd, args, log_path, record_log=false, env=nil)
@env = env
@pid = nil
@log_file = nil
@args = args.map {|el| el.to_s}
Expand Down Expand Up @@ -786,7 +787,11 @@ def disable_internal_log_recording!
def boot
Util.log "Process Booter - booting #{@cmd} with args #{@args.inspect}"
Util.log "#{@cmd} #{@args.join(' ')}"
@stdin, @stdout_and_err, @wait_thr = Open3.popen2e @cmd, *@args
if @env
@stdin, @stdout_and_err, @wait_thr = Open3.popen2e @env, @cmd, *@args
else
@stdin, @stdout_and_err, @wait_thr = Open3.popen2e @cmd, *@args
end
@pid = @wait_thr.pid
if @log_file
@io_thr = Thread.new do
Expand Down Expand Up @@ -1030,7 +1035,6 @@ def kill
end
end


class JackBooter < ProcessBooter
def initialize
cmd = "jackd"
Expand Down Expand Up @@ -1134,6 +1138,10 @@ def initialize(ports, no_scsynth_inputs=false)
toml_opts_hash = {}
end

# freeze toml_opts_hash in case any nasty mutation happens below
# (oh for immutable data structures by default!)
toml_opts_hash.freeze

Util.log "Got Audio Settings toml hash: #{toml_opts_hash.inspect}"
opts = unify_toml_opts_hash(toml_opts_hash)
Util.log "Unified Audio Settings toml hash: #{opts.inspect}"
Expand All @@ -1145,9 +1153,40 @@ def initialize(ports, no_scsynth_inputs=false)
@num_outputs = opts["-o"].to_i
args = opts.to_a.flatten
cmd = Paths.scsynth_path

case Util.os
when :linux, :raspberry
toml_pw_buffsize = toml_opts_hash[:linux_pipewire_buffsize].to_i
toml_pw_samplerate = toml_opts_hash[:linux_pipewire_samplerate].to_i
pw_buffsize = 1024
pw_samplerate = 48000

if (toml_opts_hash.has_key?(:linux_pipewire_buffsize) && (toml_pw_buffsize > 0))
Util.log "Setting pipewire buffsize to: #{toml_pw_buffsize}"
pw_buffsize = toml_pw_buffsize
else
Util.log "Using default pipewire buffsize of: 1024"
end

if (toml_opts_hash.has_key?(:linux_pipewire_samplerate) && (toml_pw_samplerate > 0))
Util.log "Setting pipewire samplerate to: #{toml_pw_samplerate}"
pw_samplerate = toml_pw_samplerate
else
Util.log "Using default pipewire samplerate of: 48000"
end

ld_library_path = `pw-jack /bin/sh -c 'echo $LD_LIBRARY_PATH'`.strip
pw_quantum ="#{pw_buffsize}/#{pw_samplerate}"

Util.log "Starting scsynth with LD_LIBRARY_PATH set to #{ld_library_path.inspect} so it uses pipewire's jack"
env = { "PIPEWIRE_QUANTUM" => pw_quantum , "LD_LIBRARY_PATH" => ld_library_path }
else
env = nil
end

@success = Promise.new
run_pre_start_commands
super(cmd, args, Paths.scsynth_log_path, true)
super(cmd, args, Paths.scsynth_log_path, true, env)
run_post_start_commands
success = wait_for_boot
disable_internal_log_recording!
Expand Down Expand Up @@ -1234,7 +1273,7 @@ def run_pre_start_commands
end
end
end

def run_post_start_commands
case Util.os
when :raspberry, :linux
Expand Down

2 comments on commit 5fbe330

@samaaron
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@porras if you have a spare moment, could you test to see if this commit (and the current state of the dev branch) is compatible with your Flatpak build process? I think we're pretty much ready for tagging...

@porras
Copy link
Contributor

@porras porras commented on 5fbe330 Nov 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi! I did (sorry I commented in the pr #3349). It works and as far as flatpak is concerned it is good to go. I mentioned a possible backwards compatibility issue but it's theoretical, I cannot test that on my system which does have pipewire.

Please sign in to comment.