1.USB-AUDIO的声卡注册过程

usb_probe_interface    ----  driver.cusb_audio_probe    ----  card.csnd_usb_create_stream    ----  card.csnd_usb_parse_audio_interface    ----  stream.csnd_usb_add_audio_stream    ----  stream.csnd_pcm_new    ----  pcm.c_snd_pcm_new    ----  pcm.cstatic struct snd_device_ops ops = {.dev_free = snd_pcm_dev_free,.dev_register =   snd_pcm_dev_register,.dev_disconnect = snd_pcm_dev_disconnect,};snd_pcm_new_stream(...,SNDRV_PCM_STREAM_PLAYBACK,...)    ----  pcm.csnd_pcm_new_stream(...,SNDRV_PCM_STREAM_CAPTURE,...)    ----  pcm.csnd_device_new    ----  pcm.c

struct snd_pcm {//是分别对应的2条音频流,一条是playback,一条是capturestruct snd_pcm_str streams[2];
};

_snd_pcm_new中有个函数需要特别关注如下:

snd_pcm_dev_register...for (cidx = 0; cidx < 2; cidx++) {...switch (cidx) {case SNDRV_PCM_STREAM_PLAYBACK:sprintf(str, "pcmC%iD%ip", pcm->card->number, pcm->device);devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;break;case SNDRV_PCM_STREAM_CAPTURE:sprintf(str, "pcmC%iD%ic", pcm->card->number, pcm->device);devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;break;}...snd_register_device_for_dev(devtype, pcm->card,pcm->device,&snd_pcm_f_ops[cidx],pcm, str, dev)...

如上是注册pcm设备的地方,同时我们需要关注pcm设备的ops,如下:

const struct file_operations snd_pcm_f_ops[2] = {{.owner =     THIS_MODULE,.write =       snd_pcm_write,.aio_write =     snd_pcm_aio_write,.open =          snd_pcm_playback_open,.release =       snd_pcm_release,.llseek =      no_llseek,.poll =          snd_pcm_playback_poll,.unlocked_ioctl =    snd_pcm_playback_ioctl,.compat_ioctl =     snd_pcm_ioctl_compat,.mmap =           snd_pcm_mmap,.fasync =     snd_pcm_fasync,.get_unmapped_area =    snd_pcm_get_unmapped_area,},{.owner =      THIS_MODULE,.read =            snd_pcm_read,.aio_read =       snd_pcm_aio_read,.open =           snd_pcm_capture_open,.release =        snd_pcm_release,.llseek =      no_llseek,.poll =          snd_pcm_capture_poll,.unlocked_ioctl = snd_pcm_capture_ioctl,.compat_ioctl =  snd_pcm_ioctl_compat,.mmap =           snd_pcm_mmap,.fasync =     snd_pcm_fasync,.get_unmapped_area =    snd_pcm_get_unmapped_area,}
};

之后pcm的录音和播放都会通过这个ops完成
2.使用tinycap的录音过程

external\tinyalsa\Tinycap.c

    main//先预先留出wav的头部fseek(file, sizeof(struct wav_header), SEEK_SET);frames = capture_sample(file, card, device, header.num_channels,header.sample_rate, format,period_size, period_count);//写入头部fseek(file, 0, SEEK_SET);fwrite(&header, sizeof(struct wav_header), 1, file);

一帧音频数据大小 = 通道数 * 采样深度

Period size:周期,每次硬件中断处理音频数据的帧数,对于音频设备的数据读写,以此为单位。

继续来看capture_sample

capture_sample打开声卡的音频设备"/dev/snd/pcmC1D0c","/dev/snd/pcmC1D0p",其中"c"对应capture,"p"对应的是playpcm_open(card, device, PCM_IN, &config);通过样本大小(4个硬件周期,每个周期处理1024帧数据)获取总字节数size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));为这次样本的采集准备空间buffer = malloc(size);通过pcm_read从内核中获取音频数据到buffer中,随后将这个buffer的内容写入到文件file中,持续的读取声卡中的音频,直到结束录音while (capturing && !pcm_read(pcm, buffer, size)) {if (fwrite(buffer, 1, size, file) != size) {fprintf(stderr,"Error capturing sample\n");break;}bytes_read += size;}录音结束,释放buffer,关闭pcm设备,返回当前读取到的音频帧数free(buffer);pcm_close(pcm);return pcm_bytes_to_frames(pcm, bytes_read);

随后进入到alsa的音频库(libtinyalsa.so)中

external\tinyalsa\Pcm.c

int pcm_read(struct pcm *pcm, void *data, unsigned int count)
{struct snd_xferi x;int len = 10;if (!(pcm->flags & PCM_IN))return -EINVAL;//x.buf指向的是内核返回的音频Buf数据x.buf = data;//x.frames 对应的是要收集满count个字节的音频数据,对应的声卡pcm设备需要采集的帧数x.frames = count / (pcm->config.channels *pcm_format_to_bits(pcm->config.format) / 8);for (;;) {if (!pcm->running) {if (pcm_start(pcm) < 0) {fprintf(stderr, "start error");return -errno;}}通过ioctl调度到到内核完成if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) {pcm->prepared = 0;pcm->running = 0;if (errno == EPIPE) {/* we failed to make our window -- try to restart */pcm->underruns++;continue;}return oops(pcm, errno, "cannot read stream data");}return 0;}
}

