Linux下ALSA声卡编程

来源:互联网 发布:excel 去掉空格数据 编辑:程序博客网 时间:2024/05/16 17:32


Linux下ALSA声卡编程

时间:2010-07-19 23:00来源:CSDN博客作者:shenbin1430 点击: 1017次
ALSA 标准是一个先进的 linux 声音体系。它包含内核驱动集合, API 库和工具对 Linux 声音进行支持。 ALSA 包含一系列内核驱动对不同的声卡进行支持,还提供了 libasound 的 API 库。
TAG: 声卡  ALSA  声卡驱动  libasound  

一 . 介绍

ALSA 标准是一个先进的 linux 声音体系。它包含内核驱动集合, API 库和工具对 Linux 声音进行支持。 ALSA 包含一系列内核驱动对不同的声卡进行支持,还提供了 libasound 的 API 库。用这些进行写程序不需要打开设备等操作,所以编程人员在写程序的时候不会被底层的东西困扰。与此相反 OSS/Free 驱动在内核层次调用,需要指定设备名和调用 ioctl 。为提供向后兼容, ALSA 提供内核模块模仿 OSS/Free 驱动,所以大多数的程序不需要改动。 ALSA 拥有调用插件的能力对新设备提供扩展,包括那些用软件模拟出来的虚拟设备。 ALSA 还提供一组命令行工具包括   mixer, sound file player 和工具控制一些特别的声卡的特别的作用。

二 .ALSA 体系:

ALSA API 被主要分为以下几种接口:

  • 控制接口:提供灵活的方式管理注册的声卡和对存在的声卡进行查询。
  • PCM 接口:提供管理数字音频的捕捉和回放。
  • 原始 MIDI 接口 : 支持 MIDI (Musical Instrument Digital Interface), 一种标准电子音乐指令集。 这些 API 提供访问声卡上的 MIDI 总线。这些原始借口直接工作在 The  MIDI 事件上,程序员只需要管理协议和时间。
  • 记时接口 : 为支持声音的同步事件提供访问声卡上的定时器。
  • 音序器接口:一个比原始 MIDI 接口高级的 MIDI 编程和声音同步高层接口。它可以处理很多的 MIDI 协议和定时器。
  • 混音器接口:控制发送信号和控制声音大小的声卡上的设备。 

三 . 声卡的缓存和数据的传输:

      一块声卡有一个声卡内存用来存储记录的样本。当它被写满时就产生中断。内核驱动就使用 DMA 将数据传输到内存中。同样地,当在播放时就将内存中的声音样本使用 DMA 传到声卡的内存中!

      声卡的缓存是环状的,这里只讨论应用程序中的内存结构: ALSA 将数据分成连续的片段然后传到按单元片段传输。

 

四:典型的声音程序结构:

        open interface for capture or playback

        set hardware parameters

        (access mode, data format, channels, rate, etc.)

        while there is data to be processed:

        read PCM data (capture)

         or write PCM data (playback)

        close interface

 

五 . 一些例子:

