25

I would like record audio with ffmpeg when I capture my screen. The error I'm getting when using alsa is that is that my image does not have a sound card -f alsa -ac 2 -i hw:0

Here is how to reproduce on a fresh version of Ubuntu

Start a session in a new ubuntu docker image.

docker pull ubuntu
docker run -it --rm ubuntu

Setup alsa (Advanced Linux Sound Architecture)

apt-get update
apt-get install alsa-utils

List the sound cards

aplay -l
# aplay: device_list:268: no soundcards found...

And playing this sound will fail because this image doesn't have any sound cards

sudo aplay /usr/share/sounds/alsa/Front_Center.wav
Dan Rasmuson
  • 5,705
  • 5
  • 29
  • 45

4 Answers4

27

EDIT: after reading first comment to BMitch about not needing to play out to local computer

Im recommanding to use pulseaudio since its userspace code and no kernel modules are needed. It would seem unlikely to me that alsa would work for docker (though I could be wrong)

If I do this:

apt-get update
apt-get install pulseaudio socat
apt-get install alsa-utils
apt-get install ffmpeg

# Start the pulseaudio server
pulseaudio -D --exit-idle-time=-1

# Load the virtual sink and set it as default
pacmd load-module module-virtual-sink sink_name=v1
pacmd set-default-sink v1

# set the monitor of v1 sink to be the default source
pacmd set-default-source v1.monitor

# Start the ffmpeg capture to an audio file
ffmpeg -f pulse -i default out.mp3

then in a separate terminal

paplay /usr/share/sounds/alsa/Front_Center.wav

The audio of the WAV file is captured by ffmpeg and appears in the out.mp3

I dont really know what your X setup looks like but if you can get the audio going to pulseaudio, then ffmpeg will capture the audio without needing a real sound card

Original Answer: if you want the audio to get to the Mac OS sound card

I originally got to this page cos I was trying to get the playback of audio from within the VM to the Mac OS. But if you dont care about getting it out the VM, then the following is overly complicated. Im leaving it here though as this idea was why i ended up here

It is possible to use pulseaudio within the VM to play back a WAV file to the physical sound card. Im using docker 17.03.1-ce on Mac OS Sierra and have used brew to install sox. This setup also requires socat to be installed on the VM but someone with more pulseaduio knowledge (or if i get more time) should be able to remove this part i think

The strategy is to use paplay to play the wav file through pulseaudio and have pulseaudio send the audio out over the network on a port you published at start up of the VM. On the Mac-side, you'll connect to this published port and send the data through sox to the Mac.

1. MAC: pull and run image with published port

    docker pull ubuntu
    docker run -it --rm -p 127.0.0.1:3000:3000 ubuntu

2. VM: update and install the require packages

    apt-get update
    apt-get install pulseaudio socat
    apt-get install alsa-utils

Im only installing alsa-utils for the wav file, so you could remove this

3. VM: start the pulseaudio server

    pulseaudio -D --exit-idle-time=-1

This tell the server to fork to the background and not to exit based on inactivity

4. VM: create a "sink" for pulseaudio

The sink is where pulseaudio will send the audio data in a specific format:

    pacmd load-module module-pipe-sink file=/dev/audio format=s16 rate=44100 channels=2

This will send the audio to the file /dev/audio in signed 16-bit 2-channel at 44100Hz.

5. VM: Attach file to the network

This file now needs to be "attached" to the network, socat is used to create a listening socket at the published address (NOTE: there is no authentication here) that is ready to send the audio when the Mac-side connects

    socat file:/dev/audio tcp-listen:3000

6. MAC: read data from network into sox

On the Mac-side, we now need to connect to this port and send the detail, via sox, to the audio driver:

    nc 127.0.0.1 3000 | sox -traw -r44100 -b16 -c2 -e signed-integer - -d

the mac has netcat (nc) by default so Im using this here to connect to the published port and then pipe the data to sox, with flags to sox to match the values set in the "load-module" statement above.

7. VM: Play!

Finally, using paplay from the pulseaudio package the WAV file can be played:

    paplay /usr/share/sounds/alsa/Front_Center.wav

