Focusrite Scarlett 18i8 Interface not setting sample sate with pipewire-alsa

Hello all,
I am new to openSUSE tumbleweed after a brief stint with arch and love it so far! I don’t know if this is entirely relevant but I am using Gnome 46 with X11 primarily due to some Wayland specific issues with certain applications like ungoogled chromium and flatpak Steam.

However, I cannot seem for the life of me to get my Scarlett 18i8 interface to work consistently. For example, when launching a game the audio will be distorted almost as if it has an extremely low bitrate and sample rate. After some troubleshooting I seem to think it’s because (at least under the information displayed by the alsa-scarlett-ui interface ( GitHub - geoffreybennett/alsa-scarlett-gui: alsa-scarlett-gui is a Gtk4 GUI for the ALSA controls presented by the Linux kernel Focusrite Scarlett2 Mixer Driver ) my sample rate is N/A.

Whenever viewing youtube videos for example, I will see it set to 48k and if I then launch a game - Cyberpunk 2077 to be specific - the audio will work correctly. After the video or game stops the sample rate returns to N/A. I have narrowed down most of the other audio problems to be game specific (for example V’s dialogue is much quieter than other NPCs… Jeez gives me flashbacks to the early days of when the game first dropped lol) since audio sounds normal in other applications. But is there a way to configure my interface to have a static internal sample rate even wtihout running applications? I swear this has happened by default with other OSes so I do not believe it is my hardware. I have also verified my routing and such are correct for my stereo speakers so I am suspecting its something to do with the underlying pipewire / pulseaudio / alsa stuff as openSUSE implements it.

I have set my default.clock.rate to 192000 and added the supported rates for the interface in default.clock.allowed-rates within my pipewire.conf config so am not sure why this is happening. Perhaps this is a fundamental misunderstanding on my part (and likely so) but in previous distros I have never seen this problem arise before.

If anyone else has experineced this problem before or knows of any good resouces to send my way that would be much appreciated. Or if someone would be willing to explain openSUSE’s audio implementatation in plain english so I may gain some intution on how to solve this problem. A good pipewire GUI would be nice as well however most I’ve seen online seem to have stopped being actively developed on.

Otherwise - and despite this hair pulling problem - I love openSUSE so far and I think my days of hopping around communities has finally reached its end!

Cheers! and thank you in advance :slight_smile: I hope to see you all around the forums in the forseeable future!

# Daemon config file for PipeWire version "1.2.2" #
#
# Copy and edit this file in /etc/pipewire for system-wide changes
# or in ~/.config/pipewire for local changes.
#
# It is also possible to place a file with an updated section in
# /etc/pipewire/pipewire.conf.d/ for system-wide changes or in
# ~/.config/pipewire/pipewire.conf.d/ for local changes.
#

context.properties = {
    ## Configure properties in the system.
    #library.name.system                   = support/libspa-support
    #context.data-loop.library.name.system = support/libspa-support
    #support.dbus                          = true
    link.max-buffers                      = 64
    #link.max-buffers                       = 16                       # version < 3 clients can't handle more
    #mem.warn-mlock                        = false
    #mem.allow-mlock                       = true
    #mem.mlock-all                         = false
    #clock.power-of-two-quantum            = true
    #log.level                             = 2
    #cpu.zero.denormals                    = false

    #loop.rt-prio = -1            # -1 = use module-rt prio, 0 disable rt
    #loop.class = data.rt
    #thread.affinity = [ 0 1 ]    # optional array of CPUs
    #context.num-data-loops = 1   # -1 = num-cpus, 0 = no data loops
    #
    #context.data-loops = [
    #    {   loop.rt-prio = -1
    #        loop.class = [ data.rt audio.rt ]
    #        #library.name.system = support/libspa-support
    #        thread.name = data-loop.0
    #        #thread.affinity = [ 0 1 ]    # optional array of CPUs
    #    }
    #]

    core.daemon = true              # listening for socket connections
    core.name   = pipewire-0        # core name and socket name

    ## Properties for the DSP configuration.
    default.clock.rate          = 192000
    default.clock.allowed-rates = [ 44100, 48000, 88200, 96000, 176400, 192000 ]
    #default.clock.quantum       = 1024
    #default.clock.min-quantum   = 32
    #default.clock.max-quantum   = 2048
    #default.clock.quantum-limit = 8192
    #default.clock.quantum-floor = 4
    #default.video.width         = 640
    #default.video.height        = 480
    #default.video.rate.num      = 25
    #default.video.rate.denom    = 1
    #
    #settings.check-quantum      = false
    #settings.check-rate         = false

    # keys checked below to disable module loading
    module.x11.bell = true
    # enables autoloading of access module, when disabled an alternative
    # access module needs to be loaded.
    module.access = true
    # enables autoloading of module-jackdbus-detect
    module.jackdbus-detect = true
}

context.properties.rules = [
    {   matches = [ { cpu.vm.name = !null } ]
        actions = {
            update-props = {
                # These overrides are only applied when running in a vm.
                default.clock.min-quantum = 1024
	    }
        }
    }
]

context.spa-libs = {
    #<factory-name regex> = <library-name>
    #
    # Used to find spa factory names. It maps an spa factory name
    # regular expression to a library name that should contain
    # that factory.
    #
    audio.convert.* = audioconvert/libspa-audioconvert
    avb.*           = avb/libspa-avb
    api.alsa.*      = alsa/libspa-alsa
    api.v4l2.*      = v4l2/libspa-v4l2
    api.libcamera.* = libcamera/libspa-libcamera
    api.bluez5.*    = bluez5/libspa-bluez5
    api.vulkan.*    = vulkan/libspa-vulkan
    api.jack.*      = jack/libspa-jack
    support.*       = support/libspa-support
    video.convert.* = videoconvert/libspa-videoconvert
    #videotestsrc   = videotestsrc/libspa-videotestsrc
    #audiotestsrc   = audiotestsrc/libspa-audiotestsrc
}

context.modules = [
    #{ name = <module-name>
    #    ( args  = { <key> = <value> ... } )
    #    ( flags = [ ( ifexists ) ( nofail ) ] )
    #    ( condition = [ { <key> = <value> ... } ... ] )
    #}
    #
    # Loads a module with the given parameters.
    # If ifexists is given, the module is ignored when it is not found.
    # If nofail is given, module initialization failures are ignored.
    # If condition is given, the module is loaded only when the context
    # properties all match the match rules.
    #

    # Uses realtime scheduling to boost the audio thread priorities. This uses
    # RTKit if the user doesn't have permission to use regular realtime
    # scheduling. You can also clamp utilisation values to improve scheduling
    # on embedded and heterogeneous systems, e.g. Arm big.LITTLE devices.
    { name = libpipewire-module-rt
        args = {
            nice.level    = -11
            rt.prio       = 88
            #rt.time.soft = -1
            #rt.time.hard = -1
            #uclamp.min = 0
            #uclamp.max = 1024
        }
        flags = [ ifexists nofail ]
    }

    # The native communication protocol.
    { name = libpipewire-module-protocol-native
        args = {
            # List of server Unix sockets, and optionally permissions
            #sockets = [ { name = "pipewire-0" }, { name = "pipewire-0-manager" } ]
        }
    }

    # The profile module. Allows application to access profiler
    # and performance data. It provides an interface that is used
    # by pw-top and pw-profiler.
    { name = libpipewire-module-profiler }

    # Allows applications to create metadata objects. It creates
    # a factory for Metadata objects.
    { name = libpipewire-module-metadata }

    # Creates a factory for making devices that run in the
    # context of the PipeWire server.
    { name = libpipewire-module-spa-device-factory }

    # Creates a factory for making nodes that run in the
    # context of the PipeWire server.
    { name = libpipewire-module-spa-node-factory }

    # Allows creating nodes that run in the context of the
    # client. Is used by all clients that want to provide
    # data to PipeWire.
    { name = libpipewire-module-client-node }

    # Allows creating devices that run in the context of the
    # client. Is used by the session manager.
    { name = libpipewire-module-client-device }

    # The portal module monitors the PID of the portal process
    # and tags connections with the same PID as portal
    # connections.
    { name = libpipewire-module-portal
        flags = [ ifexists nofail ]
    }

    # The access module can perform access checks and block
    # new clients.
    { name = libpipewire-module-access
        args = {
            # Socket-specific access permissions
            #access.socket = { pipewire-0 = "default", pipewire-0-manager = "unrestricted" }

            # Deprecated legacy mode (not socket-based),
            # for now enabled by default if access.socket is not specified
            #access.legacy = true
        }
        condition = [ { module.access = true } ]
    }

    # Makes a factory for wrapping nodes in an adapter with a
    # converter and resampler.
    { name = libpipewire-module-adapter }

    # Makes a factory for creating links between ports.
    { name = libpipewire-module-link-factory }

    # Provides factories to make session manager objects.
    { name = libpipewire-module-session-manager }

    # Use libcanberra to play X11 Bell
    { name = libpipewire-module-x11-bell
        args = {
            #sink.name = "@DEFAULT_SINK@"
            #sample.name = "bell-window-system"
            #x11.display = null
            #x11.xauthority = null
        }
        flags = [ ifexists nofail ]
        condition = [ { module.x11.bell = true } ]
    }
    { name = libpipewire-module-jackdbus-detect
        args = {
            #jack.library     = libjack.so.0
            #jack.server      = null
            #jack.client-name = PipeWire
            #jack.connect     = true
            #tunnel.mode      = duplex  # source|sink|duplex
            source.props = {
                #audio.channels = 2
		#midi.ports = 1
                #audio.position = [ FL FR ]
                # extra sink properties
            }
            sink.props = {
                #audio.channels = 2
		#midi.ports = 1
                #audio.position = [ FL FR ]
                # extra sink properties
            }
        }
        flags = [ ifexists nofail ]
        condition = [ { module.jackdbus-detect = true } ]
    }
]

context.objects = [
    #{ factory = <factory-name>
    #    ( args  = { <key> = <value> ... } )
    #    ( flags = [ ( nofail ) ] )
    #    ( condition = [ { <key> = <value> ... } ... ] )
    #}
    #
    # Creates an object from a PipeWire factory with the given parameters.
    # If nofail is given, errors are ignored (and no object is created).
    # If condition is given, the object is created only when the context properties
    # all match the match rules.
    #
    #{ factory = spa-node-factory   args = { factory.name = videotestsrc node.name = videotestsrc node.description = videotestsrc "Spa:Pod:Object:Param:Props:patternType" = 1 } }
    #{ factory = spa-device-factory args = { factory.name = api.jack.device foo=bar } flags = [ nofail ] }
    #{ factory = spa-device-factory args = { factory.name = api.alsa.enum.udev } }
    #{ factory = spa-node-factory   args = { factory.name = api.alsa.seq.bridge node.name = Internal-MIDI-Bridge } }
    #{ factory = adapter            args = { factory.name = audiotestsrc node.name = my-test node.description = audiotestsrc } }
    #{ factory = spa-node-factory   args = { factory.name = api.vulkan.compute.source node.name = my-compute-source } }

    # A default dummy driver. This handles nodes marked with the "node.always-process"
    # property when no other driver is currently active. JACK clients need this.
    { factory = spa-node-factory
        args = {
            factory.name    = support.node.driver
            node.name       = Dummy-Driver
            node.group      = pipewire.dummy
            node.sync-group  = sync.dummy
            priority.driver = 20000
            #clock.id       = monotonic # realtime | tai | monotonic-raw | boottime
            #clock.name     = "clock.system.monotonic"
        }
    }
    { factory = spa-node-factory
        args = {
            factory.name    = support.node.driver
            node.name       = Freewheel-Driver
            priority.driver = 19000
            node.group      = pipewire.freewheel
            node.sync-group  = sync.dummy
            node.freewheel  = true
            #freewheel.wait = 10
        }
    }

    # This creates a new Source node. It will have input ports
    # that you can link, to provide audio for this source.
    #{ factory = adapter
    #    args = {
    #        factory.name     = support.null-audio-sink
    #        node.name        = "my-mic"
    #        node.description = "Microphone"
    #        media.class      = "Audio/Source/Virtual"
    #        audio.position   = "FL,FR"
    #        monitor.passthrough = true
    #    }
    #}

    # This creates a single PCM source device for the given
    # alsa device path hw:0. You can change source to sink
    # to make a sink in the same way.
    #{ factory = adapter
    #    args = {
    #        factory.name           = api.alsa.pcm.source
    #        node.name              = "alsa-source"
    #        node.description       = "PCM Source"
    #        media.class            = "Audio/Source"
    #        api.alsa.path          = "hw:0"
    #        api.alsa.period-size   = 1024
    #        api.alsa.headroom      = 0
    #        api.alsa.disable-mmap  = false
    #        api.alsa.disable-batch = false
    #        audio.format           = "S16LE"
    #        audio.rate             = 48000
    #        audio.channels         = 2
    #        audio.position         = "FL,FR"
    #    }
    #}

    # Use the metadata factory to create metadata and some default values.
    #{ factory = metadata
    #    args = {
    #        metadata.name = my-metadata
    #        metadata.values = [
    #            { key = default.audio.sink   value = { name = somesink } }
    #            { key = default.audio.source value = { name = somesource } }
    #        ]
    #    }
    #}
]

context.exec = [
    #{   path = <program-name>
    #    ( args = "<arguments>" | [ <arg1> <arg2> ... ] )
    #    ( condition = [ { <key> = <value> ... } ... ] )
    #}
    #
    # Execute the given program with arguments.
    # If condition is given, the program is executed only when the context
    # properties all match the match rules.
    #
    # You can optionally start the session manager here,
    # but it is better to start it as a systemd service.
    # Run the session manager with -h for options.
    #
    #{ path = "/usr/bin/pipewire-media-session" args = ""
    #  condition = [ { exec.session-manager = null } { exec.session-manager = true } ] }
    #
    # You can optionally start the pulseaudio-server here as well
    # but it is better to start it as a systemd service.
    # It can be interesting to start another daemon here that listens
    # on another address with the -a option (eg. -a tcp:4713).
    #
    #{ path = "/usr/bin/pipewire" args = [ "-c" "pipewire-pulse.conf" ]
    #  condition = [ { exec.pipewire-pulse = null } { exec.pipewire-pulse = true } ] }
]

Update:

For some reason my system now sets my sample rate to 192kHz even without actively playing audio. The only thing that changed was I installed the OBS kernel-liqourix package so maybe it was a 6.10.4-1-default kernel bug? It also fixed the audio quality problems.

I also think I found the source of part of the problem for V’s dialogue being quiet too. When running wpctl status I can see that my device is set up to be recognized as a 7-1 surround system.

PipeWire 'pipewire-0' [1.2.2, krakhexd@wattsup, cookie:2452939963]
 └─ Clients:
        32. WirePlumber                         [1.2.2, krakhexd@wattsup, pid:3007]
        36. pipewire                            [1.2.2, krakhexd@wattsup, pid:3008]
        38. GNOME Volume Control Media Keys     [1.2.2, krakhexd@wattsup, pid:2800]
        47. WirePlumber [export]                [1.2.2, krakhexd@wattsup, pid:3007]
        48. gnome-shell                         [1.2.2, krakhexd@wattsup, pid:2697]
        49. GNOME Shell Volume Control          [1.2.2, krakhexd@wattsup, pid:2697]
        50. xdg-desktop-portal                  [1.2.2, krakhexd@wattsup, pid:3106]
       101. Steam Voice Settings                [1.2.2, krakhexd@wattsup, pid:134]
       102. Steam                               [1.2.2, krakhexd@wattsup, pid:134]
       103. Chromium input                      [1.2.2, krakhexd@wattsup, pid:231]
       123. gnome-control-center                [1.2.2, krakhexd@wattsup, pid:20059]
       156. wpctl                               [1.2.2, krakhexd@wattsup, pid:35067]
       183. GNOME Settings                      [1.2.2, krakhexd@wattsup, pid:20059]

Audio
 ├─ Devices:
 │      51. GA102 High Definition Audio Controller [alsa]
 │      52. Scarlett 18i8 3rd Gen               [alsa]
 │      53. Rembrandt Radeon High Definition Audio Controller [alsa]
 │      54. Family 17h/19h HD Audio Controller  [alsa]
 │  
 ├─ Sinks:
 │      60. GA102 High Definition Audio Controller Digital Stereo (HDMI) [vol: 0.40]
 │  *   62. Scarlett 18i8 3rd Gen Analog Surround 7.1 [vol: 0.54]
 │  
 ├─ Sources:
 │  *   61. Scarlett 18i8 3rd Gen Multichannel  [vol: 1.00]
 │  
 ├─ Filters:
 │  
 └─ Streams:
       127. GNOME Settings                                              
            108. input_SL        < Scarlett 18i8 USB:monitor_SL	[active]
            112. monitor_FR     
            114. monitor_RR     
            130. monitor_SL     
            132. monitor_RL     
            133. monitor_FL     
            140. input_RR        < Scarlett 18i8 USB:monitor_RR	[active]
            141. input_LFE       < Scarlett 18i8 USB:monitor_LFE	[active]
            142. input_RL        < Scarlett 18i8 USB:monitor_RL	[active]
            149. input_FR        < Scarlett 18i8 USB:monitor_FR	[active]
            153. monitor_LFE    
            157. input_FC        < Scarlett 18i8 USB:monitor_FC	[active]
            159. input_FL        < Scarlett 18i8 USB:monitor_FL	[active]
            161. monitor_FC     
            172. monitor_SR     
            173. input_SR        < Scarlett 18i8 USB:monitor_SR	[active]
       148. GNOME Settings                                              
            121. input_FR        < Scarlett 18i8 USB:capture_AUX1	[active]
            150. monitor_FL     
            152. monitor_FR     
            170. input_FL        < Scarlett 18i8 USB:capture_AUX0	[active]

Video
 ├─ Devices:
 │  
 ├─ Sinks:
 │  
 ├─ Sources:
 │  
 ├─ Filters:
 │  
 └─ Streams:

Settings
 └─ Default Configured Devices:
         0. Audio/Sink    alsa_output.usb-Focusrite_Scarlett_18i8_USB_F9C4V4K2386A34-00.analog-surround-71
         1. Audio/Source  alsa_input.usb-Focusrite_Scarlett_18i8_USB_F9C4V4K2386A34-00.multichannel-input

Is there any way to force it to be stereo? My routing is set up for such ( I think)

OK so through the Volume Control Pulseaudio app in the flathub repo I was able to change the device to a Pro Audio type which fixed speaker positioning. However, now I am back to being unable to establish a sample rate unless another open program already negotiates it.

Volume Control Pulseaudio app should be in a normal repo not flathub try install via yast

Thank you for the reply. I had already done so but found issues with that version.

~ > pavucontrol                                                                                                                                             3s
**
ERROR:../src/devicewidget.cc:116:void DeviceWidget::setVolume(const pa_cvolume&, bool): assertion failed: (v.channels == channelMap.channels)
Bail out! ERROR:../src/devicewidget.cc:116:void DeviceWidget::setVolume(const pa_cvolume&, bool): assertion failed: (v.channels == channelMap.channels)
[1]    16859 IOT instruction (core dumped)  pavucontrol
~ > sudo pavucontrol                                                                                                                                       IOT

(process:16919): Gtk-WARNING **: 21:42:51.915: Failed to open display
~ >

This error happened before I had experimented with the flatpak.

Use only one: PipeWire or PulseAudio.
You can route sound with PipeWire.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.