[bootlin/training-materials updates] master: audio: checkpoint (e480fd16)
Alexandre Belloni
alexandre.belloni at bootlin.com
Wed Apr 26 02:17:44 CEST 2023
Repository : https://github.com/bootlin/training-materials
On branch : master
Link : https://github.com/bootlin/training-materials/commit/e480fd166b31a977d8fd44df9325d1c50b806c17
>---------------------------------------------------------------
commit e480fd166b31a977d8fd44df9325d1c50b806c17
Author: Alexandre Belloni <alexandre.belloni at bootlin.com>
Date: Wed Apr 26 02:17:44 2023 +0200
audio: checkpoint
Signed-off-by: Alexandre Belloni <alexandre.belloni at bootlin.com>
>---------------------------------------------------------------
e480fd166b31a977d8fd44df9325d1c50b806c17
common/audio-title.tex | 2 +-
mk/audio.mk | 3 +
slides/audio-alsa-lib/audio-alsa-lib.tex | 344 +++++++++++++++++++++
slides/audio-alsa-utils/audio-alsa-utils.tex | 344 +++++++++++++++++++++
slides/audio-asoc-codec/audio-asoc-codec.tex | 2 +-
.../audio-asoc-component-callbacks.tex | 14 +-
slides/audio-asoc-cpu/audio-asoc-cpu.tex | 92 ++++++
7 files changed, 792 insertions(+), 9 deletions(-)
diff --git a/common/audio-title.tex b/common/audio-title.tex
index f4686abf..1a942d7c 100644
--- a/common/audio-title.tex
+++ b/common/audio-title.tex
@@ -1,2 +1,2 @@
\def \trainingurl{https://bootlin.com/training/graphics}
-\def \trainingtitle{Audio with embedded Linux training}
+\def \trainingtitle{Audio with embedded Linux}
diff --git a/mk/audio.mk b/mk/audio.mk
index 051cb6bc..b238b303 100644
--- a/mk/audio.mk
+++ b/mk/audio.mk
@@ -11,5 +11,8 @@ AUDIO_SLIDES = \
audio-asoc-component-callbacks \
audio-auxiliary \
audio-asoc-DAPM \
+ audio-asoc-cpu \
+ audio-alsa-lib \
+ audio-alsa-utils \
audio-debugging \
last-slides
diff --git a/slides/audio-alsa-lib/audio-alsa-lib.tex b/slides/audio-alsa-lib/audio-alsa-lib.tex
new file mode 100644
index 00000000..1985e768
--- /dev/null
+++ b/slides/audio-alsa-lib/audio-alsa-lib.tex
@@ -0,0 +1,344 @@
+\section{Userspace ALSA}
+
+\subsection{alsa-lib}
+
+\begin{frame}{alsa-lib}
+ \begin{itemize}
+ \item The main way to interact with ALSA devices is to use alsa-lib.
+ \item \url{https://github.com/alsa-project/alsa-lib.git}
+ \item It provides mainly access to the devices but also goes further
+ and allows handling audio in userspace
+ \item The library itself is actually named \code{libasound}
+ \item The include file is \code{alsa/asoundlib.h}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{alsa-lib API}
+ \begin{itemize}
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_open(snd_pcm_t ** pcmp, const char * name, snd_pcm_stream_t stream, int mode)
+ \end{minted}
+ \end{block}
+ \item \code{name} is the name of the PCM to be opened.
+ \item \code{stream} can be either \code{SND_PCM_STREAM_PLAYBACK} or
+ \code{SND_PCM_STREAM_CAPTURE}
+ \item \code{mode} can be a combination of \code{SND_PCM_NONBLOCK}
+ and \code{SND_PCM_ASYNC}
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_close(snd_pcm_t *pcm)
+ \end{minted}
+ \end{block}
+ \item Closes the PCM.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}{PCM name}
+ \begin{itemize}
+ \item This can be specified as a hardware device. The three
+ arguments (in order: CARD,DEV,SUBDEV) specify card number or
+ identifier, device number and subdevice number (-1 means any). For
+ example: \code{hw:0} or \code{hw:1,0}
+ \item Or through the \code{plug} plugin: \code{plug:mypcmdef},
+ \code{plug:hw:0,0}
+ \item The list of available names can be generated using
+ \code{snd_card_next} to iterate over all the physical cards. See
+ \code{device_list} in \code{aplay}.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{alsa-lib API - PCM}
+ \begin{itemize}
+ \item The next step is to handle the PCM stream parameters
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+snd_pcm_hw_params_t *hw_params;
+int snd_pcm_hw_params_malloc(snd_pcm_hw_params_t ** ptr)
+int snd_pcm_hw_params_any(snd_pcm_t * pcm, snd_pcm_hw_params_t * params)
+ \end{minted}
+ \end{block}
+ \item This will allocate a \code{snd_pcm_hw_params_t} and fill it
+ with the range of parameters supported by \code{pcm}.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_hw_params_set_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ snd_pcm_access_t _access)
+ \end{minted}
+ \end{block}
+ \item This set the proper access type: interleaved or
+ non-interleaved, mmap or not.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_hw_params_set_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ snd_pcm_format_t val)
+ \end{minted}
+ \end{block}
+ \item This set the format, using a \code{SND_PCM_FORMAT_} macro.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{alsa-lib API - PCM}
+ \begin{itemize}
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_hw_params_set_channels(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int val)
+ \end{minted}
+ \end{block}
+ \item Sets the number of channels.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_hw_params_set_rate_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int *val, int *dir)
+ \end{minted}
+ \end{block}
+ \item Sets the sample rate, setting \code{dir} to 0 will require
+ the exact rate.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_hw_params_set_periods(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int val, int dir)
+int snd_pcm_hw_params_set_period_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ snd_pcm_uframes_t val, int dir)
+int snd_pcm_hw_params_set_buffer_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ snd_pcm_uframes_t val)
+ \end{minted}
+ \end{block}
+ \item Sets the number of periods and the period size in the
+ buffer or the buffer size.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{alsa-lib API - PCM}
+ \begin{itemize}
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_hw_params(snd_pcm_t * pcm, snd_pcm_hw_params_t * params)
+ \end{minted}
+ \end{block}
+ \item Installs the parameters and calls \code{snd_pcm_prepare} on
+ the stream.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+void snd_pcm_hw_params_free(snd_pcm_hw_params_t * obj)
+ \end{minted}
+ \end{block}
+ \item Frees the allocated \code{snd_pcm_hw_params_t}.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_prepare(snd_pcm_t * pcm)
+ \end{minted}
+ \end{block}
+ \item Prepares the stream.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_wait(snd_pcm_t * pcm, int timeout)
+ \end{minted}
+ \end{block}
+ \item Waits for the PCM to be ready.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{alsa-lib API - PCM}
+ \begin{itemize}
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
+snd_pcm_sframes_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
+snd_pcm_sframes_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
+snd_pcm_sframes_t snd_pcm_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
+ \end{minted}
+ \end{block}
+ \item Write or read from an interleaved or non-interleaved buffer.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas,
+ snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames)
+snd_pcm_sframes_t snd_pcm_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset,
+ snd_pcm_uframes_t frames)
+snd_pcm_sframes_t snd_pcm_mmap_writei(snd_pcm_t *pcm, const void *buffer,
+ snd_pcm_uframes_t size)
+snd_pcm_sframes_t snd_pcm_mmap_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
+snd_pcm_sframes_t snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
+snd_pcm_sframes_t snd_pcm_mmap_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
+ \end{minted}
+ \end{block}
+ \item Write or read from an interleaved or non-interleaved mmap buffer.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{alsa-lib API - controls}
+ \begin{itemize}
+ \item It is possible to set controls programatically.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+snd_ctl_t *handle;
+int snd_ctl_open (snd_ctl_t **ctl, const char *name, int mode)
+ \end{minted}
+ \end{block}
+ \item Opens the sound card to be controlled.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+snd_ctl_elem_id_t *id;
+#define snd_ctl_elem_id_alloca(ptr)
+snd_ctl_elem_value_t *value;
+#define snd_ctl_elem_value_alloca(ptr)
+ \end{minted}
+ \end{block}
+ \item Allocate a \code{snd_ctl_elem_id_t}, referring to a particular
+ control and a \code{snd_ctl_elem_value_t} to be set for this
+ control.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+void snd_ctl_elem_id_set_interface(snd_ctl_elem_id_t *obj, snd_ctl_elem_iface_t val)
+void snd_ctl_elem_id_set_name(snd_ctl_elem_id_t *obj, const char *val)
+ \end{minted}
+ \end{block}
+ \item Set the interface and name of the control to be set.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{alsa-lib API - controls}
+ \begin{itemize}
+ \item A lookup is needed to fill the \code{snd_ctl_elem_id_t}
+ completely
+ \end{itemize}
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int lookup_id(snd_ctl_elem_id_t *id, snd_ctl_t *handle)
+{
+ int err;
+ snd_ctl_elem_info_t *info;
+ snd_ctl_elem_info_alloca(&info);
+
+ snd_ctl_elem_info_set_id(info, id);
+ if ((err = snd_ctl_elem_info(handle, info)) < 0) {
+ return err;
+ }
+ snd_ctl_elem_info_get_id(info, id);
+
+ return 0;
+}
+ \end{minted}
+ \end{block}
+\end{frame}
+
+\begin{frame}[fragile]{alsa-lib API - controls}
+ \begin{itemize}
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+void snd_ctl_elem_value_set_id(snd_ctl_elem_value_t *obj, const snd_ctl_elem_id_t *ptr)
+ \end{minted}
+ \end{block}
+ \item Links the value with the control id.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+void snd_ctl_elem_value_set_boolean(snd_ctl_elem_value_t *obj, unsigned int idx, long val)
+void snd_ctl_elem_value_set_integer(snd_ctl_elem_value_t *obj, unsigned int idx, long val)
+void snd_ctl_elem_value_set_integer64(snd_ctl_elem_value_t *obj, unsigned int idx,
+ long long val)
+void snd_ctl_elem_value_set_enumerated(snd_ctl_elem_value_t *obj, unsigned int idx,
+ unsigned int val)
+void snd_ctl_elem_value_set_byte(snd_ctl_elem_value_t *obj, unsigned int idx,
+ unsigned char val)
+void snd_ctl_elem_set_bytes(snd_ctl_elem_value_t *obj, void *data, size_t size)
+ \end{minted}
+ \end{block}
+ \item Set the value in \code{snd_ctl_elem_value_t}.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_ctl_elem_write(snd_ctl_t *ctl, snd_ctl_elem_value_t *data)
+ \end{minted}
+ \end{block}
+ \item Actually set the control.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{alsa-lib API - controls}
+ \begin{itemize}
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+void snd_ctl_elem_value_set_id(snd_ctl_elem_value_t *obj, const snd_ctl_elem_id_t *ptr)
+ \end{minted}
+ \end{block}
+ \item Links the value with the control id.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+void snd_ctl_elem_value_set_boolean(snd_ctl_elem_value_t *obj, unsigned int idx, long val)
+void snd_ctl_elem_value_set_integer(snd_ctl_elem_value_t *obj, unsigned int idx, long val)
+void snd_ctl_elem_value_set_integer64(snd_ctl_elem_value_t *obj, unsigned int idx,
+ long long val)
+void snd_ctl_elem_value_set_enumerated(snd_ctl_elem_value_t *obj, unsigned int idx,
+ unsigned int val)
+void snd_ctl_elem_value_set_byte(snd_ctl_elem_value_t *obj, unsigned int idx,
+ unsigned char val)
+void snd_ctl_elem_set_bytes(snd_ctl_elem_value_t *obj, void *data, size_t size)
+ \end{minted}
+ \end{block}
+ \item Set the value in \code{snd_ctl_elem_value_t}.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_ctl_elem_write(snd_ctl_t *ctl, snd_ctl_elem_value_t *data)
+ \end{minted}
+ \end{block}
+ \item Actually set the control.
+ \end{itemize}
+\end{frame}
+
+
+\begin{frame}{Going further}
+ \begin{itemize}
+ \item UCM: The ALSA Use Case Configuration:
+ \url{https://www.alsa-project.org/alsa-doc/alsa-lib/group__ucm__conf.html}
+ \item ALSA topology:
+ \url{https://www.alsa-project.org/wiki/ALSA_topology}
+ \end{itemize}
+\end{frame}
diff --git a/slides/audio-alsa-utils/audio-alsa-utils.tex b/slides/audio-alsa-utils/audio-alsa-utils.tex
new file mode 100644
index 00000000..1985e768
--- /dev/null
+++ b/slides/audio-alsa-utils/audio-alsa-utils.tex
@@ -0,0 +1,344 @@
+\section{Userspace ALSA}
+
+\subsection{alsa-lib}
+
+\begin{frame}{alsa-lib}
+ \begin{itemize}
+ \item The main way to interact with ALSA devices is to use alsa-lib.
+ \item \url{https://github.com/alsa-project/alsa-lib.git}
+ \item It provides mainly access to the devices but also goes further
+ and allows handling audio in userspace
+ \item The library itself is actually named \code{libasound}
+ \item The include file is \code{alsa/asoundlib.h}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{alsa-lib API}
+ \begin{itemize}
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_open(snd_pcm_t ** pcmp, const char * name, snd_pcm_stream_t stream, int mode)
+ \end{minted}
+ \end{block}
+ \item \code{name} is the name of the PCM to be opened.
+ \item \code{stream} can be either \code{SND_PCM_STREAM_PLAYBACK} or
+ \code{SND_PCM_STREAM_CAPTURE}
+ \item \code{mode} can be a combination of \code{SND_PCM_NONBLOCK}
+ and \code{SND_PCM_ASYNC}
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_close(snd_pcm_t *pcm)
+ \end{minted}
+ \end{block}
+ \item Closes the PCM.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}{PCM name}
+ \begin{itemize}
+ \item This can be specified as a hardware device. The three
+ arguments (in order: CARD,DEV,SUBDEV) specify card number or
+ identifier, device number and subdevice number (-1 means any). For
+ example: \code{hw:0} or \code{hw:1,0}
+ \item Or through the \code{plug} plugin: \code{plug:mypcmdef},
+ \code{plug:hw:0,0}
+ \item The list of available names can be generated using
+ \code{snd_card_next} to iterate over all the physical cards. See
+ \code{device_list} in \code{aplay}.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{alsa-lib API - PCM}
+ \begin{itemize}
+ \item The next step is to handle the PCM stream parameters
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+snd_pcm_hw_params_t *hw_params;
+int snd_pcm_hw_params_malloc(snd_pcm_hw_params_t ** ptr)
+int snd_pcm_hw_params_any(snd_pcm_t * pcm, snd_pcm_hw_params_t * params)
+ \end{minted}
+ \end{block}
+ \item This will allocate a \code{snd_pcm_hw_params_t} and fill it
+ with the range of parameters supported by \code{pcm}.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_hw_params_set_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ snd_pcm_access_t _access)
+ \end{minted}
+ \end{block}
+ \item This set the proper access type: interleaved or
+ non-interleaved, mmap or not.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_hw_params_set_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ snd_pcm_format_t val)
+ \end{minted}
+ \end{block}
+ \item This set the format, using a \code{SND_PCM_FORMAT_} macro.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{alsa-lib API - PCM}
+ \begin{itemize}
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_hw_params_set_channels(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int val)
+ \end{minted}
+ \end{block}
+ \item Sets the number of channels.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_hw_params_set_rate_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int *val, int *dir)
+ \end{minted}
+ \end{block}
+ \item Sets the sample rate, setting \code{dir} to 0 will require
+ the exact rate.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_hw_params_set_periods(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int val, int dir)
+int snd_pcm_hw_params_set_period_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ snd_pcm_uframes_t val, int dir)
+int snd_pcm_hw_params_set_buffer_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ snd_pcm_uframes_t val)
+ \end{minted}
+ \end{block}
+ \item Sets the number of periods and the period size in the
+ buffer or the buffer size.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{alsa-lib API - PCM}
+ \begin{itemize}
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_hw_params(snd_pcm_t * pcm, snd_pcm_hw_params_t * params)
+ \end{minted}
+ \end{block}
+ \item Installs the parameters and calls \code{snd_pcm_prepare} on
+ the stream.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+void snd_pcm_hw_params_free(snd_pcm_hw_params_t * obj)
+ \end{minted}
+ \end{block}
+ \item Frees the allocated \code{snd_pcm_hw_params_t}.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_prepare(snd_pcm_t * pcm)
+ \end{minted}
+ \end{block}
+ \item Prepares the stream.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_wait(snd_pcm_t * pcm, int timeout)
+ \end{minted}
+ \end{block}
+ \item Waits for the PCM to be ready.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{alsa-lib API - PCM}
+ \begin{itemize}
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
+snd_pcm_sframes_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
+snd_pcm_sframes_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
+snd_pcm_sframes_t snd_pcm_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
+ \end{minted}
+ \end{block}
+ \item Write or read from an interleaved or non-interleaved buffer.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_pcm_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas,
+ snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames)
+snd_pcm_sframes_t snd_pcm_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset,
+ snd_pcm_uframes_t frames)
+snd_pcm_sframes_t snd_pcm_mmap_writei(snd_pcm_t *pcm, const void *buffer,
+ snd_pcm_uframes_t size)
+snd_pcm_sframes_t snd_pcm_mmap_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
+snd_pcm_sframes_t snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
+snd_pcm_sframes_t snd_pcm_mmap_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
+ \end{minted}
+ \end{block}
+ \item Write or read from an interleaved or non-interleaved mmap buffer.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{alsa-lib API - controls}
+ \begin{itemize}
+ \item It is possible to set controls programatically.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+snd_ctl_t *handle;
+int snd_ctl_open (snd_ctl_t **ctl, const char *name, int mode)
+ \end{minted}
+ \end{block}
+ \item Opens the sound card to be controlled.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+snd_ctl_elem_id_t *id;
+#define snd_ctl_elem_id_alloca(ptr)
+snd_ctl_elem_value_t *value;
+#define snd_ctl_elem_value_alloca(ptr)
+ \end{minted}
+ \end{block}
+ \item Allocate a \code{snd_ctl_elem_id_t}, referring to a particular
+ control and a \code{snd_ctl_elem_value_t} to be set for this
+ control.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+void snd_ctl_elem_id_set_interface(snd_ctl_elem_id_t *obj, snd_ctl_elem_iface_t val)
+void snd_ctl_elem_id_set_name(snd_ctl_elem_id_t *obj, const char *val)
+ \end{minted}
+ \end{block}
+ \item Set the interface and name of the control to be set.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{alsa-lib API - controls}
+ \begin{itemize}
+ \item A lookup is needed to fill the \code{snd_ctl_elem_id_t}
+ completely
+ \end{itemize}
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int lookup_id(snd_ctl_elem_id_t *id, snd_ctl_t *handle)
+{
+ int err;
+ snd_ctl_elem_info_t *info;
+ snd_ctl_elem_info_alloca(&info);
+
+ snd_ctl_elem_info_set_id(info, id);
+ if ((err = snd_ctl_elem_info(handle, info)) < 0) {
+ return err;
+ }
+ snd_ctl_elem_info_get_id(info, id);
+
+ return 0;
+}
+ \end{minted}
+ \end{block}
+\end{frame}
+
+\begin{frame}[fragile]{alsa-lib API - controls}
+ \begin{itemize}
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+void snd_ctl_elem_value_set_id(snd_ctl_elem_value_t *obj, const snd_ctl_elem_id_t *ptr)
+ \end{minted}
+ \end{block}
+ \item Links the value with the control id.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+void snd_ctl_elem_value_set_boolean(snd_ctl_elem_value_t *obj, unsigned int idx, long val)
+void snd_ctl_elem_value_set_integer(snd_ctl_elem_value_t *obj, unsigned int idx, long val)
+void snd_ctl_elem_value_set_integer64(snd_ctl_elem_value_t *obj, unsigned int idx,
+ long long val)
+void snd_ctl_elem_value_set_enumerated(snd_ctl_elem_value_t *obj, unsigned int idx,
+ unsigned int val)
+void snd_ctl_elem_value_set_byte(snd_ctl_elem_value_t *obj, unsigned int idx,
+ unsigned char val)
+void snd_ctl_elem_set_bytes(snd_ctl_elem_value_t *obj, void *data, size_t size)
+ \end{minted}
+ \end{block}
+ \item Set the value in \code{snd_ctl_elem_value_t}.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_ctl_elem_write(snd_ctl_t *ctl, snd_ctl_elem_value_t *data)
+ \end{minted}
+ \end{block}
+ \item Actually set the control.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{alsa-lib API - controls}
+ \begin{itemize}
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+void snd_ctl_elem_value_set_id(snd_ctl_elem_value_t *obj, const snd_ctl_elem_id_t *ptr)
+ \end{minted}
+ \end{block}
+ \item Links the value with the control id.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+void snd_ctl_elem_value_set_boolean(snd_ctl_elem_value_t *obj, unsigned int idx, long val)
+void snd_ctl_elem_value_set_integer(snd_ctl_elem_value_t *obj, unsigned int idx, long val)
+void snd_ctl_elem_value_set_integer64(snd_ctl_elem_value_t *obj, unsigned int idx,
+ long long val)
+void snd_ctl_elem_value_set_enumerated(snd_ctl_elem_value_t *obj, unsigned int idx,
+ unsigned int val)
+void snd_ctl_elem_value_set_byte(snd_ctl_elem_value_t *obj, unsigned int idx,
+ unsigned char val)
+void snd_ctl_elem_set_bytes(snd_ctl_elem_value_t *obj, void *data, size_t size)
+ \end{minted}
+ \end{block}
+ \item Set the value in \code{snd_ctl_elem_value_t}.
+ \item
+ \begin{block}{}
+ \fontsize{9}{9}\selectfont
+ \begin{minted}{c}
+int snd_ctl_elem_write(snd_ctl_t *ctl, snd_ctl_elem_value_t *data)
+ \end{minted}
+ \end{block}
+ \item Actually set the control.
+ \end{itemize}
+\end{frame}
+
+
+\begin{frame}{Going further}
+ \begin{itemize}
+ \item UCM: The ALSA Use Case Configuration:
+ \url{https://www.alsa-project.org/alsa-doc/alsa-lib/group__ucm__conf.html}
+ \item ALSA topology:
+ \url{https://www.alsa-project.org/wiki/ALSA_topology}
+ \end{itemize}
+\end{frame}
diff --git a/slides/audio-asoc-codec/audio-asoc-codec.tex b/slides/audio-asoc-codec/audio-asoc-codec.tex
index fddefa94..7d04976a 100644
--- a/slides/audio-asoc-codec/audio-asoc-codec.tex
+++ b/slides/audio-asoc-codec/audio-asoc-codec.tex
@@ -86,7 +86,7 @@ struct snd_soc_component_driver {
When called, all the parameters of the stream are known so it is
possible to configure the component to handle the stream
correctly.
- \item Those are mostyl not used, the DAI specific callbacks are used
+ \item Those are mostly not used, the DAI specific callbacks are used
instead.
\end{itemize}
\end{frame}
diff --git a/slides/audio-asoc-component-callbacks/audio-asoc-component-callbacks.tex b/slides/audio-asoc-component-callbacks/audio-asoc-component-callbacks.tex
index 51dc3f07..061c8dd2 100644
--- a/slides/audio-asoc-component-callbacks/audio-asoc-component-callbacks.tex
+++ b/slides/audio-asoc-component-callbacks/audio-asoc-component-callbacks.tex
@@ -226,10 +226,10 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
\end{itemize}
\item Also the polarity can be changed:
\begin{itemize}
- \item \ksym{SND_SOC_DAIFMT_NB_NF}: normal bit clock + frame
+ \item \ksym{SND_SOC_DAIFMT_NB_NF}: normal bit clock + normal frame
\item \ksym{SND_SOC_DAIFMT_NB_IF}: normal bit clock + invert frame
\item \ksym{SND_SOC_DAIFMT_IB_NF}: invert bit clock + normal frame
- \item \ksym{SND_SOC_DAIFMT_IB_IF}: invert bit clock + frame
+ \item \ksym{SND_SOC_DAIFMT_IB_IF}: invert bit clock + invert frame
\end{itemize}
\end{itemize}
\end{frame}
@@ -248,10 +248,10 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
\fontsize{9}{9}\selectfont
\begin{minted}{c}
/* previous definitions kept for backwards-compatibility, do not use in new contributions */
-#define SND_SOC_DAIFMT_CBM_CFM SND_SOC_DAIFMT_CBP_CFP
-#define SND_SOC_DAIFMT_CBS_CFM SND_SOC_DAIFMT_CBC_CFP
-#define SND_SOC_DAIFMT_CBM_CFS SND_SOC_DAIFMT_CBP_CFC
-#define SND_SOC_DAIFMT_CBS_CFS SND_SOC_DAIFMT_CBC_CFC
+#define SND_SOC_DAIFMT_CBM_CFM SND_SOC_DAIFMT_CBP_CFP
+#define SND_SOC_DAIFMT_CBS_CFM SND_SOC_DAIFMT_CBC_CFP
+#define SND_SOC_DAIFMT_CBM_CFS SND_SOC_DAIFMT_CBP_CFC
+#define SND_SOC_DAIFMT_CBS_CFS SND_SOC_DAIFMT_CBC_CFC
\end{minted}
\end{block}
\end{itemize}
@@ -299,7 +299,7 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
\begin{itemize}
\item This callback configures the DAI for TDM operation.
\item \code{slot} is the total number of slots of the TDM stream and
- \code{slot_with} the width of each slot in bit clock cycles.
+ \code{slot_width} the width of each slot in bit clock cycles.
\item \code{tx_mask} and \code{rx_mask} are bitmasks specifying the
active slots of the TDM stream for the specified DAI, i.e. which slots the
DAI should write to or read from. A set bit means the channel is
diff --git a/slides/audio-asoc-cpu/audio-asoc-cpu.tex b/slides/audio-asoc-cpu/audio-asoc-cpu.tex
new file mode 100644
index 00000000..81cdbd0d
--- /dev/null
+++ b/slides/audio-asoc-cpu/audio-asoc-cpu.tex
@@ -0,0 +1,92 @@
+\subsection{CPU DAI driver}
+
+\begin{frame}{CPU DAI driver}
+ \begin{itemize}
+ \item The CPU DAI driver is now a component driver, like the codec
+ ones.
+ \item However, it is usually more complex as it need to handle IRQs
+ and take care of pinmuxing, clocks and DMA.
+ \item Also, the list of supported format and rates is usually very
+ large.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}{DMA handling}
+ \begin{itemize}
+ \item When a DMA controller is available, handling DMA in ALSA is
+ done almost completely in the core, through \code{dmaengine_pcm}.
+ \item The DMA is simply registered using
+ \kfunc{devm_snd_dmaengine_pcm_register}. This handles parsing the
+ device tree if necessary.
+ \item In the DAI driver probe callback, the DMA engine is simply
+ configured using \kfunc{snd_soc_dai_init_dma_data} which takes the
+ DMA configuration for playback and capture.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{DMA handling example}
+ \begin{block}{\code{sound/soc/atmel/atmel-i2s.c}}
+ \fontsize{8}{7}\selectfont
+ \begin{minted}{c}
+struct atmel_i2s_dev {
+ struct device *dev;
+ struct regmap *regmap;
+ struct clk *pclk;
+ struct clk *gclk;
+ struct snd_dmaengine_dai_dma_data playback;
+ struct snd_dmaengine_dai_dma_data capture;
+ unsigned int fmt;
+ const struct atmel_i2s_gck_param *gck_param;
+ const struct atmel_i2s_caps *caps;
+ int clk_use_no;
+};
+[...]
+static int atmel_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+ struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai, &dev->playback, &dev->capture);
+ return 0;
+}
+ \end{minted}
+ \end{block}
+\end{frame}
+
+\begin{frame}[fragile]{DMA handling example}
+ \begin{block}{\code{sound/soc/atmel/atmel-i2s.c}}
+ \fontsize{8}{8}\selectfont
+ \begin{minted}{c}
+static int atmel_i2s_probe(struct platform_device *pdev)
+{
+[...]
+ /* Prepare DMA config. */
+ dev->playback.addr = (dma_addr_t)mem->start + ATMEL_I2SC_THR;
+ dev->playback.maxburst = 1;
+ dev->capture.addr = (dma_addr_t)mem->start + ATMEL_I2SC_RHR;
+ dev->capture.maxburst = 1;
+
+ if (of_property_match_string(np, "dma-names", "rx-tx") == 0)
+ pcm_flags |= SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX;
+ err = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, pcm_flags);
+ if (err) {
+ dev_err(&pdev->dev, "failed to register PCM: %d\n", err);
+ clk_disable_unprepare(dev->pclk);
+ return err;
+ }
+[...]
+}
+ \end{minted}
+ \end{block}
+\end{frame}
+
+\begin{frame}{DMA handling}
+ \begin{itemize}
+ \item When a peripheral DMA controller is used, this is more
+ complex.
+ \item The driver will have to handle all th aspects of the PCM
+ stream life cycle
+ \item Understandable example in \kfile{sound/soc/atmel/atmel-pcm-pdc.c}
+ \end{itemize}
+\end{frame}
+
+
More information about the training-materials-updates
mailing list