How to Play Audio on a Raspberry PI using Nerves

This took a bit of experimentation so I thought I would share my findings.
The first thing you need to do is set the audio output to the microphone jack on the Raspberry PI:
:os.cmd(‘amixer cset numid=3 1’)
Note: If you want to use HDMI for audio output change the 1 to a 2.
Then we need to select the command line application we want to use to run our audio files. On my mac it’s afplay
and on the RPI it’s aplay
:
audio_player = if Mix.env() == :prod, do: “aplay”, else: “afplay”
We’re also going to want a command we can interpolate with to run the audio:
audio_player_cmd = if Mix.env() == :prod, do: “#{audio_player} -q”, else: audio_player
And let’s use the priv/static
directory to store our audio files.
static_directory_path = Path.join(:code.priv_dir(:audio_playing_app), “static”)
Then to play sounds we can run this code with a given file_name
. I’ve only tried with wav
files and they worked like a charm.
Wrap it in a spawn
so it isn’t blocking and fails gracefully.
spawn(fn ->
audio_player = if Mix.target() in [rpi, rpi2, rpi3], do: “aplay”, else: “afplay”
audio_player_cmd = if Mix.target() in [rpi, rpi2, rpi3], do: “#{audio_player} -q”, else: audio_player
static_directory_path = Path.join(:code.priv_dir(:audio_playing_app), “static”)
full_path = Path.join(static_directory_path, file_name)
:os.cmd('#{@audio_player_cmd} #{full_path}')
end)
Anv Voila! That’s it. Congratulations, you played audio on your RPI using Elixir and Nerves!
And if you want to, you could set the volume on the RPI using:
percent = "50"
:os.cmd('amixer cset numid=1 %{percent}%')
And to stop the audio run:
:os.cmd('killall #{@audio_player}')
This isn’t a surgical approach to stopping audio as it stops all of the audio that is currently playing. This approach worked for me so I didn’t explore stopping specific audio files!
I have tried this on a RPI2 and RPI4 with success. I’m sure it’ll work with an RPI3 as well.