Playing sound at the same time from Rhasspy (Docker) and the host

I have a Pi Zero with a USB soundcard and a PS3 Eye set up with Rhasspy 2.5-pre in Docker. I’ve set up my asoundrc.conf to be able to play and record from multiple applications at the same time outside of Docker (which indicates to me that my dmix and dsnoop config is working), but then when I try to play back a file from the host and from within the Rhasspy container at the same time, I get an error from aplay:

root@1530daa229ed:/usr/lib/rhasspy-voltron# aplay etc/wav/beep_hi.wav 
ALSA lib pcm_dmix.c:1108:(snd_pcm_dmix_open) unable to open slave
aplay: main:828: audio open error: Device or resource busy

Has anyone had any success with getting sound to play on the host and inside a Docker container at the same time?

I’ve tried linking my /etc/asoundrc.conf into the container (-v /etc/asound.conf:/etc/asound.conf:ro), making /dev/snd available in the container (--device /dev/snd), and even setting the container to privileged without any success.

When the host is not playing and I have brought /dev/snd and my asoundrc.conf into the container, I can play multiple files from within the container as I would on the host. I’m not quite sure how the dmix ALSA plugin works, but if it accesses the hardware directly through DMA, perhaps the instance inside the Docker container is trying to grab the hardware device and create an entirely new dmix plugin instance within the container instead of using the existing one outside of the container. Any ALSA gurus have any ideas?

Because this is on a Pi Zero, I’d rather not run pulseaudio and hog more CPU…

Any advice would be appreciated! Thanks!

Well, I may have answered my own question. Running this:

$ aplay -D plug:dmix test.wav

in both the container and on the host at the same time results in both files being played back at the same time!

Now to figure out how to make this the default…

Just adapt the respeaker 2mic asound.conf

# The IPC key of dmix or dsnoop plugin must be unique
# If 555555 or 666666 is used by other processes, use another one


# use samplerate to resample as speexdsp resample is bad
defaults.pcm.rate_converter "samplerate"

pcm.!default {
    type asym
    playback.pcm "playback"
    capture.pcm "capture"
}

pcm.playback {
    type plug
    slave.pcm "dmixed"
}

pcm.capture {
    type plug
    slave.pcm "array"
}

pcm.dmixed {
    type dmix
    slave.pcm "hw:seeed2micvoicec"
    ipc_key 555555 
}

pcm.array {
    type dsnoop
    slave {
        pcm "hw:seeed2micvoicec"
        channels 2
    }
    ipc_key 666666
}

Found my problem. In my own asound.conf, I had the following line in my pcm.dmixed section:

   ipc_key_add_uid yes

This was causing the issue as the uid in the container was different from the uid in the host.
After I removed that line and reloaded the alsa config, all was working as expected.

Hope this helps someone else in the future!

Hello,

one question is this working when alsa conf as above is done only on host machine? I have problems, when modifying asound.conf on hot machine my Rhasspy running in Docker do not see changes. For example I created new PCM device for output into the file and I can see it corectly in aplay -L on host machine, but Rhasspy Docker even after restart do not list it as output device on the web configuration page under alsa output devices dropdown.

Thank you. :slight_smile:
litin

Make sure you run the container with --device /dev/snd, or add a devices: line to your docker-compose.yaml file.

Because I also have some extra plugins for my PS Eye mic, I map my asound.conf into the container as well. Here is my docker-compose.yaml:

version: "2"
services:
  rhasspy:
    container_name: rhasspy
    image: "rhasspy/rhasspy:2.5.0-pre-arm32v6"
    restart: unless-stopped
    ipc: host
    volumes:
        - "/home/pi/docker/rhasspy/profiles:/profiles"
        - "/etc/asound.conf:/etc/asound.conf"
    ports:
        - "12101:12101"
    devices:
        - "/dev/snd/:/dev/snd/"
    command: --user-profiles /profiles --profile en

And here is my /etc/asound.conf:

pcm.array {
  type hw
  card CameraB409241
}

pcm.dsnooped {
    type dsnoop
    ipc_key 666666
    ipc_perm 0666
    slave.pcm "array"
}

pcm.array_gain {
    type softvol
    slave.pcm "dsnooped"
    control {
      name "PSEye"
      count 2
      card 0
    }
    min_dB -10.0
    max_dB 30.0
}

