Electron snap having trouble using sox

I have an app that uses electron. I want to snap it. I have the following problem with the audio. I use sox in the app, but in the snap the program cannot find the sox executable, or it calls it inappropriately, I am not sure which one. Otherwise my app seems to work.

I can run the program with ‘npm run start’, and I can get the flatpak system to containerize the app, and it works mostly from there too. I feel I am doing something simple wrong. My host system is ubuntu 22.04.

    $ DEBUG=record gpt-etc 

I get this error.

    Gtk-Message: 10:48:46.984: Failed to load module "colorreload-gtk-module"
    Gtk-Message: 10:48:46.984: Failed to load module "window-decorations-gtk-module"
    [54366:0529/104854.279497:ERROR:sandbox_linux.cc(377)] InitializeSandbox() called with multiple threads in process gpu-process.
      record Started recording +0ms
      record {
      record   sampleRate: 16000,
      record   channels: 1,
      record   compress: false,
      record   threshold: 0,
      record   thresholdStart: null,
      record   thresholdEnd: null,
      record   silence: '10.0',
      record   recorder: 'sox',
      record   endOnSilence: false,
      record   audioType: 'wav',
      record   sampleRateHertz: 16000,
      record   verbose: false,
      record   recordProgram: 'rec'
      record } +1ms
      record  sox --default-device --no-show-progress --rate 16000 --channels 1 --encoding signed-integer --bits 16 --type wav - +4ms
      record Recording ended +241ms
      record STDERR: sox FAIL sox: Sorry, there is no default audio device configured
      record  +11ms
    sox has exited with error code 1.

This is part of my snapcraft.yaml file.

    apps:
      #sox:
      #  command: sox
      gpt-etc:
        command: gpt-etc/gpt-etc --no-sandbox
        extensions: [gnome-3-38]
        plugs:
        - browser-support
        - network
        - network-bind
        - pulseaudio
        - alsa 
        - audio-record
        - audio-playback
        environment:
          # Correct the TMPDIR path for Chromium Framework/Electron to ensure
          # libappindicator has readable resources.
          TMPDIR: $XDG_RUNTIME_DIR
          LD_LIBRARY_PATH: $LD_LIBRARY_PATH:$SNAP/usr/lib 

    parts:
      #sox:
      #  plugin: autotools
      #  source: https://sourceforge.net/projects/sox/files/sox/14.4.0/sox-14.4.0.tar.gz/download    
      #  source-type: tar

      gpt-etc:
        plugin: nil
        source: . 
        override-build: |
          npm install electron electron-packager
          npx electron-packager . --overwrite --platform=linux --output=release-build --prune=true
          cp -rv gpt-etc* $SNAPCRAFT_PART_INSTALL/gpt-etc
        build-snaps:
          - node/16/stable
        build-packages:
          - unzip
        stage-packages:
          - libnss3
          - libnspr4
          - sox
          - libsox-dev 
          - libsox-fmt-all
          - libpulse0

try using:

that should map a virtual alsa device inside the snap env to the pulseaudio server outside the snap … so that sox actually plays though a fake alsa setup …

Thank you. I did not use the mixin that you linked to, though I tried it and could not get it to work. I ended up with something else. After adding lots of elements to parts, I have something that works part of the time.

If I set an AUDIODEV=hw:0 in the command to start my snap, it will capture audio and also play audio back. My problem now, and the reason I’m writing, is that the app will record input once, and then on the second attempt, find that the device is busy.

layout:
  $SNAP/usr/local/bin/sox:
    bind-file: $SNAP/usr/bin/sox
  /usr/lib/$SNAPCRAFT_ARCH_TRIPLET/alsa-lib:
    bind: $SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/alsa-lib
  /etc/asound.conf:
    bind-file: $SNAP/etc/asound.conf
  /usr/share/alsa/alsa.conf:
    bind-file: $SNAP/usr/share/alsa/alsa.conf
  /etc/alsa/conf.d:
    bind: $SNAP/usr/etc/alsa/conf.d 

parts:
  sox:
    plugin: autotools 
    source: https://sourceforge.net/projects/sox/files/sox/14.4.1/sox-14.4.1.tar.gz/download    
    source-type: tar
    build-packages:
      - libsox-dev
      - libasound2-dev
    autotools-configure-parameters:
      - --bindir=/usr/bin 
      - --libdir=/usr/lib/$SNAPCRAFT_ARCH_TRIPLET
    stage-packages:
      - libsox-dev
      - libsox-fmt-all
      - libaudio-dev
      - libsndio-dev
      - alsa-utils
      - libsndio7.0
      - libasound2-dev
      - libasound2-plugins

  alsa:
      plugin: nil
      source: https://github.com/diddledan/snapcraft-alsa.git
      override-pull: |
        cat > alsa.conf <<EOF
        pcm.!default {
          type pulse
          fallback "sysdefault"
          hint {
            show on
            description "Default ALSA Output (currently PulseAudio Sound Server)"
          }
        }
        ctl.!default {
          type pulse
          fallback "sysdefault"
        }
        EOF
      override-build: |
        install -m644 -D -t $SNAPCRAFT_PART_INSTALL/etc alsa.conf
      build-packages:
        - libasound2-dev
      stage-packages:
        - libasound2
        - libasound2-plugins
        - libpulse0
        - pulseaudio

  gpt-etc:
    plugin: nil
    source: . 
    override-build: |
      npm install electron electron-packager
      npx electron-packager . --overwrite --platform=linux --output=release-build --prune=true
      cp -rv gpt-etc* $SNAPCRAFT_PART_INSTALL/gpt-etc
    build-snaps:
      - node/16/stable
    build-packages:
      - unzip
    stage-packages:
      - libnss3
      - libnspr4
      - alsa-base
      - ffmpeg
      - libavcodec-dev
      - libgtk-3-0

