camillaDSP: How to monitor and control audio channel mapping to HDMI?

The goal is to make writes at multiples of 192 samples which is length of the HDMI audio block. IIUC then an xrun at that write size should keep the audio block at standard 192 samples. Maybe the HDMI receiver does not work nicely with shorter audio blocks, even if they are properly aligned to 8 channels (which they should be as all writes are aligned to audio frames). I do not know, it's just a test. But it's important to check the actual period length in the hw_params file.
 
Code:
gordoste@raspberrypi:~ $ (while true; do for CH in '\x01' '\x02' '\x03' '\x04' '\x05' '\x06' '\x07' '\x08' ; do echo -n -e $CH; echo -n -e '\x00\x00'; done; done ) | aplay -v -c 8 -f S24_3LE  -r 48000  -D testiec
Playing raw data 'stdin' : Signed 24 bit Little Endian in 3bytes, Rate 48000 Hz, Channels 8
IEC958 subframe conversion PCM (IEC958_SUBFRAME_LE)
Its setup is:
  stream       : PLAYBACK
  access       : RW_INTERLEAVED
  format       : S24_3LE
  subformat    : STD
  channels     : 8
  rate         : 48000
  exact rate   : 48000 (48000/1)
  msbits       : 24
  buffer_size  : 16384
  period_size  : 4096
  period_time  : 85333
  tstamp_mode  : NONE
  tstamp_type  : MONOTONIC
  period_step  : 1
  avail_min    : 4096
  period_event : 0
  start_threshold  : 16384
  stop_threshold   : 16384
  silence_threshold: 0
  silence_size : 0
  boundary     : 4611686018427387904
Slave: File PCM (file=/tmp/out.raw)
Final file PCM (file=/tmp/out.raw)
Its setup is:
  stream       : PLAYBACK
  access       : MMAP_INTERLEAVED
  format       : IEC958_SUBFRAME_LE
  subformat    : STD
  channels     : 8
  rate         : 48000
  exact rate   : 48000 (48000/1)
  msbits       : 24
  buffer_size  : 16384
  period_size  : 4096
  period_time  : 85333
  tstamp_mode  : NONE
  tstamp_type  : MONOTONIC
  period_step  : 1
  avail_min    : 4096
  period_event : 0
  start_threshold  : 16384
  stop_threshold   : 16384
  silence_threshold: 0
  silence_size : 0
  boundary     : 4611686018427387904
Slave: Hardware PCM card 1 'vc4-hdmi-1' device 0 subdevice 0
Its setup is:
  stream       : PLAYBACK
  access       : MMAP_INTERLEAVED
  format       : IEC958_SUBFRAME_LE
  subformat    : STD
  channels     : 8
  rate         : 48000
  exact rate   : 48000 (48000/1)
  msbits       : 24
  buffer_size  : 16384
  period_size  : 4096
  period_time  : 85333
  tstamp_mode  : NONE
  tstamp_type  : MONOTONIC
  period_step  : 1
  avail_min    : 4096
  period_event : 0
  start_threshold  : 16384
  stop_threshold   : 16384
  silence_threshold: 0
  silence_size : 0
  boundary     : 4611686018427387904
  appl_ptr     : 0
  hw_ptr       : 0
underrun!!! (at least 603.243 ms long)
Status:
  state       : XRUN
  trigger_time: 120109.856139
  tstamp      : 0.000000
  delay       : 0
  avail       : 16400
  avail_max   : 16400
underrun!!! (at least 601.405 ms long)
Status:
  state       : XRUN
  trigger_time: 120113.642725
  tstamp      : 0.000000
  delay       : 0
  avail       : 16400
  avail_max   : 16400
underrun!!! (at least 607.963 ms long)
Status:
  state       : XRUN
  trigger_time: 120117.431007
  tstamp      : 0.000000
  delay       : 0
  avail       : 16400
  avail_max   : 16400
underrun!!! (at least 606.215 ms long)
Status:
  state       : XRUN
  trigger_time: 120121.231995
  tstamp      : 0.000000
  delay       : 0
  avail       : 16400
  avail_max   : 16400
^CAborted by signal Interrupt...

I didn't need to nice aplay or anything to cause the xruns, perhaps file output of alsa couldn't keep up. They happen regularly every 4 seconds.

The first few samples look similar to yours (the '80' varies to c0 and 40 at various times):
Code:
gordoste@raspberrypi:/tmp $ xxd  -c32 -g1 out.raw | head
00000000: 18 00 00 80 24 00 00 80 34 00 00 00 44 00 00 80 54 00 00 00 64 00 00 00 74 00 00 80 84 00 00 80  ....$...4...D...T...d...t.......
00000020: 12 00 00 80 24 00 00 80 34 00 00 00 44 00 00 80 54 00 00 00 64 00 00 00 74 00 00 80 84 00 00 80  ....$...4...D...T...d...t.......
00000040: 12 00 00 80 24 00 00 80 34 00 00 00 44 00 00 80 54 00 00 00 64 00 00 00 74 00 00 80 84 00 00 80  ....$...4...D...T...d...t.......
00000060: 12 00 00 80 24 00 00 80 34 00 00 00 44 00 00 80 54 00 00 00 64 00 00 00 74 00 00 80 84 00 00 80  ....$...4...D...T...d...t.......
00000080: 12 00 00 80 24 00 00 80 34 00 00 00 44 00 00 80 54 00 00 00 64 00 00 00 74 00 00 80 84 00 00 80  ....$...4...D...T...d...t.......
000000a0: 12 00 00 80 24 00 00 80 34 00 00 00 44 00 00 80 54 00 00 00 64 00 00 00 74 00 00 80 84 00 00 80  ....$...4...D...T...d...t.......
000000c0: 12 00 00 80 24 00 00 80 34 00 00 00 44 00 00 80 54 00 00 00 64 00 00 00 74 00 00 80 84 00 00 80  ....$...4...D...T...d...t.......
000000e0: 12 00 00 80 24 00 00 80 34 00 00 00 44 00 00 80 54 00 00 00 64 00 00 00 74 00 00 80 84 00 00 80  ....$...4...D...T...d...t.......
00000100: 12 00 00 80 24 00 00 80 34 00 00 00 44 00 00 80 54 00 00 00 64 00 00 00 74 00 00 80 84 00 00 80  ....$...4...D...T...d...t.......
00000120: 12 00 00 40 24 00 00 40 34 00 00 c0 44 00 00 40 54 00 00 c0 64 00 00 c0 74 00 00 40 84 00 00 40  ...@$..@4...D..@T...d...t..@...@

