Linux下ALSA声卡编程

news/2024/7/18 21:26:35 标签: linux, access, buffer, loops, playback, stream

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

 

二.ALSA 体系:
ALSA API 被主要分为以下几种接口:

l         控制接口:提供灵活的方式管理注册的声卡和对存在的声卡进行查询。

l         PCM接口:提供管理数字音频的捕捉和回放。

l         原始 MIDI 接口: 支持 MIDI (Musical Instrument Digital Interface), 一种标准电子音乐指令集。 这些 API 提供访问声卡上的 MIDI 总线。这些原始借口直接工作在 The  MIDI 事件上,程序员只需要管理协议和时间。

l         记时接口: 为支持声音的同步事件提供访问声卡上的定时器。

l         音序器接口:一个比原始MIDI接口高级的MIDI编程和声音同步高层接口。它可以处理很多的MIDI协议和定时器。

l         混音器接口:控制发送信号和控制声音大小的声卡上的设备。

 

三.声卡的缓存和数据的传输:
      一块声卡有一个声卡内存用来存储记录的样本。当它被写满时就产生中断。内核驱动就使用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的类型和格式:
 

#include <iostream>

#include <alsa/asoundlib.h>

 

int main()

{

       std::cout << "ALSA library version: " << SND_LIB_VERSION_STR << std::endl;

 

       std::cout << "PCM stream types: " << std::endl;

 

       for (int val=0; val <= SND_PCM_STREAM_LAST; ++val)

              std::cout << snd_pcm_stream_name((snd_pcm_stream_t)val) << std::endl;

       std::cout << std::endl;

 

       std::cout << "PCM access types: " << std::endl;

       for (int val=0; val <= SND_PCM_ACCESS_LAST; ++val)

              std::cout << snd_pcm_access_name((snd_pcm_access_t)val) << std::endl;

       std::cout << std::endl;

 

       std::cout << "PCM subformats: " << std::endl;

       for (int val=0; val <= SND_PCM_SUBFORMAT_LAST; ++val)

              std::cout << snd_pcm_subformat_name((snd_pcm_subformat_t)val) << " (" << snd_pcm_subformat_description((snd_pcm_subformat_t)val) << ")" << std::endl;

       std::cout << std::endl;

 

       std::cout << "PCM states: " << std::endl;

       for (int val=0; val <= SND_PCM_STATE_LAST; ++val)

              std::cout << snd_pcm_state_name((snd_pcm_state_t)val) << std::endl;

       std::cout << std::endl;

 

 

       std::cout << "PCM formats: " << std::endl;

       for (int val=0; val <= SND_PCM_FORMAT_LAST; ++val)

              std::cout << snd_pcm_format_name((snd_pcm_format_t)val) << " (" << snd_pcm_format_description((snd_pcm_format_t)val) << ")" << std::endl;

       std::cout << std::endl;

      

}

 

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

#include <iostream>

#include <alsa/asoundlib.h>

 

int main()