1. 显示一些 PCM 的类型和格式 :

  1. #include <iostream> 
  2. #include <alsa/asoundlib.h> 
  3. int main() 
  4.        std::cout << "ALSA library version: " << SND_LIB_VERSION_STR << std::endl; 
  5.        std::cout << "PCM stream types: " << std::endl; 
  6.        for (int val=0; val <= SND_PCM_STREAM_LAST; ++val) 
  7.               std::cout << snd_pcm_stream_name((snd_pcm_stream_t)val) << std::endl; 
  8.        std::cout << std::endl; 
  9.        std::cout << "PCM access types: " << std::endl; 
  10.        for (int val=0; val <= SND_PCM_ACCESS_LAST; ++val) 
  11.               std::cout << snd_pcm_access_name((snd_pcm_access_t)val) << std::endl; 
  12.        std::cout << std::endl; 
  13.        std::cout << "PCM subformats: " << std::endl; 
  14.        for (int val=0; val <= SND_PCM_SUBFORMAT_LAST; ++val) 
  15.               std::cout << snd_pcm_subformat_name((snd_pcm_subformat_t)val) << " (" 
  16. << snd_pcm_subformat_description((snd_pcm_subformat_t)val) << ")" << std::endl; 
  17.        std::cout << std::endl; 
  18.        std::cout << "PCM states: " << std::endl; 
  19.        for (int val=0; val <= SND_PCM_STATE_LAST; ++val) 
  20.               std::cout << snd_pcm_state_name((snd_pcm_state_t)val) << std::endl; 
  21.        std::cout << std::endl; 
  22.        std::cout << "PCM formats: " << std::endl; 
  23.        for (int val=0; val <= SND_PCM_FORMAT_LAST; ++val) 
  24.               std::cout << snd_pcm_format_name((snd_pcm_format_t)val) << " (" 
  25. << snd_pcm_format_description((snd_pcm_format_t)val) << ")" << std::endl; 
  26.        std::cout << std::endl; 
  27. }

2. 打开 PCM 设备和设置参数

 

  1. #include <iostream> 
  2. #include <alsa/asoundlib.h> 
  3. int main() 
  4.        int                               rc; 
  5.        snd_pcm_t*                         handle; 
  6.        snd_pcm_hw_params_t*      params; 
  7.        unsigned int                  val, val2; 
  8.        int                               dir; 
  9.        snd_pcm_uframes_t             frames; 
  10.        if ( (rc = snd_pcm_open(&handle, "default",
  11.  SND_PCM_STREAM_PLAYBACK, 0)) < 0) 
  12.        { 
  13.               std::cerr << "unable to open pcm devices: " 
  14. << snd_strerror(rc) << std::endl; 
  15.               exit(1); 
  16.        } 
  17.        snd_pcm_hw_params_alloca(&params); 
  18.        snd_pcm_hw_params_any(handle, params); 
  19.        snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); 
  20.        snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); 
  21.        snd_pcm_hw_params_set_channels(handle, params, 2); 
  22.        val = 44100; 
  23.        snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); 
  24.        if ( (rc = snd_pcm_hw_params(handle, params)) < 0) 
  25.        { 
  26.               std::cerr << "unable to set hw parameters: " 
  27. << snd_strerror(rc) << std::endl; 
  28.               exit(1); 
  29.        } 
  30.       snd_pcm_hw_params_get_access(params, (snd_pcm_access_t *)&val); 
  31.       snd_pcm_hw_params_get_format(params, (snd_pcm_format_t*)(&val)); 
  32.       snd_pcm_hw_params_get_subformat(params, (snd_pcm_subformat_t *)&val); 
  33.       snd_pcm_hw_params_get_rate(params, &val, &dir); 
  34.       std::cout << "rate = " << val << " bps" << std::endl; 
  35.       snd_pcm_hw_params_get_period_time(params, &val, &dir); 
  36.       std::cout << "period time = " << val << " us" << std::endl; 
  37.       snd_pcm_hw_params_get_period_size(params, &frames, &dir); 
  38.       snd_pcm_hw_params_get_buffer_time(params, &val, &dir); 
  39.       std::cout << "buffer time = " << val << " us" << std::endl; 
  40.       snd_pcm_hw_params_get_buffer_size(params, (snd_pcm_uframes_t *) &val); 
  41.       std::cout << "buffer size = " << val << " frames" << std::endl; 
  42.       snd_pcm_hw_params_get_periods(params, &val, &dir); 
  43.       std::cout << "periods per buffer = " << val << " frames" << std::endl; 
  44.       snd_pcm_hw_params_get_rate_numden(params, &val, &val2); 
  45.       std::cout << "exact rate = " << val/val2 << " bps" << std::endl; 
  46.       val = snd_pcm_hw_params_get_sbits(params); 
  47.       std::cout << "significant bits = " << val << std::endl; 
  48.       snd_pcm_hw_params_get_tick_time(params, &val, &dir); 
  49.       std::cout << "tick time = " << val << " us" << std::endl; 
  50.       val = snd_pcm_hw_params_is_batch(params); 
  51.       std::cout << "is batch = " << val << std::endl; 
  52.       val = snd_pcm_hw_params_is_block_transfer(params); 
  53.       std::cout << "is block transfer = " << val << std::endl; 
  54.       val = snd_pcm_hw_params_is_double(params); 
  55.       std::cout << "is double = " << val << std::endl; 
  56.       val = snd_pcm_hw_params_is_half_duplex(params); 
  57.       std::cout << "is half duplex = " << val << std::endl; 
  58.       val = snd_pcm_hw_params_is_joint_duplex(params); 
  59.       std::cout << "is joint duplex = " << val << std::endl; 
  60.       val = snd_pcm_hw_params_can_overrange(params); 
  61.       std::cout << "can overrange = " << val << std::endl; 
  62.       val = snd_pcm_hw_params_can_mmap_sample_resolution(params); 
  63.       std::cout << "can mmap = " << val << std::endl; 
  64.       val = snd_pcm_hw_params_can_pause(params); 
  65.       std::cout << "can pause = " << val << std::endl; 
  66.       val = snd_pcm_hw_params_can_resume(params); 
  67.       std::cout << "can resume = " << val << std::endl; 
  68.       val = snd_pcm_hw_params_can_sync_start(params); 
  69.       std::cout << "can sync start = " << val << std::endl; 
  70.       snd_pcm_close(handle); 
  71.       return 0; 