The command

Code:
xxd -c 32 -g 1 /tmp/out.raw | grep -v "54 00 00"

Returns no output which seems to indicate no sample shifting though.
 
Last edited:
See my edit for the reason I chose that grep... I randomly selected channel 5 to see if it ever gets corrupted.

Code:
gordoste@raspberrypi:/tmp $ df -k
Filesystem     1K-blocks     Used Available Use% Mounted on
udev             1669488        0   1669488   0% /dev
tmpfs             388432     1452    386980   1% /run
/dev/mmcblk0p2  60798236 13946012  43743904  25% /
tmpfs            1942148      420   1941728   1% /dev/shm
tmpfs               5120       24      5096   1% /run/lock
/dev/mmcblk0p1    522232    74268    447964  15% /boot/firmware
tmpfs             388428       36    388392   1% /run/user/1000
/dev/sda1        7798784   842256   6956528  11% /media/gordoste/ESD-USB
tmpfs             388428       36    388392   1% /run/user/106
gordoste@raspberrypi:/tmp $ id
uid=1000(gordoste) gid=1000(gordoste) groups=1000(gordoste),4(adm),20(dialout),24(cdrom),27(sudo),29(audio),44(video),46(plugdev),60(games),100(users),102(input),105(render),106(netdev),115(lpadmin),993(gpio),994(i2c),995(spi)

I changed the .asoundrc to send the file to /run/user/1000/out.raw but it still gets the under-runs. I am using an SD card.
 
Does top show that the bash command can keep up generating the samples? If not, you can generate some block of samples into a file and cat that file in an endless loop.

I am not sure your grep can detect the corruption. IMO storing the output to less and scrolling through the list may show issues fast. Also what needs to be checked are the 18 every 192 lines, at best even at xrun. Maybe setting period size e.g. to 6144 (i.e. multiple of 192 frames).
 
Shell scripts often have bottlenecks due to too much process spawning. Here's a perl script to do this in a single process:
Code:
#!perl
while (1) { print "\001\0\0\002\0\0\003\0\0\004\0\0\005\0\0\006\0\0\007\0\0\010\0\0"; }
exit 0;
I then modified the script by the user oozmay from the thread on the RPi forums, placing the command
Code:
perl ~/test.pl | aplay -c8 -r48000 -fS24_3LE -D testiec &
where it had speaker-test.
Here is an example of the output running under sh -x:
Code:
sh -x test_chan_swap.sh
+ trap killall background EXIT
+ perl /home/gordoste/test.pl+ bgpid=15972

+ true
+ sleep 10
+ aplay -c8 -r48000 -fS24_3LE -Dtestiec
Playing raw data 'stdin' : Signed 24 bit Little Endian in 3bytes, Rate 48000 Hz, Channels 8
+ echo Forcing x-run...
Forcing x-run...
+ kill -STOP 15972
+ sleep 0.5
+ kill -CONT 15972
+ true
+ sleep 10
underrun!!! (at least 227.306 ms long)
+ echo Forcing x-run...
Forcing x-run...
+ kill -STOP 15972
+ sleep 0.5
+ kill -CONT 15972
+ true
+ sleep 10
underrun!!! (at least 237.979 ms long)
+ echo Forcing x-run...
Forcing x-run...
+ kill -STOP 15972
+ sleep 0.5
+ kill -CONT 15972
+ true
+ sleep 10
underrun!!! (at least 238.469 ms long)
+ echo Forcing x-run...
Forcing x-run...

After 14 under-runs I terminated it and was left with a 222MB output file. xxd output generates nearly 7 million lines... too many for manual scanning.

Here is the command I used to automatically scan the output and flag any improper data:
Code:
gordoste@raspberrypi:~ $ xxd -c32 -g4 /run/user/1000/out.raw | perl -lne '{print unless m/^[0-9a-f]{8}: 1[0-9a-f]0000[0-9a-f]0 2[0-9a-f]0000[0-9a-f]0 3[0-9a-f]0000[0-9a-f]0 4[0-9a-f]0000[0-9a-f]0 5[0-9a-f]0000[0-9a-f]0 6[0-9a-f]0000[0-9a-f]0 7[0-9a-f]0000[0-9a-f]0 8[0-9a-f]0000[0-9a-f]0 \s\S+$/}'
In case you aren't up on perl regexps, it checks that every 32-bit block looks like 0xN?0000?0 where N is the channel number.