{

       int                               rc;

       snd_pcm_t*                         handle;

       snd_pcm_hw_params_t*      params;

       unsigned int                  val, val2;

       int                               dir;

       snd_pcm_uframes_t             frames;

 

       if ( (rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0)

       {

              std::cerr << "unable to open pcm devices: " << snd_strerror(rc) << std::endl;

              exit(1);

       }

 

       snd_pcm_hw_params_alloca(&params);

 

       snd_pcm_hw_params_any(handle, params);

 

       snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);

 

       snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);

 

       snd_pcm_hw_params_set_channels(handle, params, 2);

 

       val = 44100;

 

       snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);

 

       if ( (rc = snd_pcm_hw_params(handle, params)) < 0)

       {

              std::cerr << "unable to set hw parameters: " << snd_strerror(rc) << std::endl;

              exit(1);

       }

 

       std::cout << "PCM handle name = " << snd_pcm_name(handle) << std::endl;

 

       std::cout << "PCM state = " << snd_pcm_state_name(snd_pcm_state(handle)) << std::endl;

 

       snd_pcm_hw_params_get_access(params, (snd_pcm_access_t *)&val);

 

       std::cout << "access type = " << snd_pcm_access_name((snd_pcm_access_t)val) << std::endl;

 

       snd_pcm_hw_params_get_format(params, (snd_pcm_format_t*)(&val));

      

       std::cout << "format = '" << snd_pcm_format_name((snd_pcm_format_t)val) << "' (" << snd_pcm_format_description((snd_pcm_format_t)val) << ")" << std::endl;

 

      snd_pcm_hw_params_get_subformat(params, (snd_pcm_subformat_t *)&val);

      std::cout << "subformat = '" <<

    snd_pcm_subformat_name((snd_pcm_subformat_t)val) << "' (" << snd_pcm_subformat_description((snd_pcm_subformat_t)val) << ")" << std::endl;

 

      snd_pcm_hw_params_get_channels(params, &val);

      std::cout << "channels = " << val << std::endl;

 

      snd_pcm_hw_params_get_rate(params, &val, &dir);

      std::cout << "rate = " << val << " bps" << std::endl;

 

       snd_pcm_hw_params_get_period_time(params, &val, &dir);

      std::cout << "period time = " << val << " us" << std::endl;

 

      snd_pcm_hw_params_get_period_size(params, &frames, &dir);

      std::cout << "period size = " << static_cast<int>(frames) << " frames" << std::endl;

 

       snd_pcm_hw_params_get_buffer_time(params, &val, &dir);

      std::cout << "buffer time = " << val << " us" << std::endl;

      

       snd_pcm_hw_params_get_buffer_size(params, (snd_pcm_uframes_t *) &val);

      std::cout << "buffer size = " << val << " frames" << std::endl;

 

      snd_pcm_hw_params_get_periods(params, &val, &dir);

      std::cout << "periods per buffer = " << val << " frames" << std::endl;

 

       snd_pcm_hw_params_get_rate_numden(params, &val, &val2);

      std::cout << "exact rate = " << val/val2 << " bps" << std::endl;

      

      val = snd_pcm_hw_params_get_sbits(params);

      std::cout << "significant bits = " << val << std::endl;

 

      snd_pcm_hw_params_get_tick_time(params, &val, &dir);

      std::cout << "tick time = " << val << " us" << std::endl;

 

      val = snd_pcm_hw_params_is_batch(params);

      std::cout << "is batch = " << val << std::endl;

 

      val = snd_pcm_hw_params_is_block_transfer(params);

      std::cout << "is block transfer = " << val << std::endl;

 

      val = snd_pcm_hw_params_is_double(params);

      std::cout << "is double = " << val << std::endl;

 

       val = snd_pcm_hw_params_is_half_duplex(params);

      std::cout << "is half duplex = " << val << std::endl;

 

       val = snd_pcm_hw_params_is_joint_duplex(params);

      std::cout << "is joint duplex = " << val << std::endl;

 

       val = snd_pcm_hw_params_can_overrange(params);

      std::cout << "can overrange = " << val << std::endl;

 

      val = snd_pcm_hw_params_can_mmap_sample_resolution(params);

      std::cout << "can mmap = " << val << std::endl;

 

      val = snd_pcm_hw_params_can_pause(params);

      std::cout << "can pause = " << val << std::endl;

 

       val = snd_pcm_hw_params_can_resume(params);

      std::cout << "can resume = " << val << std::endl;

 

      val = snd_pcm_hw_params_can_sync_start(params);

      std::cout << "can sync start = " << val << std::endl;

 

      snd_pcm_close(handle);

 

      return 0;

}

 

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

#include <iostream>

#include <alsa/asoundlib.h>

 

int main()

{

       long                             loops;

       int                               rc;

       int                                       size;

       snd_pcm_t*                         handle;

       snd_pcm_hw_params_t*      params;

       unsigned int                  val;

       int                               dir;

       snd_pcm_uframes_t             frames;

       char*                                  buffer;

 

       if ( (rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0)

       {

              std::cerr << "unable to open pcm device: " << snd_strerror(rc) << std::endl;

              exit(1);

       }

 

       snd_pcm_hw_params_alloca(&params);

 

       snd_pcm_hw_params_any(handle, params);

 

       snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);

 

       snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);

 

       snd_pcm_hw_params_set_channels(handle, params, 2);

 

       val = 44100;

 

       snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);

 

       frames = 32;

       snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);

 

       if ( (rc = snd_pcm_hw_params(handle, params)) < 0)

       {

              std::cerr << "unable to set hw paramseters: " << snd_strerror(rc) << std::endl;

              exit(1);

       }

 

       snd_pcm_hw_params_get_period_size(params, &frames, &dir);

       size = frames * 4;

       buffer = new char[size];

 

       snd_pcm_hw_params_get_period_time(params, &val, &dir);

 

       loops = 5000000 / val;

 

       while (loops > 0) {

              loops--;

              if ( (rc = read(0, buffer, size)) == 0)

              {

                     std::cerr << "end of file on input" << std::endl;

                     break;

              }

              else if (rc != size)

                     std::cerr << "short read: read " << rc << " bytes" << std::endl;

 

              if ( (rc = snd_pcm_writei(handle, buffer, frames)) == -EPIPE)

              {

                     std::cerr << "underrun occurred" << std::endl;

                     snd_pcm_prepare(handle);

              }

              else if (rc < 0)

                     std::cerr << "error from writei: " << snd_strerror(rc) << std::endl;

              else if (rc != (int)frames)

                     std::cerr << "short write, write " << rc << " frames" << std::endl;

       }

 

       snd_pcm_drain(handle);

       snd_pcm_close(handle);

       free(buffer);

 

       return 0;

}

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

#include <iostream>

#include <alsa/asoundlib.h>

 

int main()

