完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
Platform: Rockchip OS: Android 6.0 Kernel: 3.10.92 借用网友的一张图,刚开始看code的时候,存在了误区,以为系统分配了n个buffer_size的buffer,后来才发现图里这么多buffer_size在code中其实都只是模拟一个循环buffer,读写指针的数值一直增大,这样他们俩理论上不会遇到,也就是没有圆形循环buffer的逻辑问题,相当于把圆形buffer拉成一条直线,然后在最终计算的时候对buffer_size求余得到读写偏移地址。还有dma_buffer的起始位置也是不会变化的,dma初始化的时候已经预分配好了。 以录音为例: snd_pcm_lib_read1 -> pcm_lib.c snd_pcm_update_hw_ptr -> snd_pcm_update_hw_ptr0 -> pcm_lib.c substream->ops->pointer -> //这个函数指针很关键! 初始化时在soc_new_pcm()中注册 soc_pcm_pointer -> soc-pcm.c platform->driver->ops->pointer -> //snd_dmaengine_pcm_register()中注册dmaengine_no_residue_pcm_platform snd_dmaengine_pcm_pointer_no_residue static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, unsigned int in_interrupt) { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t pos; snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base; snd_pcm_sframes_t hdelta, delta; unsigned long jdelta; unsigned long curr_jiffies; struct timespec curr_tstamp; struct timespec audio_tstamp; int crossed_boundary = 0; old_hw_ptr = runtime->status->hw_ptr; /* * group pointer, time and jiffies reads to allow for more * accurate correlations/corrections. * The values are stored at the end of this routine after * corrections for hw_ptr position */ //dma硬件读当前相对dma buffer address的偏移, //每次拿到的pos相对上一次的偏移量其实就是peroid_size, //也就是说每次读的size受peroid_size控制。 //而最多的pos是瘦buffer_size控制,当到达buffer_size之后,就会重置 pos = substream->ops->pointer(substream); ...... //runtime->hw_ptr_base以buffer_size的单位移动 hw_base = runtime->hw_ptr_base; //得到当前实际的读取位置 new_hw_ptr = hw_base + pos; if (in_interrupt) { /* we know that one period was processed */ /* delta = "expected next hw_ptr" for in_interrupt != 0 */ delta = runtime->hw_ptr_interrupt + runtime->period_size; ...... } /* new_hw_ptr might be lower than old_hw_ptr in case when */ /* pointer crosses the end of the ring buffer */ //当dma buffer完成一个buffer_size之后,pos又从0开始计算,这时就会成立。 if (new_hw_ptr < old_hw_ptr) { //hw_base要往后挪 hw_base += runtime->buffer_size; //防止移动后超过边界 if (hw_base >= runtime->boundary) { hw_base = 0; crossed_boundary++; } //重新更新正确的new_hw_ptr new_hw_ptr = hw_base + pos; } __delta: //delta其实就是0或者一个peroid_size delta = new_hw_ptr - old_hw_ptr; ...... /* Do jiffies check only in xrun_debug mode */ if (!xrun_debug(substream, XRUN_DEBUG_JIFFIESCHECK)) goto no_jiffies_check; ...... no_jiffies_check: ...... no_delta_check: //当dma没有读到数据,会直接返回,等待下一次中断到来更新pos. //当用户调用读写接口不更新pos的时候,会是这种情况 if (runtime->status->hw_ptr == new_hw_ptr) return 0; ...... if (in_interrupt) { delta = new_hw_ptr - runtime->hw_ptr_interrupt; if (delta < 0) delta += runtime->boundary; delta -= (snd_pcm_uframes_t)delta % runtime->period_size; runtime->hw_ptr_interrupt += delta; if (runtime->hw_ptr_interrupt >= runtime->boundary) runtime->hw_ptr_interrupt -= runtime->boundary; } //更新base和hw_ptr值 runtime->hw_ptr_base = hw_base; runtime->status->hw_ptr = new_hw_ptr; ...... return snd_pcm_update_state(substream, runtime); } snd_pcm_update_state(): int snd_pcm_update_state(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime) { snd_pcm_uframes_t avail; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) avail = snd_pcm_playback_avail(runtime); else //计算出当前总buffer有效数据空间 avail = snd_pcm_capture_avail(runtime); if (avail > runtime->avail_max) runtime->avail_max = avail; if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { if (avail >= runtime->buffer_size) { snd_pcm_drain_done(substream); return -EPIPE; } } else { if (avail >= runtime->stop_threshold) { xrun(substream); return -EPIPE; } } ...... return 0; } static inline snd_pcm_uframes_t snd_pcm_capture_avail(struct snd_pcm_runtime *runtime) { //hw_ptr为当前硬件录音后没被读走的终点位置,appl_ptr为应用层读取的当前位置,也就是硬件录音没被读取的起点位置 snd_pcm_sframes_t avail = runtime->status->hw_ptr - runtime->control->appl_ptr; if (avail < 0) avail += runtime->boundary; return avail; } 原作者:KrisFei |
|
相关推荐
1个回答
|
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
2121 浏览 1 评论
synopsys 的design ware:DW_fpv_div,浮点数除法器,默认32位下,想提升覆盖率(TMAX),如果用功能case去提升覆盖率呢?
2767 浏览 1 评论
RK3588 GStreamer调试四路鱼眼摄像头四宫格显示报错
5542 浏览 1 评论
【飞凌嵌入式OK3576-C开发板体验】RKNN神经网络-YOLO图像识别
254 浏览 0 评论
【飞凌嵌入式OK3576-C开发板体验】SSH远程登录网络配置及CAN通讯
1336 浏览 0 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-29 17:12 , Processed in 0.726081 second(s), Total 71, Slave 56 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号