ALSA子系统(十八)------指纹解锁动画提示声卡顿问题解析
你好!这里是风筝的博客,
欢迎和我一起交流。
很久没写kernel相关的东西了,主要是来到手机厂之后,大部分还是在Android上,Kernel虽然也有涉及,但毕竟只是有所涉及,主要业务逻辑还是在HAL之上,kernel的修改除了项目bringup,之后基本甚少修改。
最近倒是碰到一个Kernel的问题,简单记录下~
【前提条件】【Prerequistes】手机录入指纹 声音与振动——触感与提示音开启指纹动画音, 指纹样式选择旋涡样式
【操作步骤】【Operation steps】播放QQ音乐,按power键息屏亮屏指纹解锁
【实际结果】【Actual results】指纹动画声音响起有卡顿声
【期望结果】【Expected results】不应该有卡顿声音
【对比的上个版本编号】【Number of previous version for comparison】低概率问题
以我多年工作经验来看,外放问题是最好解决的了,相对好处理些。
查看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的播放:
灵魂画手,嘿嘿,按照理解自己画了下图~
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, ¶m);
即可加入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子系统(十八)------指纹解锁动画提示声卡顿问题解析
你好!这里是风筝的博客, 欢迎和我一起交流。 很久没写kernel相关的东西了,主要是来到手机厂之后,大部分还是在Android上,Kernel虽然也有涉及,但毕竟只是有所涉及,主要业务逻辑还是在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…...

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

【MATLAB图像处理实用案例详解(16)】——利用概念神经网络实现手写体数字识别
目录 一、问题描述二、概念神经网络实现手写体数字识别原理三、算法步骤3.1 数据输入3.2 特征提取3.3 模型训练3.4 测试 四、运行结果 一、问题描述 手写体数字属于光学字符识别(Optical Character Recognition,OCR)的范畴,但分类…...
数据库管理-第六十九期 另一种累(20230422)
数据库管理 2023-04-22 第六十九期 另一种累1 国产数据库沟通2 问题3 我的建议总结 第六十九期 另一种累 Oracle 23c的相关内容先缓缓,有些数据库管理相关的还是得正式版发布后才好去做实验。这周相较于之前那种割接较多的累还有点不一样,这周陪着客户交…...

Cesium入门之六:Cesium加载影像图层(ArcGIS、Bing、Mapbox、高德地图、腾讯地图、天地图等各类影像图)
Cesium加载影像图层 一、ImageryLayer类常用属性常用方法 二、ImageryLayerCollection类常用属性常用方法 三、ImageryProvider类常用属性常用方法 四、ImageryProvider子类1. ArcGisMapServerImageryProvider加载ArcGIS地图服务 2. BingMapsImageryProvider加载BingMap地图服务…...

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

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

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

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

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

js绘制的红心
看腻歪了粒子特效的红心,今天给各位整个线条的,效果图如下: 表白显圣神器,你值得拥有,代码如下: <!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
转载:登录appuploader 常规使用登录方法 双击appuploader.exe 启动appuploader 点击底部的未登录,弹出登录框 在登录框内输入apple开发者账号 如果没有apple开发者账号,只是普通的apple账号,请勾选上未支付688 然后软件会提示…...

都别吹牛逼了,2个英语指令简单评测便知ChatGPT、博弈Ai、文心一言、通义千问、讯飞星火真实水平
一、博弈Ai:GPT3.5版 演示:https://chat.bo-e.com/ 1、充当英语发言助手 评分:10分 总结:完整满足了指令需求 2、充当英汉互译器 评分:8分 总结:基本满足了我的指令需求。但是有点啰嗦,扣…...
使用Spring Boot快速搭建项目:减少配置,提升开发效率
使用Spring Boot快速搭建项目:减少配置,提升开发效率 一、Spring Boot简介1 Spring Boot的起源2 Spring Boot的核心特点3 Spring Boot的优势 二、Spring Boot快速搭建项目1 Spring Boot的项目搭建方式使用Spring Initializr创建项目使用Spring Boot CLI创…...

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

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

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

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

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...

《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
C语言中提供的第三方库之哈希表实现
一. 简介 前面一篇文章简单学习了C语言中第三方库(uthash库)提供对哈希表的操作,文章如下: C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...
区块链技术概述
区块链技术是一种去中心化、分布式账本技术,通过密码学、共识机制和智能合约等核心组件,实现数据不可篡改、透明可追溯的系统。 一、核心技术 1. 去中心化 特点:数据存储在网络中的多个节点(计算机),而非…...

FFmpeg avformat_open_input函数分析
函数内部的总体流程如下: avformat_open_input 精简后的代码如下: int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...