USB-AUDIO初步分析
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初步分析相关推荐
- Android USB AUDIO初步分析
1.USB-AUDIO的声卡注册过程 usb_probe_interface ---- driver.cusb_audio_probe ---- card.csnd_usb_create_stream ...
- linux uac 设备,USB Audio Class (UAC) 分析
一个UAC设备插入到Ubuntu 14.04电脑上dmesg中打印的信息如下: [ 2367.490491] usb 3-3.2: new full-speed USB device number 9 ...
- usb audio知识点
已基本完成wavedev结构的usb音频驱动,现将开发心得及经验总结一下与大家分享/********************************************************** ...
- USB Audio Class (UAC)音频解读规范
前言 USB 音频非常流行,原因之一是USB Audio 是USB 标准的一部分,因此原生模式驱动程序可用于所有流程的操作系统(Win Linux Mac).USB 音频是一种灵活的解决方案,因为任何 ...
- USB audio调试
androidstudio打印的信息有如下: 07-12 08:27:17.660 2284-2284/? I/AudioFlinger: loadHwModule() Loaded a2dp aud ...
- usb audio设备驱动
本文引用自ls.cq<usb audio设备驱动> http://bbs.driverdevelop.com/read.php?tid-118579-page-1.html 已基本完成wa ...
- USB总线-Linux内核USB3.0设备控制器复合设备之USB gadget configfs分析(七)
1.简介 configfs是基于ram的文件系统,与sysfs的功能有所不同.sysfs是基于文件系统的kernel对象视图,虽然某些属性允许用户读写,但对象是在kernel中创建.注册.销毁,由ke ...
- Azure底层架构的初步分析
之所以要写这样的一篇博文的目的是对于大多数搞IT的人来说,一般都会对这个topic很感兴趣,因为底层架构直接关乎到一个公有云平台的performance,其实最主要的原因是我们的客户对此也非常感兴趣, ...
- win8计算机usb无法识别usb设备,Win8.1无法识别USB设备原因分析及解决办法(适合Win8)...
Win8.1无法识别USB设备原因分析及解决办法 同事孩子要上大学,购买了预装Win8.1系统的笔记本,想要使用读卡器传照片,插上USB读卡器后,任务栏右下角显示无法识别的USB设备,这怎么可能呢?W ...
- Linux USB驱动框架分析 【转】
转自:http://blog.chinaunix.net/uid-11848011-id-96188.html 初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结 ...
最新文章
- Java字符串就该这样设计
- 混合云存储组合拳:基于云存储网关与混合云备份的OSS数据备份方案
- php exif信息,php通过exif_read_data函数获取图片的exif信息
- OpenCV简单的几何绘图的实例(附完整代码)
- CodeForces - 856B Similar Words(AC自动机+树形dp)
- 你懂change buffer吗
- mybatis学习(24):分页2 多参数传递(使用注解)
- XNA中的Render State管理
- JAVAWEB入门之Requset原理
- win7系统cocos2dx 3.4 绑定自定义类到Lua
- SQL Server 新增数据表数据
- 《大道至简第二章读后感》
- AS3多人游戏开发—同步人物移动2
- 计算机语言学翁富良,形式语言与自动机的关系
- 小样本(少样本)目标检测概述(few-shot object detection)
- Matlab论文插图绘制模板第60期—瀑布图(Waterfall)
- qlv转mp4格式工厂失败 解决方法
- 怎么看曲线有没有斜渐近线_怎样判断一个曲线有无斜渐近线
- 类和对象(Java)
- NX二次开发-UFUN自定义尺寸导出NX窗口区域图像UF_DISP_create_framed_image