云题海 - 专业文章范例文档资料分享平台

当前位置:首页 > alsa声卡dev_snd_pcmC0D0p的open打开流程

alsa声卡dev_snd_pcmC0D0p的open打开流程

  • 62 次阅读
  • 3 次下载
  • 2025/6/20 14:10:22

alsa声卡/dev/snd/pcmC0D0p的open打开流程

原文地址:http://blog.chinaunix.net/space.php?uid=20564848&do=blog&cuid=2116725 aplay.c ==> main

==> snd_pcm_open(&handle, pcm_name, stream, open_mode); // 打开一路pcm,刷新config配置 如果是\同时type等于SND_CONFIG_TYPE_COMPOUND那么这里对应\static const char *const build_in_pcms[] = {

\

\ \ NULL };

_snd_pcm_empty_open和snd_pcm_open_named_slave

==> snd_pcm_open_conf(pcmp, name, root, conf, stream, mode);

==> open_func = snd_dlobj_cache_lookup(open_name);将获得lib库中_snd_pcm_empty_open函数 所以open_func将等于_snd_pcm_empty_open

_snd_pcm_empty_open _snd_pcm_asym_open

_snd_pcm_plug_open _snd_pcm_softvol_open _snd_pcm_dmix_open _snd_pcm_hw_open

==> snd_pcm_hw_open(pcmp, name, card, device, subdevice, stream, mode | (nonblock ? SND_PCM_NONBLOCK : 0), 0, sync_ptr_ioctl);

==> snd_ctl_hw_open

filename等于\==> snd_open_device(filename, fmode); ctl->ops = &snd_ctl_hw_ops; ctl->private_data = hw; ctl->poll_fd = fd; *handle = ctl;

filename等于\

==> fd = snd_open_device(filename, fmode);

==> return snd_pcm_hw_open_fd(pcmp, name, fd, 0, sync_ptr_ioctl);

==> snd_pcm_new(&pcm, SND_PCM_TYPE_HW, name, info.stream, mode); pcm->ops = &snd_pcm_hw_ops;

pcm->fast_ops = &snd_pcm_hw_fast_ops;

static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm) {

snd_pcm_hw_t *hw = pcm->private_data; void *ptr; int err;

if (hw->sync_ptr == NULL) { // 如果还没有mmap,那么执行mmap映射内核空间驱动使用的声音缓冲区 ptr = mmap(NULL, page_align(sizeof(struct sndrv_pcm_mmap_control)), PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); if (ptr == MAP_FAILED || ptr == NULL) { err = -errno;

SYSMSG(\

return err; }

hw->mmap_control = ptr; // 声卡驱动头部填充了一个结构体sndrv_pcm_mmap_control,类似qvfb显示原理.

// struct sndrv_pcm_mmap_control {

// sndrv_pcm_uframes_t appl_ptr; /* RW: appl ptr (0...boundary-1) */

// sndrv_pcm_uframes_t avail_min; /* RW: min available frames for wakeup */ // };

} else {

hw->mmap_control->avail_min = 1; }

snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); return 0; }

snd_pcm_mmap

switch (i->type) {

case SND_PCM_AREA_MMAP: // 表示为数据区分配驱动内存,在snd_pcm_hw_channel_info中设置了type

ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, i->u.mmap.fd, i->u.mmap.offset); /*

mmap

==> snd_pcm_mmap_data ==> snd_pcm_default_mmap // mmap the DMA buffer on RAM

static int snd_pcm_default_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *area)

{

area->vm_ops = &snd_pcm_vm_ops_data; // vma操作函数,当应用程序向该area读写不存在的内存数据时,

area->vm_private_data = substream; // 将执行snd_pcm_vm_ops_data中的fault

// 函数snd_pcm_mmap_data_fault进一步以页为单位申请内存空间,所以如果用户程序需要64k,那么将执行16次,每次申请4k空间[luther.gliethttp]. area->vm_flags |= VM_RESERVED; atomic_inc(&substream->mmap_count); return 0; } */

if (ptr == MAP_FAILED) { SYSERR(\

return -errno; }

i->addr = ptr;

==> snd_pcm_mmap_control

static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area) {

struct snd_pcm_runtime *runtime; long size;

if (!(area->vm_flags & VM_READ)) return -EINVAL;

runtime = substream->runtime;

size = area->vm_end - area->vm_start;

if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control))) return -EINVAL;

