SPDIF S24_LE S24_3LE调试小结

在验证spdif S24_3LE/S24_LE格式的数据播放时,因为我的linux rootfs中没有alsa-libaplay,所以我用了android中的tinyalsa

因为android tinyalsa默认是不支持24bit数据的,所以需要先修改tinyalsa

 

CarlLinux rootfs 下, 底层注册了两个声卡,但是在/dev/snd/下面只有第一个声卡的相关节点。从底层的打印消息来看,底层完成了第二个声卡创建节点的工作。当我尝试用下面方式手动创建节点时,创建的节点是和底层一致,可以用的:

mknod /dev/snd/pcmC1D0p c 116 48 // c的意思是字符设备, 116主设备号,48次设备号

mknod /dev/snd/controlC1 c 116 32

另外,还可以在Linux rootfsetc/目录下增加mdev.conf,里面的内容如下:

# alsa sound devices and audio stuff

pcm.*       0:0 660 =snd/

control.*   0:0 660 =snd/

midi.*      0:0 660 =snd/

seq         0:0 660 =snd/

timer       0:0 660 =snd/

按照mdev.conf的例子,上面红色的0:0应该是用root:audio,但是这样用时却没有效果。不知道具体原因。

 

CarlLinux rootfs中的aplay 播放S24_LE S24_3LE文件的音乐时,底层收到的参数都是S24_LE的。这是因为alsa-libS24_3LE转换成了S24_LE

 

如果想直接播放S24_3LE,而不是将它转换成S24_LE,该如何办?

首先,对于android来讲,默认的tinyalsa只能认出是16bit还是24bit数据,却无法区分24bit中的S24_LE24bit数据放到4bytes/32bits空间里)或S24_3LE24bit数据紧接着下一个24bit数据,是放在3bytes空间里面)。

我们先看下wav文件的包头(windows下用HxD/ultraedit打开wav文件, linux下用hexdump)

上面阴影部分的52 49 46 46 RIFF四个字母的ASCII值。

上面阴影部分的四个值18 55 86 00代表波形文件大小,计算大小的时候是按照00 86 55 18

也就是0x865518 = 8803608 bytes,但是这个值要加上8 bytes(52 49 46 46 18 55 86 00)

上面阴影部分是WAVEfmtASCII, 最后一位0x20=32是空格的ASCII码。

上面阴影部分的02 00应该读成00 02,也就是2,代表两个声道。

上面阴影部分的80 BB 00 00代表采样率,读成0xBB80 = 48000

上面阴影为每秒钟播放的字节数:48000 * 24 *2 = 采样率*采样位数*声道数= 2304000 bits

2304000/8 = 288000 bytes = 0x 04 65 00

上面阴影的意思是24 bits 是放到6/2=3 bytes里面存储的,也就是该数据格式是S24_3LE

对于S24_LE来讲,这个值应该是8,也就是24bits数据是放到4 bytes = 32bits中的。

这两个bytes叫做BlockAlign,我们可以根据它来区分S24_LE/S24_3LE

上面阴影部分18 00该读成00 18 0x18=24,是24 bit 的意思。

androidtinyplay.c中,struct chunk_fmt中有一个block_align可以用来区分S24_LE/S24_3LE

 

 

 

tinyalsa的这些参数,是怎么传到底层的:

 

 

 

对于S16_LE来讲:

bit = 2,

    (bit >> 5) = 0

    (1 << (bit & 31)) = (1 << 2) = 4

    m->bits[bit >> 5] = m->bits[0]

    m->bits[0] = m->bits[0] | 4 = 4

    m->bits[0] = 4 = 0x0004

    m->bits[1] = 0

对于S24_LE来讲:

bit = 6,

    (bit >> 5) = 0

    (1 << (bit & 31)) = (1 << 6) = 64

    m->bits[bit >> 5] = m->bits[0]

    m->bits[0] = m->bits[0] | 64 = 64

    m->bits[0] = 64 = 0x0040

    m->bits[1] = 0

对于S24_3LE来讲:

bit = 32,

    (bit >> 5) = 1

    (1 << (bit & 31)) = (1 << 0) = 1

    m->bits[bit >> 5] = m->bits[1]

    m->bits[1] = m->bits[1] | 1 = 1

    m->bits[0] = 0

    m->bits[1] = 1 = 0x0001

这些参数,都通过ioctl传递到了底层:

 

在底层:

 

 

 

在上面会对m->bits[3/2/1/0] snd_mask_refine之后的m->bits[3/2/1/0]进行比较。

刚开始,由于底层dummy_codec那边不支持S24_3LE数据格式,在播放S24_3LE格式音乐时,这边的比较通不过。

 

在底层也要加入S24_3LE格式的支持,尤其是在soc-utils.c中的dummy_codec_dai中,因为我们spdif用的是dummy_dodec,而dummy_codec的默认代码中是不支持S24_3LE格式的。

 

 

通过上面的方法,我可以解决S24_3LE无法播放。

但是测试后发现,第一次播放S24_3LE是正常的,停止后继续重新播放,就会有时候播出来的是噪音。用示波器量输出波形,发现是有声音数据的,我自己在声音数据里加入了很多规律性的数据,比如说0xAA1010 1010),通过示波器也是可以量出来的,所以怀疑是不是数据发生了偏移

IC那边讨论后,发现,S24_3LE是比较特殊的,DMA那边搬3笔数据,SPDIF把它解释成四笔:

如果播放结束后,SPDIF FIFO里有残留数据,会破坏下一次数据的时序,所以需要在播放结束的时候,将FIFODMAreset。而我这边是忘了在spdif trigger stop里面将DMA Request Router关掉。

 

在调试的过程当中,为了更好的观察输出信号的质量,可以播放一些特殊文件,如方波/正弦波。可以通过goldwave来做出这些特殊文件(工具/表达式计算器):

调试S24_3LE_mono时,遇到了很有规律的噪音(正常的音乐之间夹杂着噪音),读数据时,发现有周期性的数据偏移。通过tinyplay -p调整period_size的时候,发现当设置period_size <= 1024的时候,底层拿到的runtime->period_size = 1366,当设置 period_size  = 2048\4096的时候,底层拿到的runtime->period_size = 2048\4096。原因可能是底层设置period_bytes_min = 4*1024 period_bytes_max = 16*1024,当你手动设置一个1024period_size时,因为它不在底层规定的范围内,所以alsa计算出了一个奇怪的period_size值(1366)。当设置period_bytes_min = 1024时,上述问题可以被解决:

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值