As noted on my previous post, tinyalsa code is not capable to playback/capture stream from designated subdevice. Fortunately, tinyalsa source code is easy to extend so that implementing subdevice option is straight forward.
Basics
In tinyalsa API, pcm_open is used instead of snd_pcm_open. To designate subdevice, consumer process need to call certain ioctl to /dev/snd/controlC%u before calling pcm_open. This is minimal code snipped to demonstrate it.
#include <unistd.h> /* close */
#include <fcntl.h> /* open */
#include <sys/ioctl.h> /* ioctl */
#include <sound/asound.h> /* SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE */
struct pcm *pcm_open_with_subdevice(unsigned int card, unsigned int device,
unsigned int subdevice, unsigned int flags, struct pcm_config *config)
{
char fn[256];
int fd;
snprintf(fn, sizeof(fn), "/dev/snd/controlC%u", card);
fd = open(fn, 0);
if (fd < 0) {
fprintf(stderr, "failed to open %s\n", fn);
return NULL;
}
if (ioctl(fd, SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE, &subdevice) < 0) {
fprintf(stderr, "failed to set subdevice %u\n", subdevice);
close(fd);
return NULL;
}
pcm = pcm_open(card, device, flags, config);
return pcm;
}
Note that, if unexisting subdevice is passed to this implementation, this program goes into infinite loop. By default, ALSA kernel side will wait until subdevice become available: pcm_native.c:2848. To avoid this behavior, adding PCM_NONBLOCK to pcm_open flags argument enable us to go through even if subdevice is not existing. In this case, user space program probably need to handle errno to get proper playback/capture.
Download
This is preparation of patch and binary for some platform.
Yocto
tinyalsa-subdevice-2.0.0.zip contains patch and rpm binary package. This patch and binary is created based on Yocto 5.0.14 -- tinyalsa-2.0.0. Compilation of patch is done by adding it to SRC_URI variable of tinyalsa_2.0.0.bb.
root@qemux86-64:~# rpm --reinstall tinyalsa-2.0.0-r0.core2_64.rpm
root@qemux86-64:~# tinyplay --help
usage: tinyplay file.wav [options]
options:
-D | --card <card number> The card to receive the audio
-d | --device <device number> The device to receive the audio
-s | --subdevice <subdevice number> The device to receive the audio
-p | --period-size <size> The size of the PCM's period
-n | --period-count <count> The number of PCM periods
-i | --file-type <file-type > The type of file to read (raw or wav)
-c | --channels <count> The amount of channels per frame
-r | --rate <rate> The amount of frames per second
-b | --bits <bit-count> The number of bits in one sample
-M | --mmap Use memory mapped IO to play audio
root@qemux86-64:~#
Android
tinyalsa-subdevice-android13_r84.zip contains patch and prebuilt binaries. After applying patch to external/tinyalsa on your Android root, compilation will be done by just launching m command. Standalone compilation command is mm tinyplay and mm tinycap. After getting binary, binary is pushed to target via adb push and then it will be used as before.
emulator_car_x86_64:/ $ tinyplay
Usage: tinyplay file.wav [-D card] [-d device] [-s subdevice] [-p period_size] [-n n_periods]
Disclaimer
At this moment, these code is not well tested against real platform.