当前位置: 首页 > news >正文

ALSA子系统(十八)------指纹解锁动画提示声卡顿问题解析

你好!这里是风筝的博客,

欢迎和我一起交流。


很久没写kernel相关的东西了,主要是来到手机厂之后,大部分还是在Android上,Kernel虽然也有涉及,但毕竟只是有所涉及,主要业务逻辑还是在HAL之上,kernel的修改除了项目bringup,之后基本甚少修改。

最近倒是碰到一个Kernel的问题,简单记录下~

【前提条件】【Prerequistes】手机录入指纹 声音与振动——触感与提示音开启指纹动画音, 指纹样式选择旋涡样式
【操作步骤】【Operation steps】播放QQ音乐,按power键息屏亮屏指纹解锁
【实际结果】【Actual results】指纹动画声音响起有卡顿声
【期望结果】【Expected results】不应该有卡顿声音
【对比的上个版本编号】【Number of previous version for comparison】低概率问题

以我多年工作经验来看,外放问题是最好解决的了,相对好处理些。
ivdump

查看AudioDspStreamManager.xx.TaskPlayback_ivdump.pcm文件,这是PA的VI反馈信号,可以反馈出喇叭的真实状态。从频谱上看,确实出现了卡顿,在解锁动画提示音响起的时候。

同样查看AudioDspStreamManager.xx.TaskPlayback_datain.pcm,发现确实Kernel里的数据就有问题了,但是查看streamout.pcm.xx.AudioALSAPlaybackHandlerDsp.flag8.xx.48000.8_24bit.2ch_20230411_092109.wav
是没有问题的,说明问题出现在了Kernel底层,没有出现在HAL。

因为提示音是短音,走的fast通路,buf又小,确实容易出现问题。

查看kernel log:

	<6>[83150.878119][T600541] mtk_dsp_check_exception() deep adsp underflow<6>[83150.926100][T516896] snd_audio_dsp snd_audio_dsp: mtk_dsp_start() deep just underflow<6>[83178.409440][T700541] mtk_dsp_check_exception() fast adsp underflow<6>[83178.419408][T712585] snd_audio_dsp snd_audio_dsp: mtk_dsp_start() fast just underflow

确实发现了异常,出现了underflow,这表明写数据慢了,没有数据可以播放,所以出现了underflow!
同步查看ADSP的log:

	 [83137.343]<A-22>[D]audio_dsp_hw_write_op(), HW_STATE_UNDERFLOW, return[83157.758]<A-11>[D] enter_write_cond, underflow, written_size[2048] datacount[0] task_name[fast_playback][83157.758]<A-11>[W] write_data_loop() ADSP_DL_CONSUME_UNDERFLOW[83166.654]<A-11>[D] enter_write_cond, underflow, written_size[2048] datacount[0] task_name[fast_playback][83166.654]<A-11>[W] write_data_loop() ADSP_DL_CONSUME_UNDERFLOW

确实同样可以看到underflow。

因为underflow是没有数据可播,属于写数据不及时,所以修改增大buffer size是没有用的。
所以我们只能另想它法!

这里简单描述下MTK的播放:
dsp

灵魂画手,嘿嘿,按照理解自己画了下图~

Hal往kernel写数据之后,会通过ipi核间通信,将数据送往DSP做处理,DSP上会跑我们用到的算法,处理完的数据就通过iis送到codec进行播放,kernel里面只负责管理对codec的control。

源码解析:
drivers/misc/mediatek/audio_ipi/common/adsp_ipi.c

static int __init audio_ipi_init(void)
{ipi_queue_init();audio_task_manager_init();audio_messenger_ipi_init();init_audio_ipi_dma();
#if IS_ENABLED(CONFIG_MTK_AUDIODSP_SUPPORT)adsp_register_notify(&audio_ctrl_notifier);
#endiffor (task_id = 0; task_id < TASK_SCENE_SIZE; task_id++) {task_info = &g_audio_task_info[task_id];dsp_id = audio_get_dsp_id(task_id);task_info->dsp_id = dsp_id;task_info->is_dsp_support = is_audio_dsp_support(dsp_id);task_info->is_adsp = is_audio_use_adsp(dsp_id);task_info->is_scp = is_audio_use_scp(dsp_id);task_info->task_ctrl = get_audio_controller_task(dsp_id);}ret = misc_register(&audio_ipi_device);
}

drivers/misc/mediatek/audio_ipi/common/adsp_ipi_queue.c