pcm.cap {
  type plug
  slave.pcm "array_gain"
  slave.channels 4
  ttable {
    0.0 15.0
    1.1 15.0
  }
}

pcm.dmixed {
    type dmix
    ipc_key 555555
    ipc_perm 0666
    slave.pcm "hw:0,0"
}

pcm.!default {
    type asym
    playback.pcm {
        type plug
        slave.pcm "dmixed"
    }
    capture.pcm {
        type plug
        slave.pcm "cap"
   }
}

ctl.!default {
        type hw
        card 0
}

Hope it helps.

Like hawkeye says your missing an internal asound.conf
"/etc/asound.conf:/etc/asound.conf"

But not sure if you should share same and prob create another file for docker.

So you have unique ipc_key 555555

Thank you for help.

Yes I run container with standard

--device /dev/snd:/dev/snd \

otherwise I would not be able to get sound output from Rhasspy at all.

I just added to /etc/asound.conf

pcm.snapcast_fifo {
    type plug
    slave {
        pcm {
            type file
            file "/tmp/snapfifo"
            slave.pcm null
            format raw
        }
        rate 48000
        format s24_3le
        channels 2
    }
}

on the host machine I see:

# aplay -L
null
    Discard all samples (playback) or generate zero samples (capture)
snapcast_fifo
default:CARD=ArrayUAC10
    ReSpeaker 4 Mic Array (UAC1.0), USB Audio
    Default Audio Device
......

I am still not able to see snapcast_fifo in Rhasspy web under alsa devices dropdown. Should I redeploy Rhasspy container?

P.S.: As you can see I would prefer Rhasspy in Docker to output into pipe input of snapcast client running on the same host. As far as I understand, snapcast discouraging using mix devices for its output because in would introduce delay and therefore desynchronization of snapcat audio.

does docker have access to /tmp/snapfifo and does docker have access to an internal asound.conf?

If you map in your asound.conf as I did, you should see all your devices inside the container.

Nope and now I understand I need both… Thank you.

/etc/asound.conf - so alsa running in the Docker will see device
/tmp/snapfifo - to be able to share the pipe (output for Rhasspy, input for snapcast)

Thank you.

BTW:do you know about any other better way how to share Rhasspy output with media players running on the same machine or snapcast?

Yep, that’s it.

I use snapcast on my Pi as well and have not noticed any latency issues using alsa’s dmix. Snapcast’s snapclient is running on the host and Rhasspy is in Docker.

Docker always does me that way its confusing and a mistake I often make that its a container and contained with own devices and file structure.

“share Rhasspy output with media players running on the same machine or snapcast”?

As in media meta data rather than output? Container & host just think as seperate machines on the same network.

PS default for /tmp in raspbian isnt tmpfs so you could get a lot of writes to your sd card.

You can either create an fstab entry with tmpfs or use the above on the host.

tmpfs /tmp tmpfs defaults,noatime 0 0 or something in fstab

I usually spam the above as it was just a protest to get biantu repos to sort out the bad zram-config they have, but people seem to find it usefull.

Thank you. :slight_smile:
that is very good hint. Just one thing, I believe that named pipes are never written to disk, as they stay in RAM only. Anyway Zram is very god project for swap and other directories to prevent SDcard wear.

Doh not the named pipe but the file fifo /tmp/snapfifo apols. If the green activity light is on whilst in use then prob so, if not prob not.

Well IMHO fifo file == named pipe. Google says same. :slight_smile:
(https://www.linuxjournal.com/article/2156)

snapcast fifo: The server’s audio input is a named pipe /tmp/snapfifo.
(https://manpages.ubuntu.com/manpages/disco/man1/snapserver.1.html)

I am just saying /tmp on Raspbian is just part of the normal / root directory and file based.

Can not remember if Ubuntu moved to tmpfs by default or not.
If when using the green activity led is on then its constant file access, if not its likely ram.

The server’s audio input is a named pipe /tmp/snapfifo. All data that is fed into this
file will be send to the connected clients

That sounds very much like a file and if in /tmp on raspbian its not in ram, by default.

sudo apt-get install  inotify-tools
inotifywait -m /tmp

True

No, at least up to 18.04.

Base on snapcast decumentation it is not file, it is named pipe. Content written to named pipe is not be written to disk and it doesn’t matters where it resides (if on tmpfs mount point or zram or disk)

I hope, that it is no more clear. :wink:

Yeah had a look its just a mount point, thought the buffer was on disk