zoukankan      html  css  js  c++  java
  • Linux音频编程(二)声卡介绍

    一、声卡

    1、声卡audio interface,它含有hardware buffer,这个hardware buffer是在声卡里面,不是内存。声卡的缓存是环状的,ALSA中是将数据分成连续的片段然后传到按单元片段传输。

    2、当我们通过麦克风讲话的声音搜集到声卡里之后,内存从声卡设备文件中读取声音数据的过程就是录音过程把内存中的声音数据写入到声卡的设备文件中可以实现音频文件。

    3、我们在/dev/snd/目录下用ls命令就可以看到相关的声卡设备。

    4、模/数(ADC)转换器将模拟电压转换成离散的样本值。声音以固定的时间间隔被采样,采样的速率称为采样率。把样本输出到数/模(DAC)转换器,比如扩音器,最后转换成原来的模拟信号。

    二、相关设备文件介绍

    1、/dev/dsp

    用于数字采样(sampling)和数字录音(recording)的设备文件,向该设备写数据时使用声卡上的D/A转换器进行放音,而向该设备读数据时使用声卡上的A/D转换器进行录音。

    声卡使用DSP数字信号处理器来实现模拟信号和数字信号之间的转换(有D/AA/D转换。声卡中的DSP设备在以只读方式打开/dev/dsp时,使用A/D转换器变成数字采样的样本通过read系统调用从声卡读取数据进行声音的输入;以只写方式打开/dev/dsp时,数字信号经过D/A转换器变成模拟信号通过write进行声音的输出。以读写的方式打开 /dev/dsp同时进行声音的输入和输出

    2、/dev/sequencer合成器

    3、/dev/mixer混音器

    三、使用

    1、在打开声卡之后可通过ioctl函数来设置声卡参数,函数如下所示:

    int ioctl(int fd, int request, ...);  

    //参数fd是打开的文件的描述符,它是在设备打开时获得的;如果设备比较复杂,那么对它的控制请求相应地也会有很多种。

    //参数request是命令,它的目的就是用来区分不同的控制请求;通常说来,在对设备进行控制时还需要有其它参数,这要根据不同的控制请求才能确定,并且可能是与硬件设备直接相关的。

    //第三个参数是完成命令的操作需要的参数或返回的结果。它的意义取决于命令参数,可以是单个数,或是指向复杂的数据结构的指针。(由于ioctl函数面向所有设备文件,不同的设备又是千差万别,所以,第三个参数的意义、函数的返回值、错误代码等等都取决于command。并且,不同的设备,即使是相同的command也有不同的含义,需要的参数和返回值、错误代码等也不同。)

    //ioctl函数中相关的命令如下

    SOUND_PCM_WRITE_BITS:设置声卡的量化位数,8或者16,有些声卡不支持16位;

    SOUND_PCM_READ_BITS:获取当前声卡的量化位数;

    SOUND_PCM_WRITE_CHANNELS:设置声卡的声道数目,1或者2,1为单声道,2为立体声;

    SOUND_PCM_READ_CHANNELS:获取当前声卡的声道数;

    SOUND_PCM_WRITE_RATE:设置声卡的采样频率,8K,16K等等;

    SOUND_PCM_READ_RATE:获取声卡的采样频率

    1)声卡读取数据和向声卡写入数据时,具有特定的格式,默认为8位无符号数据、单声道、8KHz采样率,可通过ioctl系统调用来改变格式,可调节运行在Linux内核中的声卡驱动程序中缓冲区的大小,进而达到放音和录音想要的效果。例如:

    //缓冲区大小设置

    int setting = 0xnnnnssss;
    int result = ioctl(handle, SNDCTL_DSP_SETFRAGMENT, &setting);

    //参数setting实际上由两部分组成,其低16位标明缓冲区的尺寸,相应的计算公式为buffer_size = 2^ssss

    //若参数setting低16位的值为16,那么相应的缓冲区的大小会被设置为65536字节。参数setting的高16位则用来标明分片(fragment)的最大序号,它的取值范围从2一直到0x7FFF,其中0x7FFF表示没有任何限制。

    //设置声卡声道数目

    int channels = 0; //0=mono 1=stereo

    int result = ioctl(handle, SNDCTL_DSP_STEREO, &channels);

    //设置采样格式

    int format = AFMT_U8;

    int result = ioctl(handle, SNDCTL_DSP_SETFMT, &format);

    //设置采样频率

    int rate = 22050;
    int result = ioctl(handle, SNDCTL_DSP_SPEED, &rate);

    //调用ioctl时将第二个参数的值设置为SNDCTL_DSP_SPEED,同时在第三个参数中指定采样频率的数值。

    //在 Linux下进行音频编程时最常用到的几种采样频率是11025Hz、16000Hz、22050Hz、32000Hz和44100Hz。

    2直接使用系统调用控制声卡的是tinyalsa库,位于目录/external/tinyalsa下,编译生成库文件libtinyalsa.so(只涉及两个文件mixer.c,pcm.c),编译生成工具 tinycaptinymixtinypcminfotinyplay,可用于直接控制音频通道,进行录音播音测试。tinyalsa中使用
    pcm_open()来打开声卡
    pcm_write()来播放音乐
    pcm_read()来录音

     

    3config 的配置很重要,tinyalsa直接从wav文件把channels,rate,等读出来并配置进声卡

     //转换成config

       config.channels = channels;  //声道数目

        config.rate = rate;  //采样频率

        config.period_size = 1024; //周期

        config.period_count = 4;  //count

        if (bits == 32)

            config.format = PCM_FORMAT_S32_LE;  //

        else if (bits == 16)

        config.format = PCM_FORMAT_S16_LE;

        config.start_threshold = 0;

        config.stop_threshold = 0;

        config.silence_threshold = 0;

        //

    pcm = pcm_open(card, device, PCM_IN, &config);  

     if (!pcm || !pcm_is_ready(pcm)) {   

      printf("Unable to open PCM device (%s) ",pcm_get_error(pcm));      

      return 0;   

     }

    四、

    1spdif接口支持rawdatapcmdata模式。

    当音频channel设置成channels=4的时候,spdif会相应设置成rawdata模式。当音频channel设置成channels=2或者1的时候,spdif会设置成pcmdata模式。spdif是一个独立的音频驱动,接口支持alsalib中的标准接口。

    2Hdmiaudio支持rawdatapcmdata模式。

    当音频channel设置成channels=4的时候,hdmiaudio会相应设置成rawdata模式。当音频channel设置成channels=2或者1的时候,hdmiaudio会设置成pcmdata模式。Hdmiaudio是一个独立的音频驱动,接口支持alsalib中的标准接口。

  • 相关阅读:
    Android学习——体验活动的生命周期
    Android学习——活动的生存期
    《程序员修炼之道:从小工到专家》 阅读笔记01
    开课第七周周总结
    Android学习——活动状态
    Android学习——返回栈
    Android学习——Intent传递数据
    Android学习——隐式Activity的用法
    Android学习——隐式Activity
    Android学习——使用显示Intent
  • 原文地址:https://www.cnblogs.com/L-102/p/11488030.html
Copyright © 2011-2022 走看看