void ipi_queue_init(void)
{for (dsp_id = 0; dsp_id < NUM_OPENDSP_TYPE; dsp_id++) {if (is_audio_dsp_support(dsp_id))ipi_queue_init_by_dsp(dsp_id);}#if IS_ENABLED(CONFIG_MTK_AUDIODSP_SUPPORT)hook_ipi_queue_send_msg_handler(dsp_send_msg_to_queue_wrap);hook_ipi_queue_recv_msg_hanlder(dsp_dispatch_ipi_hanlder_to_queue_wrap);
#endif
}

hook_ipi_queue_send_msg_handler和hook_ipi_queue_recv_msg_hanlder主要是给ipi_queue_send_msg_handler和ipi_queue_recv_msg_handler这两个函数指针赋值的,在给dsp发送msg和接受msg的时候会用,这里没啥好说的,主要是:ipi_queue_init_by_dsp,这里会针对DSP做初始化:

int ipi_queue_init_by_dsp(uint32_t dsp_id)
{for (dsp_path = 0; dsp_path < DSP_NUM_PATH; dsp_path++) {msg_queue = &g_dsp_msg_queue[dsp_id][dsp_path];ret = dsp_init_single_msg_queue(msg_queue, dsp_id, dsp_path);if (ret != 0)WARN_ON(1);}
}

这里会循环两次:0是AP to DSP,1是DSP to AP。

static int dsp_init_single_msg_queue(struct dsp_msg_queue_t *msg_queue,const uint32_t dsp_id,const uint32_t dsp_path)
{if (dsp_path == DSP_PATH_A2D) {msg_queue->dsp_process_msg_func = dsp_send_msg_to_dsp;} else if (dsp_path == DSP_PATH_D2A) {msg_queue->dsp_process_msg_func = dsp_process_msg_from_dsp;} elseWARN_ON(1);/* lunch thread */msg_queue->dsp_thread_task = kthread_create(dsp_process_msg_thread,msg_queue,"%s",thread_name);if (IS_ERR(msg_queue->dsp_thread_task)) {pr_info("can not create %s kthread", thread_name);WARN_ON(1);msg_queue->thread_enable = false;} else {msg_queue->thread_enable = true;dsb(SY);wake_up_process(msg_queue->dsp_thread_task);}
}

重点看下这里面就好了,针对不同的情况,AP to DSP 还是 DSP to AP,会赋值不同的处理函数到dsp_process_msg_func。然后会创建线程:dsp_process_msg_thread,并启动:wake_up_process

static int dsp_process_msg_thread(void *data)
{while (msg_queue->thread_enable && !kthread_should_stop()) {/* wait until element pushed */retval = dsp_get_queue_element(msg_queue, &p_dsp_msg, &idx_msg);p_element = &msg_queue->element[idx_msg];/* send to dsp */retval = msg_queue->dsp_process_msg_func(msg_queue, p_dsp_msg);/* notify element if need */spin_lock_irqsave(&p_element->element_lock, flags);if (p_element->wait_in_thread == true) {p_element->send_retval = retval;p_element->signal_arrival = true;dsb(SY);wake_up_interruptible(&p_element->element_wq);}spin_unlock_irqrestore(&p_element->element_lock, flags);/* pop message from queue */spin_lock_irqsave(&msg_queue->queue_lock, flags);dsp_pop_msg(msg_queue);spin_unlock_irqrestore(&msg_queue->queue_lock, flags);}return 0;
}

线程里面处理还是比较简单的,就是等待有数据到queue里,如果有就通过之前填充的dsp_process_msg_func钩子函数,发给DSP处理即可。

好,扯了这么一大堆,回归本题,如果出现了underflow,说明写数据不及时,写数据就是通过dsp_process_msg_thread这个线程里面写到DSP的,所以,我们只需要保证这个线程的正常调度运行即可。

如何保证呢?自然是提升线程优先级!

为了使得用户能有良好的用户体验,dsp_init_single_msg_queue这里在创建线程的时候,这里直接将线程加入RT线程,RT (Real Thread)实时线程。
kthread_create线程创建之后,通过这个API:

struct sched_param param = { .sched_priority = 3 };
sched_setscheduler_nocheck(msg_queue->dsp_thread_task, SCHED_FIFO, &param);

即可加入RT线程。

加入RT线程之后,压测问题场景,没有再出现underflow的情况,卡顿问题也没有再复现了,问题完美解决~