8. MAC: Listen! On the mac side you should now here the audio and be able to see the output from sox which includes a small level meter and this should move:

    $ nc 127.0.0.1 3000 | sox -traw -r44100 -b16 -c2 -e signed-integer - -d
    -: (raw)

     File Size: 0
      Encoding: Signed PCM
      Channels: 2 @ 16-bit
    Samplerate: 44100Hz
    Replaygain: off
      Duration: unknown

    In:0.00% 00:00:06.78 [00:00:00.00] Out:299k  [      |      ]        Clip:0

Doing the reverse (ie sending the Mac audio to pulseaudio on the VM) should also be possible with a similar, though backwards, setup (module-pipe-source?)

I haven't tested this against the commands on the ffmpeg page as I have no X server.

Community
  • 1
  • 1
spacepickle
  • 2,678
  • 16
  • 21
  • 2
    Wow, what an amazing answer. Thanks so much. Worked perfectly. – Dan Rasmuson Apr 13 '17 at 05:04
  • What can cause "E: [pulseaudio] main.c: Daemon startup failed." error when starting the pulseaudio daemon? – pablo Jan 04 '20 at 15:04
  • it has lots of latency when the client trying to play something(for example music). do you have any solution for it? – MHM Jun 18 '22 at 12:38
3

I think the key is on docker run command to map device into the container. Try this:

docker run -ti --rm \
    -v /dev/snd:/dev/snd \
    --lxc-conf='lxc.cgroup.devices.allow = c 116:* rwm' \
    myContainer sh -c "echo run something"`

Extracted from here. On this link there are more options if this doesn't work for you. Check it out!

Community
  • 1
  • 1
OscarAkaElvis
  • 5,384
  • 4
  • 27
  • 51
  • Hi @OscarAkaElvis. I tried this command but it looks like `--lxc-conf` was removed in 2014. I tried the other suggested keys to replace `lxc-conf`. But id didn't look like any of them worked. Any advice? – Dan Rasmuson Apr 09 '17 at 23:50
  • maybe you need dbus and shm inside the container. Try adding `-v /run/dbus/:/run/dbus/ -v /dev/shm:/dev/shm` to the docker run command – OscarAkaElvis Apr 10 '17 at 00:11
  • Hi @OscarAkaElvis I wanted to let you know I started an $50 bounty for this issue, https://www.bountysource.com/issues/43724935-capture-audio-with-video-recording. – Dan Rasmuson Apr 11 '17 at 04:39
3

This will be much more difficult than you're hoping for. Since Docker runs in an embedded VM, you'd need to first map the sound card to the VM. Once mapped to the VM, you would be able to do a docker run --device=/dev/snd:/dev/snd ... to map the device from the VM into the container.

The issue is the first part, particularly since Mac and Linux are different operating systems. There appear to be some options to install tools that create the cross platform /dev devices needed. Once you do that, you'll need to configure the VM to share these devices into the VM.

Community
  • 1
  • 1
BMitch
  • 231,797
  • 42
  • 475
  • 450
  • Thanks for the background @BMitch. I don't need the audio to be played on my speakers but rather just saved in the video. Do I still need to do this sound card mapping? – Dan Rasmuson Apr 10 '17 at 00:03
  • I haven't been following the linux sound device development (ALSA appears to be the current version with /dev/snd). However, the mic and speakers tend to be handled together, so if you want the mic from the Mac to be reachable inside the container, you'll need to pass this through to the VM and then into the container, a very non-trivial task considering the different OS's involved. – BMitch Apr 10 '17 at 00:11
  • Hi @BMitch I wanted to let you know I started an $50 bounty for this issue, https://www.bountysource.com/issues/43724935-capture-audio-with-video-recording. – Dan Rasmuson Apr 11 '17 at 04:39
3
sudo adduser $USER audio

and

usermod --append --groups audio $USER

both of these commands helped me for displaying soundcards in linux(ubuntu to be specific). I was also getting the same error in docker container and adding these to the automated scripts when using docker exec solved the problem and I was able to display souncards using arecord -l and aplay -l commands.

Also, I used these commands to install necessary alsa and pulse audio.

sudo apt-get install alsa alsa-utils alsa-tools

sudo apt install pulseaudio pulseaudio-utils

lorugant
  • 95
  • 1
  • 11