3.tinycap的录音过程进入内核

snd_pcm_capture_ioctlsnd_pcm_capture_ioctl1snd_pcm_lib_readsnd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer)

ok,我们看看snd_pcm_lib_read1这个函数

snd_pcm_lib_read1....//这里实现的是一个等待队列,等待usb收集到足够的音频数据后会返回avail的值wait_for_avail(substream, &avail);//调用transfer的函数指针callback到userspacetransfer(substream, appl_ofs, data, offset, frames);...

USB采集音频数据的大致流程如下:

最后回到transfer的函数指针实现

static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream, unsigned int hwoff,unsigned long data, unsigned int off,snd_pcm_uframes_t frames)
{struct snd_pcm_runtime *runtime = substream->runtime;int err;char __user *buf = (char __user *) data + frames_to_bytes(runtime, off);if (substream->ops->copy) {if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0)return err;} else {//走这儿,很简单,就是将dma采集到的buf传递到用户空间,完事char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames)))return -EFAULT;}return 0;
}

USB-AUDIO初步分析相关推荐

  1. Android USB AUDIO初步分析

    1.USB-AUDIO的声卡注册过程 usb_probe_interface ---- driver.cusb_audio_probe ---- card.csnd_usb_create_stream ...

  2. linux uac 设备,USB Audio Class (UAC) 分析

    一个UAC设备插入到Ubuntu 14.04电脑上dmesg中打印的信息如下: [ 2367.490491] usb 3-3.2: new full-speed USB device number 9 ...

  3. usb audio知识点

    已基本完成wavedev结构的usb音频驱动,现将开发心得及经验总结一下与大家分享/********************************************************** ...

  4. USB Audio Class (UAC)音频解读规范

    前言 USB 音频非常流行,原因之一是USB Audio 是USB 标准的一部分,因此原生模式驱动程序可用于所有流程的操作系统(Win Linux Mac).USB 音频是一种灵活的解决方案,因为任何 ...

  5. USB audio调试

    androidstudio打印的信息有如下: 07-12 08:27:17.660 2284-2284/? I/AudioFlinger: loadHwModule() Loaded a2dp aud ...

  6. usb audio设备驱动

    本文引用自ls.cq<usb audio设备驱动> http://bbs.driverdevelop.com/read.php?tid-118579-page-1.html 已基本完成wa ...

  7. USB总线-Linux内核USB3.0设备控制器复合设备之USB gadget configfs分析(七)

    1.简介 configfs是基于ram的文件系统,与sysfs的功能有所不同.sysfs是基于文件系统的kernel对象视图,虽然某些属性允许用户读写,但对象是在kernel中创建.注册.销毁,由ke ...

  8. Azure底层架构的初步分析

    之所以要写这样的一篇博文的目的是对于大多数搞IT的人来说,一般都会对这个topic很感兴趣,因为底层架构直接关乎到一个公有云平台的performance,其实最主要的原因是我们的客户对此也非常感兴趣, ...

  9. win8计算机usb无法识别usb设备,Win8.1无法识别USB设备原因分析及解决办法(适合Win8)...

    Win8.1无法识别USB设备原因分析及解决办法 同事孩子要上大学,购买了预装Win8.1系统的笔记本,想要使用读卡器传照片,插上USB读卡器后,任务栏右下角显示无法识别的USB设备,这怎么可能呢?W ...

  10. Linux USB驱动框架分析 【转】

    转自:http://blog.chinaunix.net/uid-11848011-id-96188.html 初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结 ...

最新文章

  1. Java字符串就该这样设计
  2. 混合云存储组合拳:基于云存储网关与混合云备份的OSS数据备份方案
  3. php exif信息,php通过exif_read_data函数获取图片的exif信息
  4. OpenCV简单的几何绘图的实例(附完整代码)
  5. CodeForces - 856B Similar Words(AC自动机+树形dp)
  6. 你懂change buffer吗
  7. mybatis学习(24):分页2 多参数传递(使用注解)
  8. XNA中的Render State管理
  9. JAVAWEB入门之Requset原理
  10. win7系统cocos2dx 3.4 绑定自定义类到Lua
  11. SQL Server 新增数据表数据
  12. 《大道至简第二章读后感》
  13. AS3多人游戏开发—同步人物移动2
  14. 计算机语言学翁富良,形式语言与自动机的关系
  15. 小样本(少样本)目标检测概述(few-shot object detection)
  16. Matlab论文插图绘制模板第60期—瀑布图(Waterfall)
  17. qlv转mp4格式工厂失败 解决方法
  18. 怎么看曲线有没有斜渐近线_怎样判断一个曲线有无斜渐近线
  19. 类和对象(Java)
  20. NX二次开发-UFUN自定义尺寸导出NX窗口区域图像UF_DISP_create_framed_image

热门文章

  1. (并查集)~APTX4869(fzu 2233)
  2. MyEclipse编码设置
  3. 软件工程之系统建模篇【设计接口类模型】
  4. 关于查看网页源文件不显示源代码(打开的是桌面文件夹)的问题
  5. 各种说明方法的答题格式_各种轴承安装方法说明及注意事项,避免这些坑提高轴承寿命...
  6. MYSQL 用户的操作
  7. 敏捷开发用户场景分析
  8. mySQL中replace的用法
  9. mysql做主从分离后插入更新过慢
  10. T-SQL连接查询,基础连接理解