3. 一个简单的声音播放程序

  1. #include <iostream> 
  2. #include <alsa/asoundlib.h> 
  3. int main() 
  4.        long                             loops; 
  5.        int                               rc; 
  6.        int                                       size; 
  7.        snd_pcm_t*                         handle; 
  8.        snd_pcm_hw_params_t*      params; 
  9.        unsigned int                  val; 
  10.        int                               dir; 
  11.        snd_pcm_uframes_t             frames; 
  12.        char*                                  buffer; 
  13.   
  14.        if ( (rc = snd_pcm_open(&handle, "default"
  15.  SND_PCM_STREAM_PLAYBACK, 0)) < 0) 
  16.        { 
  17.               std::cerr << "unable to open pcm device: " 
  18.  << snd_strerror(rc) << std::endl; 
  19.               exit(1); 
  20.        } 
  21.   
  22.        snd_pcm_hw_params_alloca(&params); 
  23.        snd_pcm_hw_params_any(handle, params); 
  24.        snd_pcm_hw_params_set_access(handle, params, 
  25.  SND_PCM_ACCESS_RW_INTERLEAVED); 
  26.        snd_pcm_hw_params_set_format(handle, params, 
  27.  SND_PCM_FORMAT_S16_LE); 
  28.        snd_pcm_hw_params_set_channels(handle, params, 2); 
  29.        val = 44100; 
  30.        snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); 
  31.        frames = 32; 
  32.        snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir); 
  33.        if ( (rc = snd_pcm_hw_params(handle, params)) < 0) 
  34.        { 
  35.               std::cerr << "unable to set hw paramseters: " 
  36.  << snd_strerror(rc) << std::endl; 
  37.               exit(1); 
  38.        } 
  39.        snd_pcm_hw_params_get_period_size(params, &frames, &dir); 
  40.        size = frames * 4; 
  41.        buffer = new char[size]; 
  42.        snd_pcm_hw_params_get_period_time(params, &val, &dir); 
  43.        loops = 5000000 / val; 
  44.        while (loops > 0) { 
  45.               loops--; 
  46.               if ( (rc = read(0, buffer, size)) == 0) 
  47.               { 
  48.                      std::cerr << "end of file on input" << std::endl; 
  49.                      break
  50.               } 
  51.               else if (rc != size) 
  52.                      std::cerr << "short read: read " 
  53.  << rc << " bytes" << std::endl; 
  54.               if ( (rc = snd_pcm_writei(handle, buffer, frames)) == -EPIPE) 
  55.               { 
  56.                      std::cerr << "underrun occurred" << std::endl; 
  57.                      snd_pcm_prepare(handle); 
  58.               } 
  59.               else if (rc < 0) 
  60.                      std::cerr << "error from writei: " 
  61.  << snd_strerror(rc) << std::endl; 
  62.               else if (rc != (int)frames) 
  63.                      std::cerr << "short write, write " 
  64.  << rc << " frames" << std::endl; 
  65.        } 
  66.        snd_pcm_drain(handle); 
  67.        snd_pcm_close(handle); 
  68.        free(buffer); 
  69.        return 0; 