{

       long                             loops;

       int                                       rc;

       int                                       size;

       snd_pcm_t*                         handle;

       snd_pcm_hw_params_t*      params;

       unsigned int                  val;

       int                                       dir;

       snd_pcm_uframes_t             frames;

       char*                                  buffer;

 

       if ( (rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0)) < 0)

       {

              std::cerr << "unable to open pcm device: " << snd_strerror(rc) << std::endl;

              exit(1);

       }

 

       snd_pcm_hw_params_alloca(&params);

 

       snd_pcm_hw_params_any(handle, params);

 

       snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);

 

       snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);

 

       snd_pcm_hw_params_set_channels(handle, params, 2);

 

       val = 44100;

       snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);

 

       if ( (rc = snd_pcm_hw_params(handle, params)) < 0)

       {

              std::cerr << "unable to set hw parameters: " << snd_strerror(rc) << std::endl;

              exit(1);

       }

 

       snd_pcm_hw_params_get_period_size(params, &frames, &dir);

 

       size = frames * 4;

       buffer = new char[size];

 

       snd_pcm_hw_params_get_period_time(params, &val, &dir);

 

       loops = 5000000 / val;

 

       while (loops > 0)

       {

              loops --;

              rc = snd_pcm_readi(handle, buffer, frames);

              if (rc == -EPIPE)

              {

                     std::cerr << "overrun occurred" << std::endl;

                     snd_pcm_prepare(handle);

              }

              else if (rc < 0)

                     std::cerr << "error from read: " << snd_strerror(rc) << std::endl;

              else if ( rc != (int)frames)

                     std::cerr << "short read, read " << rc << " frames" << std::endl;

              rc = write(1, buffer, size);

              if (rc != size)

                     std::cerr << "short write: wrote " << rc << " bytes" << std::endl;

       }

 

       snd_pcm_drain(handle);

       snd_pcm_close(handle);

       free(buffer);

      

       return 0;

}

 

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

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ruancsdn/archive/2004/10/14/135911.aspx


http://www.niftyadmin.cn/n/1713856.html

相关文章

Linux下声卡驱动软件ALSA的安装与配置

几年以来&#xff0c;尽管Linux凭借开放、自由的特性和强大的性能&#xff0c;在全球服务器市场上所向披靡&#xff0c;占据越来越多的市场份额&#xff0c;但是若作为桌面软件&#xff0c;Linux的多媒体特性一直不能让人非常满意。比如&#xff0c;Linux系统自带的声卡驱动程序…

别让妈妈生气——浅谈长者用户

放假回家难得清闲&#xff0c;奇怪还不到一周就坐不住了&#xff0c;左顾右盼百无聊赖&#xff0c;心里痒滋滋的——原来是网瘾犯了——为了说服父母同意牵网&#xff0c;我承诺他们&#xff0c;保证他们学会上网&#xff01; 我的计划是&#xff1a;一周之内&#xff0c;教会妈…

linux下的共享库和静态库

&#xff08;1&#xff09;linux下文件的类型是不依赖于其后缀名的&#xff0c;但一般来讲&#xff1a;  .o,是目标文件。 .so 为共享库,是shared object,用于动态连接的。 .a为静态库,是好多个.o合在一起,用于静态连接。 &#xff08;2&#xff09;静态库的生成和使用 概述静…

gcc生成静态库和动态库

gcc生成静态库和动态库 一、库文件简介 简单地说&#xff0c;库&#xff08;Library&#xff09;就是一组已经写好了的函数和变量、经过编译代码&#xff0c;是为了能够提高开发效率和运行效率而设计的。库分为静态库&#xff08;Static Library&#xff09;和共享库&#xf…

alsa 音频库的移植

alsa 是在LINUX出现比较晚的音频处理库,主要是针对原有的OSS的库进行改进.性能更好,支持多个播放源等.但相应的,增加的编程的复杂性. 旧的oss是采用标准文件IO接口,设备打开采用open,声音播录是采用数据IO接口(read/write),设备的参数采用ioctl来控制.都是 系统调用因此无需额…

【Spark】RDD转换算子

目录 map mapPartitions mapPartitionsWithIndex flatMap glom groupBy shuffle filter sample distinct coalesce repartition sortBy ByKey intersection union subtract zip partitionBy reduceByKey groupByKey reduceByKey 和 groupByKey 的区别 a…

ALSA架构简介

ALSA &#xff08;Advanced Linux Sound Architecture&#xff08;高级Linux声音体系&#xff09;的缩写&#xff09; 是为声卡提供驱动的Linux内核组件&#xff0c;以替代原先的OSS&#xff08;开放声音系统&#xff09;。ALSA除了像OSS那样提供一组内核驱动程序模块以外&…

在Linux中安装ALSA声卡驱动

刚装好了显卡这回轮到安声卡了&#xff0c;安装声卡比安装显卡简单多&#xff0c;主要原因网上的资料比较全自然省心不少 。好了言归正转。    1.下载驱动    你可以到这里下载ALSA的驱动&#xff1a;    你需要下载以下几个包&#xff1a;  alsa-driver-1.0.10.…