最开始的audio_ipi_init函数里,还有一些内容就不多阐述了,DSP这块资料比较少,还是比较难去了解的,非本文重点。
audio_ipi_init后面就是配置DMA和TASK这些,每个scene占用一个Task:

        /* scene for library */TASK_SCENE_PHONE_CALL           = 0,TASK_SCENE_VOICE_ULTRASOUND     = 1,TASK_SCENE_PLAYBACK_MP3         = 2,TASK_SCENE_RECORD               = 3,TASK_SCENE_VOIP                 = 4,TASK_SCENE_SPEAKER_PROTECTION   = 5,TASK_SCENE_VOW                  = 6,TASK_SCENE_PRIMARY              = 7,TASK_SCENE_DEEPBUFFER           = 8,TASK_SCENE_AUDPLAYBACK          = 9,TASK_SCENE_CAPTURE_UL1          = 10,TASK_SCENE_A2DP                 = 11,//......

OK,后面就不表了,以后再说吧~

相关文章:

ALSA子系统(十八)------指纹解锁动画提示声卡顿问题解析

你好&#xff01;这里是风筝的博客&#xff0c; 欢迎和我一起交流。 很久没写kernel相关的东西了&#xff0c;主要是来到手机厂之后&#xff0c;大部分还是在Android上&#xff0c;Kernel虽然也有涉及&#xff0c;但毕竟只是有所涉及&#xff0c;主要业务逻辑还是在HAL之上&am…...

[230513] TPO72 | 2022年托福阅读真题第1/36篇 | 10:45

Invading Algae 目录 Invading Algae 全文 题目 Paragraph 1 P1 段落大意 问题1 Paragraph 2 P2 段落大意 问题2 *问题3* Paragraph 3 P3 段落大意 问题4 Paragraph 4 P4 段落大意 Paragraph 5 P5 段落大意 *问题5* *问题6* 问题7 问题8 问题9…...

操作符详解

目录 操作符分类 算术操作符 - * / % 二进制 二进制总结 移位操作符&#xff08;操作数只能为整数&#xff09; << >> 位操作符&#xff08;操作数必须为整数&#xff09; & | ^ 面试题 赋值操作符 复合赋值符 单目操作符 单目操作符介绍…...

【MATLAB图像处理实用案例详解(16)】——利用概念神经网络实现手写体数字识别

目录 一、问题描述二、概念神经网络实现手写体数字识别原理三、算法步骤3.1 数据输入3.2 特征提取3.3 模型训练3.4 测试 四、运行结果 一、问题描述 手写体数字属于光学字符识别&#xff08;Optical Character Recognition&#xff0c;OCR&#xff09;的范畴&#xff0c;但分类…...

数据库管理-第六十九期 另一种累(20230422)

数据库管理 2023-04-22 第六十九期 另一种累1 国产数据库沟通2 问题3 我的建议总结 第六十九期 另一种累 Oracle 23c的相关内容先缓缓&#xff0c;有些数据库管理相关的还是得正式版发布后才好去做实验。这周相较于之前那种割接较多的累还有点不一样&#xff0c;这周陪着客户交…...

Cesium入门之六:Cesium加载影像图层(ArcGIS、Bing、Mapbox、高德地图、腾讯地图、天地图等各类影像图)

Cesium加载影像图层 一、ImageryLayer类常用属性常用方法 二、ImageryLayerCollection类常用属性常用方法 三、ImageryProvider类常用属性常用方法 四、ImageryProvider子类1. ArcGisMapServerImageryProvider加载ArcGIS地图服务 2. BingMapsImageryProvider加载BingMap地图服务…...

Redis系列--redis持久化

一、为什么需要持久化 redis本身运行时数据保存在内存中&#xff0c;如果不进行持久化&#xff0c;那么在redis出现非正常原因宕机或者关闭redis的进程或者关闭计算机后数据肯定被会操作系统从内存中清掉。当然&#xff0c;redis本身默认采用了一种持久化方式&#xff0c;即RD…...

在外Windows远程连接MongoDB数据库【无公网IP】

文章目录 前言1. 安装数据库2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射2.3 测试随机公网地址远程连接 3. 配置固定TCP端口地址3.1 保留一个固定的公网TCP端口地址3.2 配置固定公网TCP端口地址3.3 测试固定地址公网远程访问 转载自远程内网穿透的文章&#xff1a;公网远…...

学网络安全怎么挖漏洞?怎么渗透?