4. 一个简单的记录声音的程序

  1. #include <iostream> 
  2. #include <alsa/asoundlib.h> 
  3. int main() 
  4.        long                             loops; 
  5.        int                                       rc; 
  6.        int                                       size; 
  7.        snd_pcm_t*                         handle; 
  8.        snd_pcm_hw_params_t*      params; 
  9.        unsigned int                  val; 
  10.        int                                       dir; 
  11.        snd_pcm_uframes_t             frames; 
  12.        char*                                  buffer; 
  13.   
  14.        if ( (rc = snd_pcm_open(&handle, "default",
  15.  SND_PCM_STREAM_CAPTURE, 0)) < 0) 
  16.        { 
  17.               std::cerr << "unable to open pcm device: "
  18.  << snd_strerror(rc) << std::endl; 
  19.               exit(1); 
  20.        } 
  21.  
  22.        snd_pcm_hw_params_alloca(&params); 
  23.        snd_pcm_hw_params_any(handle, params); 
  24.        snd_pcm_hw_params_set_access(handle, params,
  25.  SND_PCM_ACCESS_RW_INTERLEAVED); 
  26.        snd_pcm_hw_params_set_format(handle, params,
  27.  SND_PCM_FORMAT_S16_LE); 
  28.        snd_pcm_hw_params_set_channels(handle, params, 2); 
  29.        val = 44100; 
  30.        snd_pcm_hw_params_set_period_size_near(handle,
  31.  params, &frames, &dir); 
  32.        if ( (rc = snd_pcm_hw_params(handle, params)) < 0) 
  33.        { 
  34.               std::cerr << "unable to set hw parameters: "
  35.  << snd_strerror(rc) << std::endl; 
  36.               exit(1); 
  37.        } 
  38.        snd_pcm_hw_params_get_period_size(params, &frames, &dir); 
  39.        size = frames * 4; 
  40.        buffer = new char[size]; 
  41.        snd_pcm_hw_params_get_period_time(params, &val, &dir); 
  42.        loops = 5000000 / val; 
  43.        while (loops > 0) 
  44.        { 
  45.               loops --; 
  46.               rc = snd_pcm_readi(handle, buffer, frames); 
  47.               if (rc == -EPIPE) 
  48.               { 
  49.                      std::cerr << "overrun occurred" << std::endl; 
  50.                      snd_pcm_prepare(handle); 
  51.               } 
  52.               else if (rc < 0) 
  53.                      std::cerr << "error from read: "
  54.  << snd_strerror(rc) << std::endl; 
  55.               else if ( rc != (int)frames) 
  56.                      std::cerr << "short read, read "
  57.  << rc << " frames" << std::endl; 
  58.               rc = write(1, buffer, size); 
  59.               if (rc != size) 
  60.                      std::cerr << "short write: wrote "
  61.  << rc << " bytes" << std::endl; 
  62.        } 
  63.        snd_pcm_drain(handle); 
  64.        snd_pcm_close(handle); 
  65.        free(buffer); 
  66.        return 0; 

编译的参数: g++ xxx.cpp -o xxx -lasound

0 0
原创粉丝点击