area->vm_ops = &snd_pcm_vm_ops_control; // 当对( area->vm_start,area->vm_end)之间空间操作,发生

area->vm_private_data = substream; // 缺页时,内核将调用该vm_ops方法来处理fault异常, area->vm_flags |= VM_RESERVED; // 进而执行snd_pcm_mmap_control_fault申请1个page空间

return 0; }

==> writei_func = snd_pcm_writei; ==> playback(argv[optind++]);

==> playback_go(fd, dtawave, pbrec_count, FORMAT_WAVE, name);

==> pcm_write(audiobuf, l);

==> writei_func(handle, data, count);就是调用上面的snd_pcm_writei

==> snd_pcm_writei ==> _snd_pcm_writei

==> pcm->fast_ops->writei(pcm->fast_op_arg, buffer, size); ==> snd_pcm_plugin_writei

==> snd_pcm_write_areas(pcm, areas, 0, size, snd_pcm_plugin_write_areas);

==> avail = snd_pcm_avail_update(pcm); // 获取可用缓冲区位置偏移索引值

==> func()就是snd_pcm_plugin_write_areas函数发送1024帧音频数据,一帧对应一次完整采样,比如stereo立体声

,24bits量化,那么这里一帧对应3*2字节数据,即一次完整采样所需空间[luther.gliethttp]. ==> plugin->write(pcm, areas, offset, frames,

slave_areas, slave_offset, &slave_frames);

即调用snd_pcm_linear_write_areas函数将areas中的frames频数据拷贝到slave_areas内存区

==> pcm->fast_ops->mmap_commit(pcm->fast_op_arg, offset, frames); ==> snd_pcm_dmix_mmap_commit ==> snd_pcm_dmix_sync_area /*

* synchronize shm ring buffer with hardware */

static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm) ==> /* add sample areas here */

src_areas = snd_pcm_mmap_areas(pcm);

dst_areas = snd_pcm_mmap_areas(dmix->spcm); // 添加

==> mix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer); if (dmix->interleaved) { // 可以将缓冲中的音频数据填充到硬件中[luther.gliethttp] /*

* process all areas in one loop

* it optimizes the memory accesses for this case */

do_mix_areas(size * channels,

(unsigned char *)dst_areas[0].addr + sample_size * dst_ofs * channels, (unsigned char *)src_areas[0].addr + sample_size * src_ofs * channels, dmix->u.dmix.sum_buffer + dst_ofs * channels, sample_size, sample_size,

sizeof(signed int)); return; }

==> do_mix_areas(size * channels,

(unsigned char *)dst_areas[0].addr + sample_size * dst_ofs * channels,

搜索更多关于: alsa声卡dev_snd_pcmC0D0p的open打开流 的文档
  • 收藏
  • 违规举报
  • 版权认领
下载文档10.00 元 加入VIP免费下载
推荐下载
本文作者:...

共分享92篇相关文档

文档简介:

alsa声卡/dev/snd/pcmC0D0p的open打开流程 原文地址:http://blog.chinaunix.net/space.php?uid=20564848&do=blog&cuid=2116725 aplay.c ==> main ==> snd_pcm_open(&handle, pcm_name, stream, open_mode); // 打开一路pcm,刷新config配置 如果是\同时type等于SND_CONFIG_TYPE_COMPOUND那么这里对应\static const char *const build_in_pcms[] = { \ \ \ NULL }; _snd_pcm_empty_open和snd_pcm_open_n

× 游客快捷下载通道(下载后可以自由复制和排版)
单篇付费下载
限时特价:10 元/份 原价:20元
VIP包月下载
特价:29 元/月 原价:99元
低至 0.3 元/份 每月下载150
全站内容免费自由复制
VIP包月下载
特价:29 元/月 原价:99元
低至 0.3 元/份 每月下载150
全站内容免费自由复制
注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信:fanwen365 QQ:370150219
Copyright © 云题海 All Rights Reserved. 苏ICP备16052595号-3 网站地图 客服QQ:370150219 邮箱:370150219@qq.com