前言 有不少阅读过我文章的伙伴都知道&#xff0c;我从事网络安全行业已经好几年&#xff0c;积累了丰富的经验和技能。在这段时间里&#xff0c;我参与了多个实际项目的规划和实施&#xff0c;成功防范了各种网络攻击和漏洞利用&#xff0c;提高了安全防护水平。 也有很多小…...

KL散度和交叉熵的对比介绍

KL散度&#xff08;Kullback-Leibler Divergence&#xff09;和交叉熵&#xff08;Cross Entropy&#xff09;是在机器学习中广泛使用的概念。这两者都用于比较两个概率分布之间的相似性&#xff0c;但在一些方面&#xff0c;它们也有所不同。本文将对KL散度和交叉熵的详细解释…...

浪涌保护器:保护电子设备免受雷击侵害

引言&#xff1a; 随着电子设备在现代生活和工业领域的普及和广泛应用&#xff0c;雷击对电子设备的损害成为一个严重的问题。浪涌保护器作为一种重要的防雷设备&#xff0c;发挥着至关重要的作用。本文将介绍浪涌保护器的防雷作用、行业应用&#xff0c;并重点介绍浪涌保护器…...

js绘制的红心

看腻歪了粒子特效的红心&#xff0c;今天给各位整个线条的&#xff0c;效果图如下&#xff1a; 表白显圣神器&#xff0c;你值得拥有&#xff0c;代码如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"…...

十、Feign客户端

目录 1、在springcloud-order项目中引入Feign客户端的依赖 2、在server-order服务的启动类中添加注解EnableFeignClients 3、使用FeignClient注解声明Feign客户端需要调用的远程接口 3.1、server-pay服务提供远程接口Controller 3.2、server-member服务提供远程接口Contro…...

登录appuploader

转载&#xff1a;登录appuploader 常规使用登录方法 双击appuploader.exe 启动appuploader 点击底部的未登录&#xff0c;弹出登录框 在登录框内输入apple开发者账号 如果没有apple开发者账号&#xff0c;只是普通的apple账号&#xff0c;请勾选上未支付688 然后软件会提示…...

都别吹牛逼了,2个英语指令简单评测便知ChatGPT、博弈Ai、文心一言、通义千问、讯飞星火真实水平

一、博弈Ai&#xff1a;GPT3.5版 演示&#xff1a;https://chat.bo-e.com/ 1、充当英语发言助手 评分&#xff1a;10分 总结&#xff1a;完整满足了指令需求 2、充当英汉互译器 评分&#xff1a;8分 总结&#xff1a;基本满足了我的指令需求。但是有点啰嗦&#xff0c;扣…...

使用Spring Boot快速搭建项目:减少配置,提升开发效率

使用Spring Boot快速搭建项目&#xff1a;减少配置&#xff0c;提升开发效率 一、Spring Boot简介1 Spring Boot的起源2 Spring Boot的核心特点3 Spring Boot的优势 二、Spring Boot快速搭建项目1 Spring Boot的项目搭建方式使用Spring Initializr创建项目使用Spring Boot CLI创…...

(2)数码管

LED数码管:数码管是一种简单、廉价的显示器&#xff0c;是由多个发光二极管封装在一起组成"8"字器件 51单片机是共阴极连接 74HC245这个芯片有什么作用呢&#xff1f;解&#xff1a;这个芯片被称之为双向数据缓冲器这个芯片的作用&#xff0c;用来进行数据缓冲(提高驱…...

赫夫曼树和赫夫曼编码详解

目录 何为赫夫曼树&#xff1f; 赫夫曼树算法 赫夫曼编码 编程实现赫夫曼树 编程实现赫夫曼编码 编程实现WPL 总代码及分析 何为赫夫曼树&#xff1f; 树的路径长度&#xff1a;从树根到每一结点的路径长度之和 结点的带权路径长度&#xff1a;从树根到该结点的路径长度…...

unity UGUI系统梳理 -交互组件

概述 unity 中的交互组件可用于处理交互&#xff0c;例如鼠标或触摸事件以及使用键盘或控制器进行的交互 1、按钮 (Button) Button详解 2、开关 (Toggle) Background&#xff1a;背景图片&#xff0c;控制toggle组件的背景颜色改变&#xff0c;从而展示此物体是否被选中的…...

HTTP第15讲——HTTP的连接管理

