Problem: Send 16 channel audio TDM stream over SAI(5) datalines using freescale IMX8m. There's no codec termination on the HW. only the data is framed in a TDM fromat and sent over the I2S Datalines. There's an FPGA that receives the data on the other end of Imx8m datalines and de-multiplexes it to multiple audio out sources.
Issue: When playing 8 (4 stereo sources) channels, the TDM frame seems to be working without any issues. But when i increase the TDM frame size to 16 channels (8 stereo sources), once in a while the playback is stuck before even beginning the playback. it remains stuck in the poll() function and never returns. this poll function is called at the top level from snd_pcm_write_areas() in /alsa-lib/src/pcm/pcm.c
Here's what I have found during my debug between aplay app/alsa-lib <=> alsa-pcm-snd-driver <==> fsl_sai driver > HW
- when the playback is functioning properly i can see the snd_pcm_direct.spcm->hw.ptr getting incremented by frame size*1 (or more) for every snd_pcm_write_areas call. this pointer seems to keep track of the #of frames in time that should have been sent out. its an unsigned int value with a boundary of 0x40000000 and the ptr loops back again once it reaches the boundary. From alsa-lib/src/pcm/pcm.c file
static int snd_pcm_dshare_start_timer(snd_pcm_direct_t *dshare) { int err; snd_pcm_hwsync(dshare->spcm); dshare->slave_appl_ptr= dshare->slave_hw_ptr = *dshare->spcm->hw.ptr;
- When the playback is stuck at poll function i see that this pointer never got updated and is stuck at period size (frame size * n) or at some multiple of frame size.
- I have seen several alsa posts online regarding the playback being stuck but no solution or direction to take in case of.
- Also read one post, mentioning this to be an existing alsa bug as of 4.14 kernel, when using Dshare/Dmix/Dsnoop plugins.
- I have tried moving from 1.1.2 to 1.1.5 or 1.1.7 version but no luck. Apparently this issue doesn't happen when using the HW cards, only when using the above mentioned plugins this issue is seen.
I am not sure which one leads to the other and which one is the bug that needs to be fixed.
The poll function getting stuck due to timer getting into bad state or the timer getting into bad state leading to the poll getting stuck.
Some details of how we creating the TDM frame we have a 16 channel audio (8 independent stereo pairs) that need to be sent as a frame to the HW to be written out on one of the SAI datalines (4 data lines). These 8 sources can be played independently and the sources will occupy the slots in the TDM frame according to the channel map as specified in the asound.conf configuration file.
The dshare plugin is being used to create the shared buffer that will hold the frame. I have created 8 virtual sources in the conf file, one for each playback process. each source can be used in a separate aplay process for playing a 8 different source. see the batch file that plays all the 8 sources.
output from aplay -L/l
null
Discard all samples (playback) or generate zero samples (capture)
src1
TDM 0 channel 0/1 for audio playback
src2
TDM 1 channel 2/3 for audio playback
src3
TDM 2 channel 4/5 for audio playback
src4
TDM 3 channel 6/7 for audio playback
src5
TDM 4 channel 8/9 for audio playback
src6
TDM 5channel 10/11 for audio playback
src7
TDM 6 channel 12/13 for audio playback
src8
TDM 7 channel 14/15 for audio playback
default:CARD=<xxxxx>
Default Audio Device
sysdefault:CARD=<xxxxxxxx>
Default Audio Device
asound.conf file
# NOTE: this is for sharing multiple channels on a single (TDM) audio device with multple ALSA clients
# shared buffer for playback
pcm_slave.tdmshare {
pcm "hw:0"
channels 16
rate 48000 # fixed, because all dshare devices must use the same samplerate.
format S24_LE
period_size 512
buffer_size 1024
}
# src1 shared pcm device and corresponding virtual playback device
pcm.src1_dshare {
type dshare
ipc_key 43544553
slave tdmshare
bindings.0 0
bindings.1 4
}
pcm.src1 {
type plug
slave.pcm "src1_dshare"
hint {
show {
@func refer
name defaults.namehint.basic
}
description "TDM 0 channel 0/1 for audio playback"
}
}
# src2 shared pcm device and corresponding virtual playback device
pcm.src2_dshare {
type dshare
ipc_key 43544553
slave tdmshare
bindings.0 8
bindings.1 12
}
pcm.src2 {
type plug
slave.pcm "src2_dshare"
hint {
show {
@func refer
name defaults.namehint.basic
}
description "TDM 1 channel 2/3 for audio playback"
}
}
# src3 shared pcm device and corresponding virtual playback device
pcm.src3_dshare {
type dshare
ipc_key 43544553
slave tdmshare
bindings.0 1
bindings.1 5
}
pcm.src3 {
type plug
slave.pcm "src3_dshare"
hint {
show {
@func refer
name defaults.namehint.basic
}
description "TDM 2 channel 4/5 for audio playback"
}
}
# src4 shared pcm device and corresponding virtual playback device
pcm.src4_dshare {
type dshare
ipc_key 43544553
slave tdmshare
bindings.0 9
bindings.1 13
}
pcm.src4 {
type plug
slave.pcm "src4_dshare"
hint {
show {
@func refer
name defaults.namehint.basic
}
description "TDM 3 channel 6/7 for audio playback"
}
}
# src5 shared pcm device and corresponding virtual playback device
pcm.src5_dshare {
type dshare
ipc_key 43544553
slave tdmshare
bindings.0 2
bindings.1 6
}
pcm.src5 {
type plug
slave.pcm "src5_dshare"
hint {
show {
@func refer
name defaults.namehint.basic
}
description "TDM 4 channel 8/9 for audio playback"
}
}
# src6 shared pcm device and corresponding virtual playback device
pcm.src6_dshare {
type dshare
ipc_key 43544553
slave tdmshare
bindings.0 10
bindings.1 14
}
pcm.src6 {
type plug
slave.pcm "src6_dshare"
hint {
show {
@func refer
name defaults.namehint.basic
}
description "TDM 5channel 10/11 for audio playback"
}
}
# src7 shared pcm device and corresponding virtual playback device
pcm.src7_dshare {
type dshare
ipc_key 43544553
slave tdmshare
bindings.0 3
bindings.1 7
}
pcm.src7 {
type plug
slave.pcm "src7_dshare"
hint {
show {
@func refer
name defaults.namehint.basic
}
description "TDM 6 channel 12/13 for audio playback"
}
}
# src8 shared pcm device and corresponding virtual playback device
pcm.src8_dshare {
type dshare
ipc_key 43544553
slave tdmshare
bindings.0 11
bindings.1 15
}
pcm.src8 {
type plug
slave.pcm "src8_dshare"
hint {
show {
@func refer
name defaults.namehint.basic
}
description "TDM 7 channel 14/15 for audio playback"
}
}
batch file for playing all 8 sources
aplay -Dplug:src1 /data/PCMCH1-Ch2_1.wav&
aplay -Dplug:src2 /data/PCMCH3-Ch4_1.wav&
aplay -Dplug:src3 /data/PCMCH5-Ch6_1.wav&
aplay -Dplug:src4 /data/PCMCH7-Ch8_1.wav&
aplay -Dplug:src5 /data/PCMCH1-Ch2_1.wav&
aplay -Dplug:src6 /data/PCMCH3-Ch4_1.wav&
aplay -Dplug:src7 /data/PCMCH5-Ch6_1.wav&
aplay -Dplug:src8 /data/PCMCH7-Ch8_1.wav&
Please let me know if there's something that can be modified in asound.conf file or if there's any limitation that i am hitting when playing 16 vs 8 channels in the alsa-lib that's causing this issue.
The other links that i have seen regarding this issue are below. they are very old links and some say its fixed but i am not sure how it was fixed or what those patches were. our system is using alsa version 1.1.6 with kernel 4.14 and is present in this build. please point me to any patchset or link that shows how to resolve this issue. i have hit a dead end at this time regarding this issue and also due to my limited knowledge in this area.
[https://bugzilla.redhat.com/show_bug.cgi?id=534130][1]
[https://www.raspberrypi.org/forums/viewtopic.php?t=64936][2]
[https://sourceforge.net/p/alsa/mailman/message/26464680/][3]