This is how I call my snap:

AUDIODEV=hw:0 DEBUG=record gpt-etc

This is the content of the error at the time I try to make my second recording.

record Started recording +7s
  record {
  record   sampleRate: 16000,
  record   channels: 1,
  record   compress: false,
  record   threshold: 0,
  record   thresholdStart: null,
  record   thresholdEnd: null,
  record   silence: '10.0',
  record   recorder: 'sox',
  record   endOnSilence: false,
  record   audioType: 'wav',
  record   sampleRateHertz: 16000,
  record   verbose: false,
  record   recordProgram: 'rec'
  record } +0ms
  record  sox --default-device --no-show-progress --rate 16000 --channels 1 --encoding signed-integer --bits 16 --type wav - +1ms
  record STDERR: sox FAIL formats: can't open input  `hw:0': snd_pcm_open error: Device or resource busy
  record  +11ms
  record Recording ended +0ms
sox has exited with error code 2.

I found that the snap works the same if I totally remove the ‘alsa’ part. After that I moved several dependencies to the gpt-etc part. I must say that with regard to the dependencies, I threw alot of packages at the audio problem that perhaps I did not need. Still, the snapcraft.yaml file is smaller now.

One of the node packages I use uses sox to record audio. I don’t have access to the code that actually calls sox. I have three problems. One: sox doesn’t record anything (because the default device cannot be found by sox version 14.4), Two: sox doesn’t record anything (because the AUDIODEV is not known to the snap) or Three: sox finds that the audio device that it used previously is busy.

I have found solutions for the first two problems.

I have to use sox from source, as the ubuntu package for sox uses version 14.4.2, which throws an error always. This is the first error I mentioned. When I build sox from an earlier version, the first issue I have goes away. If I use AUDIODEV the snap records audio when the app is run. This is the solution to the second problem. The snap seems to work momentarily. It records audio once. After that, when I would like the snap to record again, I get the third error.

I did find that I had to set the variable ‘AUDIODEV’ in the host. This is the second error. This looked like this:

    AUDIODEV=hw:1,6 DEBUG=record gpt-etc ## <-- this is for the record device

I posted recently my progress from another computer. On that machine the AUDIODEV is set to hw:0 . Regardless of the machine, the pattern is the same.

Below is a portion of my snapcraft file.

    apps:
      gpt-etc:
        command: gpt-etc/gpt-etc --no-sandbox
        extensions: [gnome-3-38]
          
        plugs:
        - browser-support
        - network
        - network-bind
        - alsa 
        - pulseaudio
        - audio-record
        - audio-playback
        environment:
          # Correct the TMPDIR path for Chromium Framework/Electron to ensure
          # libappindicator has readable resources.
          TMPDIR: $XDG_RUNTIME_DIR

    parts:
      sox:
        plugin: autotools 
        source: https://sourceforge.net/projects/sox/files/sox/14.3.2/sox-14.3.2.tar.gz/download    
        source-type: tar
        build-packages:
          - libsox-dev
          - libasound2-dev
        autotools-configure-parameters:
          - --bindir=/usr/bin 
          - --libdir=/usr/lib/$SNAPCRAFT_ARCH_TRIPLET
        stage-packages:
          - libsox-dev
          - libsox-fmt-all
          - libaudio-dev
          - libsndio-dev
          - alsa-utils
          - libsndio7.0
          - libasound2-dev
          - libasound2-plugins

      gpt-etc:
        plugin: nil
        source: . 
        override-build: |
          case "$SNAP_ARCH" in
            "amd64") SARCH='x64'
            ;;
            "arm64") SARCH='arm64'
            ;;
            *)
              echo "Unsupported architecture for this app build"
              exit 1
            ;;
          esac
          npm install electron electron-packager
          npx electron-packager . --overwrite --platform=linux --output=release-build --prune=true --arch=$SARCH 
          cp -rv gpt-etc* $SNAPCRAFT_PART_INSTALL/gpt-etc
        build-snaps:
          - node/16/stable
        build-packages:
          - unzip
        stage-packages:
          - libnss3
          - libnspr4
          - alsa-base
          - ffmpeg
          - libavcodec-dev
          - libgtk-3-0
          - libasound2-dev
          - libasound2
          - libasound2-plugins
          - libpulse0
          - pulseaudio
          - pulseaudio-utils
          - libaudio-dev
          - libsndio-dev
          - alsa-utils
          - libsndio7.0

One thing I don’t understand is that the node app works properly from my current install of ubuntu. If I type ‘npm run start’ in the project home directory, the app works. The sox package, apparently, is using a version that works with my node js app. You would think that ubuntu used the most recent version, whereas we think that that version does not work with the electron project when we are packaging it.