0

    比内存被踩还难调试的问题

    2023.06.24 | admin | 441次围观

    DEBUG

    比内存被踩

    还难调试的问题

    软件领域的难题很多。在很多同行看来,内存数据被踩是很难调试的问题,因为内存空间很大,内存中的数据很多,重要的数据和不重要的数据杂居交错,鱼龙混杂,一个数据被踩了后,它又不会说话,等发现时,已经不知道过了多久,这时再还原真相,就很不容易了。

    在我看来,内存被踩的问题的确有难度,但并不是最难的。还有一些问题比它的难度大,比如声音的问题。

    Part 01

    声音的捕捉和回放

    Capture & Playback

    声音的捕捉(capture)和回放(playback)是多媒体技术中的重要部分了。简单说,声音的捕捉和回放就是分别把声音信号做AD和DA转换。但因为如下几个因素,它变得复杂了。

    一个因素是系统里常常要支持多种声音设备,通俗说,就是多声“卡”。以幽兰为例,就有两个声卡,使用aplay -l可以列出:

    geduer@ulan:~$ aplay**** List of PLAYBACK Hardware Devices ****card 0: rockchipes8326 [rockchip-es8326], device 0: dailink-multicodecs ES8326.3-0019-0 [dailink-multicodecs ES8326.3-0019-0]  Subdevices: 1/1  Subdevice #0: subdevice #0card 1: rockchiphdmi0 [rockchip-hdmi0], device 0: rockchip-hdmi0 i2s-hifi-0 [rockchip-hdmi0 i2s-hifi-0]  Subdevices: 1/1  Subdevice #0: subdevice #0

    幽兰主板上的

    “声卡”芯片

    其中,card 0是内建的声卡设备,主要部件是贴在主板上的两块芯片,大一点的叫ES8326,小一点的是与ES8326配合使用的AD/DA转换芯片。

    第二个因素是声音格式有很多种,技术参数众多,比如采样率,编码宽度,数据压缩方式等等。

    上面两个因素就可以产生出很多种排列组合。为了管理这些组合方式,一种比较先进的方法是使用“图”。把处理视频的每个部件称为节点(Node),每个节点可以有一或者多个端口(Port),端口之间可以互联(link)。有了这样的图后,声音数据流便在这个图中“流淌”。

    记得大约十年前网站视频声音代码关闭,我的一位英特尔同事离职创业,做了一款特殊用途的平板电脑,软硬件都跑起来后,发现声音有问题,回放时声音流偶尔有“断裂”。当时使用的是系统是Windows,声音子系统叫UAA(Universal Audio Architecture)。UAA使用复杂的软件栈来管理声音数据,当系统中的CPU忙碌时便可能来不及把声音数据及时送给声音硬件,这时就会出现声音“断断续续”、不流畅。对于这样的问题,有很大的随机性,不好复现,上调试器也不容易找到问题,很难调试。

    Part 02

    失声的幽兰

    'Aphasic' Yourland

    在幽兰上运行qpwgraph观察音频设备节点

    今日幽兰上也出现了一个声音的问题:在把Ubuntu系统升级到23.04后,没有声音了,播放视频没有声音,麦克风输入也不工作。

    在Ubuntu 23.04中,默认使用了名为PipeWare的音频服务器。在升级之前,系统中使用的音频服务器叫PulseAudio。PulseAudio已经在Linux中流行了十几年,已经有很多应用是基于它开发的,但是它在安全性方面有个明显的问题,各个应用之间缺少隔离,可以相互影响。

    除此以外,Linux的声音子系统也一直有卡顿和不流畅的问题。而PipeWire则旨在彻底改变这个局面,革新内部实现,以全新的设计打造一个强大的音视频服务系统,替换到本来的实现,而在接口方面,尽可能保持兼容现有的各种应用。

    PipeWire不是个小工程,这个工程从2015年左右就开始了,起初的名字叫皮洛斯(Pinos),是以主要作者Wim Taymans所居住的城市命名的。

    Wim Taymans

    在GStreamer 2015

    会议上介绍Pinos

    到2020年时,Pinos已经基本完成,开始工作,并且有了一个新的名字,叫PipeWire。

    Wim Taymans在2020年9月

    演示初步完成的PipeWire

    在幽兰的最初镜像中,使用的是Ubuntu 20.04和PulseAudio,升级到23.04后,默认使用的音频服务器便改为PipeWire。测试时,我们很快便发现了声音有问题,播放视频没有声音,Sound设置中没有输入设备。

    使用pw-top工具观察,可以看到有音频数据在活动,但是却听不到声音。

    如前面所说,幽兰有两个声卡,使用HDMI时,能听到声音,pw-top看到的活动信息与使用8326类似。

    当观察日志时,有两种声音有关的错误信息。一种是安全权限有关的,如下图所示。

    上面的日志中,有两条都包含Permission denied。而且这个信息也出现在pipewire的其它服务中。原因看起来是pipewire想提高自己的优先级,以便可以多拿到CPU执行时间,但是这样的操作被系统拒绝了。

    网站视频声音代码关闭_5月30所有视频网站关闭弹幕_微信视频怎么关闭声音

    另一类错误信息是来自内核驱动,打印出的信息是:TX FIFO Underrun

    root@ulan:/# dmesg[ 3878.801599] rockchip_i2s_tdm_isr: 411761 callbacks suppressed[ 3878.801609] rockchip-i2s-tdm fe470000.i2s: TX FIFO Underrun[ 3878.801620] rockchip-i2s-tdm fe470000.i2s: TX FIFO Underrun[ 3878.801647] rockchip-i2s-tdm fe470000.i2s: TX FIFO Underrun[ 3878.801651] rockchip-i2s-tdm fe470000.i2s: TX FIFO Underrun[ 3878.801667] rockchip-i2s-tdm fe470000.i2s: TX FIFO Underrun[ 3878.801688] rockchip-i2s-tdm fe470000.i2s: TX FIFO Underrun[ 3878.801694] rockchip-i2s-tdm fe470000.i2s: TX FIFO Underrun[ 3878.801709] rockchip-i2s-tdm fe470000.i2s: TX FIFO Underrun[ 3878.801714] rockchip-i2s-tdm fe470000.i2s: TX FIFO Underrun[ 3878.801730] rockchip-i2s-tdm fe470000.i2s: TX FIFO Underrun

    Underrun是相对overrun而言的,意思是发送(TX)视频数据的FIFO队列里缺少数据,换句话来说就是供给没有消耗快,供不上硬件使用。

    在驱动代码中找到打印这个消息的地方网站视频声音代码关闭,它的确有stop_xrun的行为。

    于是,我们花了不少时间在这两类错误上,但是都没有什么收效。

    从pw-top的数据活动情况看,音频数据是在流动的,但是没有声音播放出来,则说明数据没有流动到硬件队列,可能是FIFO队列出了underrun的故障后,处理故障时出错了。

    为了定位这个错误,我们曾尝试把gdb附加到音频服务进程,但是这个进程太敏感了,挂上gdb后,进程便退出(深层原因待查)。

    既然服务进程敏感,我们便把gdb挂在播放视频的mpv进程上,看到了一些错误信息。

    今日Pipewire的官方网站提供了一些诊断方法,包括调整日志级别,从源代码编译和在源代码目录不安装运行(make run)等,但都没有解决问题。我们也曾想到把PipeWire卸载掉,回退到PulseAudio,但是在卸载PipeWire时发现,因为桌面程序依赖PipeWire,所以卸载PipeWire会导致桌面软件被卸载。

    geduer@ulan:~$ sudo apt remove pipewire[sudo] password for geduer:Reading package lists... DoneBuilding dependency tree... DoneReading state information... DoneThe following packages will be REMOVED:  gdm3 gnome-remote-desktop gnome-shell gnome-shell-extension-appindicator gnome-shell-extension-desktop-icons-ng gnome-shell-extension-ubuntu-dock gstreamer1.0-pipewire pipewire pipewire-jack  pipewire-pulse ubuntu-desktop ubuntu-desktop-minimal ubuntu-session wireplumber0 upgraded, 0 newly installed, 14 to remove and 13 not upgraded.After this operation, 10.5 MB disk space will be freed.Do you want to continue? [Y/n]

    这个依赖太强了,让我们放弃了这个想法。

    以上方法都尝试了之后,我决定放缓解决这个问题,使用“缓兵之计”,让同事先做其它任务,只留我一个人一边准备3588配套课程的讲义,一边看代码。

    说是缓兵之计,但因为这个问题不解决新镜像就没法发布,所以,我还是有些着急的。一边看代码,一边结合着代码在幽兰上做试验,做各种尝试。

    Part 03

    柳暗花明

    Enchanting Sight

    in Spring Time

    上海今日下雨,从昨晚就开始下,一直到早晨,又持续到上午。因为下雨,气温一下子低了下来。窗外的雨声滴滴答答,把树叶冲洗得干干净净,鲜绿鲜绿。格蠹的办公室里很安静,只有键盘的声音。看了一阵子代码后,我突发奇想,起身拍了个照,并顺手发到了朋友圈,想记录一下这春夏之交的平凡一天。

    拍照之后,我继续一边看代码一边做试验。在反复看了几次pipewire的配置文件后,大胆地做了一个修改。这次修改后,再尝试播放视频,log中的错误信息不一样了。

    这次的错误信息中有多处是:“Device or resource busy”。总的来说,硬件是不可以被多个程序同时用的,设计Pipewire这样的服务进程,某种程度来说就是为了把多个应用的需求结合起来,让PipeWire一个人与硬件沟通。而此时,我的声音设置界面是打开的。

    把声音设置窗口关闭,再用mpv播放视频文件,这一次,幽兰主板两侧的扬声器真的发出声音了。

    使用pw-top观察,这次的音频数据是在传递给我新创建的音频插槽(sink),名叫alsa_sink。

    困扰多日的问题终于解决了。回顾起来,除了开篇提到的音频问题难点外,其实还有一个更基本的障碍,那就是涉及的问题域太大,既有内核空间,又有用户空间,既有mpv这样的应用软件,还有很多个敏感的后台服务。这么多角色加在一起后,总的代码量巨大,总的变量数太多。当然这个问题的难度也体现在涉及相对较新的PipeWire系统,它推出的时间较短,资料比较少。

    这次的调试经历也坚定了我把工作环境迁移到幽兰的想法。一般说来,Linux是指Linux内核。但是实际上,内核本身是无法使用的,大家真正使用的都是Linux系统,这个系统要比内核大很多。因为此,学习Linux,只学习内核是不够的,还要学习用户空间的各种系统服务和子系统。而要熟悉整个系统的最好方法就是把工作环境迁移过去,与它们朝夕相处。

    ·· Yourland ··

    — End —

    购买幽兰代码本即可成为兰舍会员,与众多技术高手一起成长。

    购买可前往淘宝格友小店:

    盛格塾是格蠹科技旗下的知识分享平台,是以“格物致知”为教育理念的现代私塾。

    本着为先圣继绝学的思想,盛格塾努力将传统文化中的精华与现代科技密切结合,以传统文化和人文情怀阐释现代科技,用现代科技传播传统文化。

    访问方式

    手机端:微信小程序搜索“盛格塾”

    电脑端:下载Nano Code社区版客户端

    #/download

    格友公众号

    盛格塾小程序

    版权声明

    本文仅代表作者观点。
    本文系作者授权发表,未经许可,不得转载。

    发表评论