ALSADMA缓冲区分析
来源:互联网 发布:返利网在淘宝上买手机 编辑:程序博客网 时间:2024/06/08 09:25
ALSA应用程序(播放器)调用ALSA lib库中的函数snd_pcm_writei()向声卡硬件(或虚拟的)写入交错(write后的i代表interleaved)数据。在ALSA lib中最后会调到snd_pcm_hw_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)函数,这个函数调用通用的ioctl接口:snd_pcm_lib_write1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_writev_transfer)函数,其中snd_pcm_lib_writev_transfer是个函数指针。这个函数很关键,其中包括下面的代码:
static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, unsigned long data, snd_pcm_uframes_t size, int nonblock, transfer_f transfer){ struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t xfer = 0; snd_pcm_uframes_t offset = 0; int err = 0; if (size == 0) return 0; snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_RUNNING: case SNDRV_PCM_STATE_PAUSED: break; case SNDRV_PCM_STATE_XRUN: err = -EPIPE; goto _end_unlock; case SNDRV_PCM_STATE_SUSPENDED: err = -ESTRPIPE; goto _end_unlock; default: err = -EBADFD; goto _end_unlock; } while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; snd_pcm_uframes_t avail; snd_pcm_uframes_t cont; if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) snd_pcm_update_hw_ptr(substream); avail = snd_pcm_playback_avail(runtime); if (!avail) { if (nonblock) { err = -EAGAIN; goto _end_unlock; } err = wait_for_avail_min(substream, &avail); if (err < 0) goto _end_unlock; } frames = size > avail ? avail : size; cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; if (frames > cont) frames = cont; snd_assert(frames != 0, snd_pcm_stream_unlock_irq(substream); return -EINVAL); appl_ptr = runtime->control->appl_ptr; appl_ofs = appl_ptr % runtime->buffer_size; snd_pcm_stream_unlock_irq(substream); if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0) goto _end; snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_XRUN: err = -EPIPE; goto _end_unlock; case SNDRV_PCM_STATE_SUSPENDED: err = -ESTRPIPE; goto _end_unlock; default: break; } appl_ptr += frames; if (appl_ptr >= runtime->boundary) appl_ptr -= runtime->boundary; runtime->control->appl_ptr = appl_ptr; if (substream->ops->ack) substream->ops->ack(substream); offset += frames; size -= frames; xfer += frames; if (runtime->status->state == SNDRV_PCM_STATE_PREPARED && snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) { err = snd_pcm_start(substream); if (err < 0) goto _end_unlock; } } _end_unlock: snd_pcm_stream_unlock_irq(substream); _end: return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;}snd_pcm_playback_avail是个内敛函数,在include/sound/pcm.h中定义:/* * result is: 0 ... (boundary - 1) */static inline snd_pcm_uframes_t snd_pcm_playback_avail(struct snd_pcm_runtime *runtime){ snd_pcm_sframes_t avail = runtime->status->hw_ptr + runtime->buffer_size - runtime->control->appl_ptr; printk("runtime->status->hw_ptr:%lu runtime->buffer_size:%lu, runtime->control->appl_ptr:%lu runtime->boundary:%lu", runtime->status->hw_ptr, runtime->buffer_size, runtime->control->appl_ptr, runtime->boundary); if (avail < 0) avail += runtime->boundary; else if ((snd_pcm_uframes_t) avail >= runtime->boundary) avail -= runtime->boundary; return avail;}
上面的函数代码,可以帮助我们理解 alsa 中的数据结构成员所代表的含义。很显然,上面的函数的目的就是返回当前hardware buffer中用户程序可写的帧(frames)数。runtime->status-hw_ptr应该表示硬件指针,指向硬件已经处理(播放/录音)过的数据的位置,runtime->control->buffer_size是整个buffer的大小,而runtime->control->appl_ptr是用户程序已经处理(读/写)过的数据的位置。appl_ptr之后的空间,一直到buffer末尾,这一段是可以写入的(注意这个函数名中有playback,只用于播放),这一段长度为runtime->buffer_size - runtime->control->appl_ptr;另外hw_ptr之前的空间也是可写的(其中的数据已经被播放),所以整个可用的长度为 runtime->status->hw_ptr + runtime->buffer_size - runtime->control->appl_ptr。
阅读全文
0 0
- ALSADMA缓冲区分析
- 缓冲区溢出机理分析
- 缓冲区分析(1)
- 缓冲区分析(2)
- 缓冲区分析(3)
- 缓冲区溢出原理分析
- 串口缓冲区管理分析
- mySql的缓冲区分析
- 缓冲区溢出-shellcode分析
- supermap 缓冲区分析
- c printf 缓冲区分析
- 串口缓冲区管理分析
- 串口缓冲区管理分析
- 缓冲区溢出分析第01课:缓冲区溢出分析导论
- 缓冲区溢出分析第06课:W32Dasm缓冲区溢出分析
- ArcGIS Engine+C#缓冲区分析
- ArcGIS缓冲区分析小例子
- 设置缓冲区类型函数分析
- Servlet(3)—Servlet
- spring boot 发送邮件
- spring集成mybatis以及SQL语句的输出
- 数据库与网络请求相结合
- 图片轮播
- ALSADMA缓冲区分析
- IP首部校验和计算原理
- 为什么HTTP有时候比HTTPS要好?
- Wireshark常用过滤器
- 将博客搬至CSDN
- 发布-订阅模式
- golang 中bufio包的用法
- Android总结(1)---如何关闭多个Activity
- Hbase之Shell基本命令