How to play audio on Torizon OS using ALSA and C/C++
Introductionβ
This article shows how to play audio using ALSA and C/C++ on Torizon OS.
What is ALSAβ
ALSA stands for Advanced Linux Sound Architecture and is responsible for accessing input and output sound devices. It works based on a client/server pattern, where the server side is the ALSA driver inside the Linux kernel space. For more information, see the ALSA documentation.
On desktop Linux distributions (e.g. Ubuntu), ALSA is rarely used directly because it can only support one client at a time. Instead, we use PulseAudio - a layer between applications and ALSA - that makes it possible to have more than one application using sound devices. Since an embedded system usually serves a single purpose, not using PulseAudio generally doesn't represent a limitation and introduces additional complexity without providing substantial benefits.
Prerequisitesβ
- A SoM with Torizon OS installed.
- An audio speaker or headphones.
Project Structureβ
For a hands-on example of using ALSA with Toradex modules, we are going to build and run a C code example. In summary, This application will:
- Read a WAV file and get audio data.
- Set up ALSA based on the file format and audio output.
- Play the audio.
This application requires the following project structure:
βββ alsa-example
β βββ main.c
β βββ wav-file.wav
β βββ Dockerfile
- main.c: The source code of the application.
- WAV file: The audio that will be played on the SoM.
- Dockerfile: The file that contains the commands to build the container.
Build the Applicationβ
Download the source code of the application alsa-alsa_example.cpp from GitHub.
Download a WAV file. You can download the following one as an example: Ryan Andersen - Faster! Faster! Faster!.wav.
Get the name of your module's audio codec with the following command:
# cat /proc/asound/cards
Output example for the
imx8mpnau8822
audio codec:1 [imx8mpnau8822 ]: simple-card - imx8mp-nau8822
imx8mp-nau8822For more information about ALSA utilities and audio processing on different SoMs, see Audio (Linux).
Create a Dockerfile with the content below. Remember to replace
imx8mpnau8822
with your module's audio codec name.Dockerfile### Build Stage ###
FROM torizon/debian:3-bookworm AS build
ENV DEBIAN_FRONTEND=noninteractive
# Install dependencies
RUN apt-get update \
&& apt-get install -y build-essential libasound2-dev
# Set the directory for subsequent Dokerfile instructions
WORKDIR /home/torizon
# Copy the source code from the local system to the build stage
COPY alsa-example.cpp .
# Compile the application, linking the libasound library
RUN g++ alsa-example.cpp -O2 -lasound -o alsa_example
### Deploy stage ###
FROM torizon/debian:3-bookworm AS deploy
ENV DEBIAN_FRONTEND=noninteractive
# Install dependencies in the container image
RUN apt-get update \
&& apt-get install -y alsa-utils \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /home/torizon
# TODO: Replace "imx8mpnau8822" with your sound codec
ENV ALSA_CARD=imx8mpnau8822
# Copy the compiled program to the container image
COPY /home/torizon/alsa_example .
# Copy the .wav file to the container image
COPY ["Ryan Andersen - Faster! Faster! Faster!.wav", "."]
# Set alsa-example as the entry point of the container
# Once up, the container will automatically run this application
ENTRYPOINT [ "./alsa_example" ]
# Pass the WAV file as an argument to alsa-example
CMD ["Ryan Andersen - Faster! Faster! Faster!.wav"]infoThis Dockerfile uses a multi-stage build to reduce container image size.
Enable ARM emulation. This is necessary for building the container for the ARM architecture.
Open a terminal in your project directory and build the container image. Make sure your project structure is correct.
$ docker build -t <your-container-registry>/alsa-example .
For more information about container registries, see Store and Share Container Images.
Push the image to a container registry:
$ docker push <your-container-registry>/alsa-example
Run the Applicationβ
Connect a speaker or headphones to the audio jack on your carrier board.
Run the container on your target device:
# docker run -it --rm --device /dev/snd/ <your-container-registry>/alsa-example
The
--device /dev/snd/
flag allows the container to access the available sound cards. For more information, see Peripheral Access Overview.If the application successfully plays the audio, it will display the following message:
Simple mixer control 'Headphone',0
Capabilities: volume pswitch
Playback channels: Front Left - Front Right
Capture channels: Front Left - Front Right
Limits: 0 - 63
Front Left: 32 [51%] [-25.00dB] Playback [on]
Front Right: 32 [51%] [-25.00dB] Playback [on]
Debuggingβ
To debug the application while it runs on your target device, we recommend using the Torizon IDE extension. It provides tasks that automatically set up the development environment and remote debugging session.