短连接 HTTP 协议最初&#xff08;0.9/1.0&#xff09;是个非常简单的协议&#xff0c;通信过程也采用了简单的“请求 - 应答”方式。 它底层的数据传输基于 TCP/IP&#xff0c;每次发送请求前需要先与服务器建立连接&#xff0c;收到响应报文后会立即关闭连接。 因为客户端与…...

如何解决SQL多表查询数据重复问题_使用DISTINCT与JOIN优化

...

别再让UI卡死了!C# UDP接收数据,用异步和Task轻松搞定后台监听

现代C# UDP通信实践&#xff1a;用异步编程拯救你的UI线程 在桌面应用开发中&#xff0c;实时数据接收是许多场景的核心需求——从工业传感器监控到金融行情展示&#xff0c;再到游戏服务器状态更新。传统多线程方案虽然能解决问题&#xff0c;却常常带来UI卡顿、资源泄漏等&qu…...

算法训练营第二天| 27. 双指针

题目链接&#xff1a;https://leetcode.cn/problems/remove-element/ 视频讲解&#xff1a;https://www.bilibili.com/video/BV12A4y1Z7LP自己看到题目的第一想法看到题目要求原地移除数组中所有等于给定值的元素&#xff0c;并返回新长度&#xff0c;我第一反应是这肯定不能真…...

Flink CDC 3.0.0 同步Oracle 19c数据,我踩过的那些坑(时区、字符集、权限)

Flink CDC 3.0.0同步Oracle 19c实战避坑指南 最近在金融级数据中台项目中实施Flink CDC 3.0.0对接Oracle 19c时&#xff0c;遇到了不少官方文档未提及的"深坑"。这些坑轻则导致数据不一致&#xff0c;重则引发生产事故。本文将分享五个典型问题的完整解决方案&#x…...

如何3分钟完成QQ音乐加密文件解密:专业音频格式转换方案

如何3分钟完成QQ音乐加密文件解密&#xff1a;专业音频格式转换方案 【免费下载链接】qmc-decoder Fastest & best convert qmc 2 mp3 | flac tools 项目地址: https://gitcode.com/gh_mirrors/qm/qmc-decoder 还在为QQ音乐下载的加密音频文件无法在其他播放器播放而…...

【2026推荐系统分水岭】:为什么92%的电商推荐团队在Q3前必须升级多模态架构?

SITS2026分享&#xff1a;多模态推荐系统 第一章&#xff1a;多模态推荐系统的时代必然性与战略拐点 2026奇点智能技术大会(https://ml-summit.org) 用户行为数据正经历从单一ID序列向跨模态语义流的范式跃迁。电商平台中&#xff0c;一次点击背后可能关联着商品图的视觉特征…...

贾子成功定理(高阶完整版):逆熵跃迁动力学——生于忧患的数学化模型

贾子成功定理&#xff08;高阶完整版&#xff09;&#xff1a;逆熵跃迁动力学——生于忧患的数学化模型摘要&#xff1a; 贾子成功定理高阶完整版将“生于忧患”转化为量化动力学模型&#xff0c;核心公式SkT/I&#xff0c;微分方程dS/dt kT - IS&#xff0c;稳态解S*kT/I。跃…...

Sogi锁相环代码及相关资料文档:电赛电源类重要参考,必备知识库

sogi锁相环代码资料文档。 电赛电源类必备。搞电源设计的兄弟对SOGI锁相环应该都不陌生。这玩意儿在逆变器、并网控制里简直是常驻嘉宾&#xff0c;尤其是电赛里头的数字锁相需求&#xff0c;传统模拟方案早就不够用了。今天咱们直接上干货&#xff0c;聊聊怎么用代码实现这个核…...

手把手教你部署MiniCPM-V-2_6:支持图文视频对话,开箱即用

手把手教你部署MiniCPM-V-2_6&#xff1a;支持图文视频对话&#xff0c;开箱即用 1. MiniCPM-V-2_6简介 MiniCPM-V 2.6是当前MiniCPM-V系列中最强大的多模态模型。这个80亿参数的模型基于SigLip-400M和Qwen2-7B构建&#xff0c;在单图理解、多图推理和视频分析方面都表现出色…...

如何永久保存微信聊天记录?WeChatMsg完整教程让数据真正属于你

如何永久保存微信聊天记录&#xff1f;WeChatMsg完整教程让数据真正属于你 【免费下载链接】WeChatMsg 提取微信聊天记录&#xff0c;将其导出成HTML、Word、CSV文档永久保存&#xff0c;对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/…...