转自: http://blog.csdn.net/safrans/article/details/6190803
本文通过对A Tutorial on Using the ALSA Audio API 这篇文章的翻译,代码注释,API整理,使读者能够对ALSA Audio API的使用有一个基本的了解,在以下的阶段里我将对ALSA编程做一个更加深入的研究。博客中的代码部分显示不怎么整齐,大家可以去我的百度文库下载,地址如下所示:http://wenku.baidu.com/view/5eff4987bceb19e8b8f6ba2e.html
This document attempts to provide an introduction to the ALSA Audio API. It is not a complete reference manual for the API, and it does not cover many specific issues that more complex software will need to address. However, it does try to provide enough background and information for a reasonably skilled programmer but who is new to ALSA to write a simple program that uses the API.
All code in the document is licensed under the GNU Public License. If you plan to write software using ALSA under some other license, then I suggest you find some other documentation.
Contents
Understanding Audio Interface
What a Typical Audio Application Does
A Minimal Playback Program
A Minimal Capture Program
A Minimal interrupt-driven Program
A Minimal Duplex Program
How To Do It
Opening The Device
Setting The Parameters
Receiving And Delivering Data
Why You Might Want To Forget About All Of This
Understanding Audio Interfaces
Let us first review the basic design of an audio interface. As an application developer, you don’t need to worry about this level of operation - its all taken care of by the device driver (which is one of the components that ALSA provides). But you do need to understand what is going at a conceptual level if you want to write efficient and flexible software.
An audio interface is a device that allows a computer to receive and to send audio data from/to the outside world. Inside of the computer, audio data is represented a stream of bits, just like any other kind of data. However, the audio interface may send and receive audio as either an analog signal (a time-varying voltage) or as a digital signal (some stream of bits). In either case, the set of bits that the computer uses to represent a particular sound will need to be transformed before it is delivered to the outside world, and likewise, the external signal received by the interface will need to be transformed before it is useful to the computer. These two transformations are the raison d’etre of the audio interface.
Within the audio interface is an area referred to as the “hardware buffer”. As an audio signal arrives from the outside world, the interface converts it into a stream of bits usable by the computer and stores it in the part hardware buffer used to send data to the computer. When it has collected enough data in the hardware buffer, the interface interrupts the computer to tell it that it has data ready for it. A similar process happens in reverse for data being sent from the computer to the outside world. The interface interrupts the computer to tell it that there is space in the hardware buffer, and the computer proceeds to store data there. The interface later converts these bits into whatever form is needed to deliver it to the outside world, and delivers it. It is very important to understand that the interface uses this buffer as a “circular buffer”. When it gets to the end of the buffer, it continues by wrapping around to the start.
For this process to work correctly, there are a number of variables that need to be configured. They include:
what format should the interface use when converting between the bitstream used by the computer and the signal used in the outside world?
at what rate should samples be moved between the interface and the computer?
how much data (and/or space) should there be before the device interrupts the computer?
how big should the hardware buffer be?
The first two questions are fundamental in governing the quality of the audio data. The second two questions affect the “latency” of the audio signal. This term refers to the delay between
data arriving at the audio interface from the outside world, and it being available to the computer ("input latency")
data being delivered by the computer, and it being delivered to the outside world ("output latency")
Both of these are very important for many kinds of audio software, though some programs do not need be concerned with such matters.
What a typical audio application does
A typical audio application has this rough structure:
[c-sharp] view plaincopyprint?
open_the_device();
set_the_parameters_of_the_device();
while (!done) {
/* one or both of these */
receive_audio_data_from_the_device();
deliver_audio_data_to_the_device();
}
close the device
A Minimal Playback Program
This program opens an audio interface for playback, configures it for stereo, 16 bit, 44.1kHz, interleaved conventional read/write access. Then its delivers a chunk of random data to it, and exits. It represents about the simplest possible use of the ALSA Audio API, and isn’t meant to be a real program.
[c-sharp] view plaincopyprint?
#include
#include
#include
main (int argc, char *argv[])
{
int i;
int err;
short buf[128];
snd_pcm_t *playback_handle;
snd_pcm_hw_params_t *hw_params;
if ((err = snd_pcm_open (&playback_handle, argv[1], SND_PCM_STREAM_PLAYBACK, 0)) < 0)
{
fprintf (stderr, "cannot open audio device %s (%s)/n", argv[1],snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0)
{
fprintf (stderr, "cannot allocate hardware parameter structure (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_any (playback_handle, hw_params)) < 0)
{
fprintf (stderr, "cannot initialize hardware parameter structure (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_access (playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
{
fprintf (stderr, "cannot set access type (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_format (playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0)
{
fprintf (stderr, "cannot set sample format (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_rate_near (playback_handle, hw_params, 44100, 0)) < 0)
{
fprintf (stderr, "cannot set sample rate (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_channels (playback_handle, hw_params, 2)) < 0)
{
fprintf (stderr, "cannot set channel count (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params (playback_handle, hw_params)) < 0)
{
fprintf (stderr, "cannot set parameters (%s)/n",snd_strerror (err));
exit (1);
}
snd_pcm_hw_params_free (hw_params);
if ((err = snd_pcm_prepare (playback_handle)) < 0)
{
fprintf (stderr, "cannot prepare audio interface for use (%s)/n",snd_strerror (err));
exit (1);
}
for (i = 0; i < 10; ++i)
{
if ((err = snd_pcm_writei (playback_handle, buf, 128)) != 128)
{
fprintf (stderr, "write to audio interface failed (%s)/n",snd_strerror (err));
exit (1);
}
}
snd_pcm_close (playback_handle);
exit (0);
}
A Minimal Capture Program
This program opens an audio interface for capture, configures it for stereo, 16 bit, 44.1kHz, interleaved conventional read/write access. Then its reads a chunk of random data from it, and exits. It isn’t meant to be a real program.
[cpp] view plaincopyprint?
#include
#include
#include
main (int argc, char *argv[])
{
int i;
int err;
short buf[128];
snd_pcm_t *playback_handle;
snd_pcm_hw_params_t *hw_params;
if ((err = snd_pcm_open (&playback_handle, argv[1], SND_PCM_STREAM_PLAYBACK, 0)) < 0)
{
fprintf (stderr, "cannot open audio device %s (%s)/n", argv[1],snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0)
{
fprintf (stderr, "cannot allocate hardware parameter structure (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_any (playback_handle, hw_params)) < 0)
{
fprintf (stderr, "cannot initialize hardware parameter structure (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_access (playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
{
fprintf (stderr, "cannot set access type (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_format (playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0)
{
fprintf (stderr, "cannot set sample format (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_rate_near (playback_handle, hw_params, 44100, 0)) < 0)
{
fprintf (stderr, "cannot set sample rate (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_channels (playback_handle, hw_params, 2)) < 0)
{
fprintf (stderr, "cannot set channel count (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params (playback_handle, hw_params)) < 0)
{
fprintf (stderr, "cannot set parameters (%s)/n",snd_strerror (err));
exit (1);
}
snd_pcm_hw_params_free (hw_params);
if ((err = snd_pcm_prepare (playback_handle)) < 0)
{
fprintf (stderr, "cannot prepare audio interface for use (%s)/n",snd_strerror (err));
exit (1);
}
for (i = 0; i < 10; ++i)
{
if ((err = snd_pcm_writei (playback_handle, buf, 128)) != 128)
{
fprintf (stderr, "write to audio interface failed (%s)/n",snd_strerror (err));
exit (1);
}
}
snd_pcm_close (playback_handle);
exit (0);
}
A Minimal Interrupt-Driven Program
This program opens an audio interface for playback, configures it for stereo, 16 bit, 44.1kHz, interleaved conventional read/write access. It then waits till the interface is ready for playback data, and delivers random data to it at that time. This design allows your program to be easily ported to systems that rely on a callback-driven mechanism, such as JACK, LADSPA, CoreAudio, VST and many others.
[c-sharp] view plaincopyprint?
#include
#include
#include
#include
#include
snd_pcm_t *playback_handle;
short buf[4096];
int playback_callback (snd_pcm_sframes_t nframes)
{
int err;
printf ("playback callback called with %u frames/n", nframes);
/* ... fill buf with data ... */
if ((err = snd_pcm_writei (playback_handle, buf, nframes)) < 0)
{
printf (stderr, "write failed (%s)/n", snd_strerror (err));
}
return err;
}
main (int argc, char *argv[])
{
snd_pcm_hw_params_t *hw_params;
snd_pcm_sw_params_t *sw_params;
snd_pcm_sframes_t frames_to_deliver;
int nfds;
int err;
struct pollfd *pfds;
if ((err = snd_pcm_open (&playback_handle, argv[1], SND_PCM_STREAM_PLAYBACK, 0)) < 0)
{
fprintf (stderr, "cannot open audio device %s (%s)/n", argv[1],snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0)
{
fprintf (stderr, "cannot allocate hardware parameter structure (%s)/n", snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_any (playback_handle, hw_params)) < 0)
{
fprintf (stderr, "cannot initialize hardware parameter structure (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_access (playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
{
fprintf (stderr, "cannot set access type (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_format (playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0)
{
fprintf (stderr, "cannot set sample format (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_rate_near (playback_handle, hw_params, 44100, 0)) < 0)
{
fprintf (stderr, "cannot set sample rate (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_channels (playback_handle, hw_params, 2)) < 0)
{
fprintf (stderr, "cannot set channel count (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params (playback_handle, hw_params)) < 0)
{
fprintf (stderr, "cannot set parameters (%s)/n",snd_strerror (err));
exit (1);
}
snd_pcm_hw_params_free (hw_params);
/* tell ALSA to wake us up whenever 4096 or more frames
of playback data can be delivered. Also, tell
ALSA that we'll start the device ourselves.
*/
if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0)
{
fprintf (stderr, "cannot allocate software parameters structure (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_sw_params_current (playback_handle, sw_params)) < 0)
{
fprintf (stderr, "cannot initialize software parameters structure (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_sw_params_set_avail_min (playback_handle, sw_params, 4096)) < 0)
{
fprintf (stderr, "cannot set minimum available count (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_sw_params_set_start_threshold (playback_handle, sw_params, 0U)) < 0)
{
fprintf (stderr, "cannot set start mode (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_sw_params (playback_handle, sw_params)) < 0)
{
fprintf (stderr, "cannot set software parameters (%s)/n",snd_strerror (err));
exit (1);
}
/* the interface will interrupt the kernel every 4096 frames, and ALSA
will wake up this program very soon after that.
*/
if ((err = snd_pcm_prepare (playback_handle)) < 0)
{
fprintf (stderr, "cannot prepare audio interface for use (%s)/n",snd_strerror (err));
exit (1);
}
while (1)
{
/* wait till the interface is ready for data, or 1 second
has elapsed.
*/
if ((err = snd_pcm_wait (playback_handle, 1000)) < 0)
{
fprintf (stderr, "poll failed (%s)/n", strerror (errno));
break;
}
/* find out how much space is available for playback data */
if ((frames_to_deliver = snd_pcm_avail_update (playback_handle)) < 0)
{
if (frames_to_deliver == -EPIPE)
{
fprintf (stderr, "an xrun occured/n");
break;
}
else {
fprintf (stderr, "unknown ALSA avail update return value (%d)/n", frames_to_deliver);
break;
}
}
frames_to_deliver = frames_to_deliver > 4096 ? 4096 : frames_to_deliver;
/* deliver the data */
if (playback_callback (frames_to_deliver) != frames_to_deliver)
{
fprintf (stderr, "playback callback failed/n");
break;
}
}
snd_pcm_close (playback_handle);
exit (0);
}
A Minimal Full-Duplex Program
Full duplex can be implemented by combining the playback and capture designs show above. Although many existing Linux audio applications use this kind of design, in this author’s opinion, it is deeply flawed. The the interrupt-driven example represents a fundamentally better design for many situations. It is, however, rather complex to extend to full duplex. This is why I suggest you forget about all of this.
Terminology
capture
Receiving data from the outside world (different from “recording” which implies storing that data somewhere, and is not part of ALSA’s API)
playback
Delivering data to the outside world, presumably, though not necessarily, so that it can be heard.
duplex
A situation where capture and playback are occuring on the same interface at the same time.
xrun
Once the audio interface starts running, it continues to do until told to stop. It will be generating data for computer to use and/or sending data from the computer to the outside world. For various reasons, your program may not keep up with it. For playback, this can lead to a situation where the interface needs new data from the computer, but it isn’t there, forcing it use old data left in the hardware buffer. This is called an “underrun”. For capture, the interface may have data to deliver to the computer, but nowhere to store it, so it has to overwrite part of the hardware buffer that contains data the computer has not received. This is called an “overrun”. For simplicity, we use the generic term “xrun” to refer to either of these conditions
PCM
Pulse Code Modulation. This phrase (and acronym) describes one method of representing an analog signal in digital form. Its the method used by almost computer audio interfaces, and it is used in the ALSA API as a shorthand for “audio”.
channel
frame
A sample is a single value that describes the amplitude of the audio signal at a single point in time, on a single channel. When we talk about working with digital audio, we often want to talk about the data that represents all channels at a single point in time. This is a collection of samples, one per channel, and is generally called a “frame”. When we talk about the passage of time in terms of frames, its roughly equivalent to what people when they measure in terms of samples, but is more accurate; more importantly, when we’re talking about the amount of data needed to represent all the channels at a point in time, its the only unit that makes sense. Almost every ALSA Audio API function uses frames as its unit of measurement for data quantities.
interleaved
a data layout arrangement where the samples of each channel that will be played at the same time follow each other sequentially. See “non-interleaved”
non-interleaved
a data layout where the samples for a single channel follow each other sequentially; samples for another channel are either in another buffer or another part of this buffer. Contrast with “interleaved”
sample clock
a timing source that is used to mark the times at which a sample should be delivered and/or received to/from the outside world. Some audio interfaces allow you to use an external sample clock, either a “word clock” signal (typically used in many studios), or “autosync” which uses a clock signal present in incoming digital data. All audio interfaces have at least one sample clock source that is present on the interface itself, typically a small crystal clock. Some interfaces do not allow the rate of the clock to be varied, and some have clocks that do not actually run at precisely the rates you would expect (44.1kHz, etc). No two sample clocks can ever be expected to run at precisely the same rate - if you need two sample streams to remain synchronized with each other, they MUST be run from the same sample clock.
How to do it …
Opening the device
ALSA separates capture and playback ….
Setting parameters
We mentioned above that there are number of parameters that need to be set in order for an audio interface to do its job. However, because your program will not actually be interacting with the hardware directly, but instead with a device driver that controls the hardware, there are really two distinct sets of parameters:
Hardware Parameters
These are parameters that directly affect the hardware of the audio interface.
Sample rate
This controls the rate at which either A/D/D/A conversion is done, if the interface has analog I/O. For fully digital interfaces, it controls the speed of the clock used to move digital audio data to/from the outside world. On some interfaces, other device-specific configuration may mean that your program cannot control this value (for example, when the interface has been told to use an external word clock source to determine the sample rate).
Sample format
This controls the sample format used to transfer data to and from the interface. It may or may not correspond with a format directly supported by the hardware.
Number of channels
Hopefully, this is fairly self-explanatory.
Data access and layout
This controls the way that the program will deliver/receive data from the interface. There are two parameters controlled by 4 possible settings. One parameter is whether or not a “read/write” model will be used, in which explicit function calls are used to transfer data. The other option here is to use “mmap mode” in which data is transferred by copying between areas of memory, and API calls are only necessary to note when it has started and finished.
The other parameter is whether the data layout will be interleaved or non-interleaved.
Interrupt interval
This determines how many interrupts the interface will generate per complete traversal of its hardware buffer. It can be set either by specifying a number of periods, of the size of a period. Since this determines the number of frames of space/data that have to accumulate before the interface will interrupt the computer. It is central in controlling latency.
Buffer size
This determines how large the hardware buffer is. It can be specified in units of time or frames.
Software Parameters
These are parameters that control the operation of the device driver rather than the hardware itself. Most programs that use the ALSA Audio API will not need to set any of these; a few will need set a subset of them.
When to start the device
When you open the audio interface, ALSA ensures that it is not active - no data is being moved to or from its external connectors. Presumably, at some point you want this data transfer to begin. There are several options for how to make this happen.
The control point here the start threshold, which defines the number of frames of space/data necessary to start the device automatically. If set to some value other than zero for playback, it is necessary to prefill the playback buffer before the device will start. If set to zero, the first data written to the device (or first attempt to read from a capture stream) will start the device.
You can also start the device explicitly using snd_pcm_start, but this requires buffer prefilling in the case of the playback stream. If you attempt to start the stream without doing this, you will get -EPIPE as a return code, indicating that there is no data waiting to deliver to the playback hardware buffer.
What to do about xruns
If an xrun occurs, the device driver may, if requested, take certain steps to handle it. Options include stopping the device, or silencing all or part of the hardware buffer used for playback.
the stop threshold
if the number of frames of data/space available meets or exceeds this value, the driver will stop the interface.
the silence threshold
if the number of frames of space available for a playback stream meets or exceeds this value, the driver will fill part of the playback hardware buffer with silence.
silence size
when the silence threshold level is met, this determines how many frames of silence are written into the playback hardware buffer
Available minimum space/data for wakeup
Programs that use poll(2) or select(2) to determine when audio data may be transferred to/from the interface may set this to control at what point relative to the state of the hardware buffer, they wish to be woken up.
Transfer chunk size
this determines the number of frames used when transferring data to/from the device hardware buffer.
There are a couple of other software parameters but they need not concern us here.
Receiving and delivering data
NOT YET WRITTEN
ALSA Audio API 使用指南
此文档旨在提供一个对ALSA Audio API的介绍。它并非是一个API的完全参考手册,它也没有涉及许多特定的方面,很多复杂的软件会涉及那些特定的方面。然而它试着给一位合理的熟练的程序员提供足够多的相关知识和信息,而并非给那些使用API来编写简单程序的不熟悉ALSA的新手。
文档中所有的代码都遵循GNU Public License。如果你试图在其它的准则下使用ALSA来编写程序,那么我将建议你寻找其他的文档。
内容介绍
理解音频接口
一个典型的音频应用程序
一个最简单的回放程序
一个最简单的捕获数据程序
一个最简单的驱动中断程序
一个最简单的全双工程序
如何使用API
打开设备
设置参数
接收和传输数据
为何你会要去忘记这里所讲述的
理解音频接口
我们先来了解下音频接口的基本设计。对于一位应用程序开发者,你不需要担心硬件水平如何操作,它们全部由设备驱动来搞定(这些驱动是由ALSA来提供的一些组件)。但是,如果你想写出高效和简洁的软件你必须要对它们有个概念上的了解。
音频接口是一种设备,该设备可以让电脑对外接收和向外发送音频数据。在电脑那一端,音频数据用一串比特流来表示,就像其它种类的数据一样。虽然如此,音频接口发送和接收音频数据即可以用模拟信号(时刻变化的电压)也可以用数字信号(一些比特流)。无论用什么来接收发送数据,电脑用来表示一段音频的比特流在往外传输前都要被转化为模拟信号;同样的,被声卡接收的外部信号在被电脑使用前也需要被转化为数字信号。这两方面的转化也是音频接口的用途所在。【注:raison d’etre为法语,意为:存在的目的或理由】
声卡内部有一个硬件缓存区域。当声卡接收到外界声音信号时,通过计算机它将信号转化为可用的比特流并存储在用来发送数据给计算机的硬件缓存中。当缓存存储了足够多的数据时,声卡中断计算机告知它数据已经准备好了。一个相似的过程将会发生在将数据从计算机传送到外界时。此过程中声卡中断计算机并通知它缓存有空间,计算机将会往里面存储数据。声卡接着将那些数据转化成所要求的任何格式并将其传送到外界,并且传输。有一点是十分重要的,那就是声卡循环使用这块缓存。也就是说,当到了缓存的末端时,会将开始的数据擦除用来存数据。
为了保证这个过程的正确执行,有一些变量需要设置。它们包括:
。当在计算机使用的比特流和外界使用的模拟信号之间转化时声卡要用什么样的格式?
。声卡的采样率是多少?
。当有多少数据时声卡才中断计算机?
。硬件缓存要设置为多大?
头两个问题是控制音频数据质量的基础。后两个问题影响着音频信号的延迟。这个术语涉及到以下两个方面的延迟
数据从外界到达声卡与转化成计算机中可用的数据之间的延迟(称为:内部延迟)
数据被计算机传输,并传输到外界的延迟(称为:外部延迟)
虽然一些程序不需要关心这两方面的东西,但对很多音频相关软件它们都十分重要。
一个典型的音频应用程序
下面是一个典型的音频应用程序的大致结构:
[c-sharp] view plaincopyprint?
open_the_device();
set_the_parameters_of_the_device();
while (!done) {
/* one or both of these */
receive_audio_data_from_the_device();
deliver_audio_data_to_the_device();
}
close the device
一个最简单的回放程序
下面这段程序开启声卡回放,设置成双声道,16bit(采样位数),44.1KHZ,交叉存储,常规的读写(不用mmap)。然后传送一些随即的数据给声卡,退出。它也许反映了最简单的ALSA Audio API的用法,但它并不是一个真正可运行的程序。
[c-sharp] view plaincopyprint?
#include
#include
#include
main (int argc, char *argv[])
{
int i;
int err;
short buf[128];
snd_pcm_t *playback_handle;
snd_pcm_hw_params_t *hw_params; //定义硬件参数变量
if ((err = snd_pcm_open (&playback_handle, argv[1], SND_PCM_STREAM_PLAYBACK, 0)) < 0)
// snd_pcm_open是Alsa库提供的打开设备调用函数
{
fprintf (stderr, "cannot open audio device %s (%s)/n", argv[1],snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) //为硬件参数变量分配空间
{
fprintf (stderr, "cannot allocate hardware parameter structure (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_any (playback_handle, hw_params)) < 0) //硬件参数初始化
{
fprintf (stderr, "cannot initialize hardware parameter structure (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_access (playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) //硬件设置为交错模式
{
fprintf (stderr, "cannot set access type (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_format (playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) //硬件设置16bit(采样位数)
{
fprintf (stderr, "cannot set sample format (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_rate_near (playback_handle, hw_params, 44100, 0)) < 0)
//硬件设置采样率为44.1KHz
{
fprintf (stderr, "cannot set sample rate (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_channels (playback_handle, hw_params, 2)) < 0)
//硬件设置为立体声双通道
{
fprintf (stderr, "cannot set channel count (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params (playback_handle, hw_params)) < 0) //硬件设置参数
{
fprintf (stderr, "cannot set parameters (%s)/n",snd_strerror (err));
exit (1);
}
snd_pcm_hw_params_free (hw_params); //释放硬件参数变量空间
if ((err = snd_pcm_prepare (playback_handle)) < 0) //准备PCM以备使用
{
fprintf (stderr, "cannot prepare audio interface for use (%s)/n",snd_strerror (err));
exit (1);
}
for (i = 0; i < 10; ++i)
{
if ((err = snd_pcm_writei (playback_handle, buf, 128)) != 128) //将帧写入PCM
{
fprintf (stderr, "write to audio interface failed (%s)/n",snd_strerror (err));
exit (1);
}
}
snd_pcm_close (playback_handle); //关闭PCM
exit (0);
}
一个最简单的捕获数据程序
这段程序打开声卡捕获数据,设置为双声道,16bit,44.1KHZ,交叉存储,常规的读写。然后读一些数据,退出。它并非实际运行程序。
[c-sharp] view plaincopyprint?
#include
#include
#include
main (int argc, char *argv[])
{
int i;
int err;
short buf[128];
snd_pcm_t *capture_handle;
snd_pcm_hw_params_t *hw_params; //硬件定义参数变量
if ((err = snd_pcm_open (&capture_handle, argv[1], SND_PCM_STREAM_CAPTURE, 0)) < 0)
// snd_pcm_open是Alsa库提供的打开设备调用函数
{
fprintf (stderr, "cannot open audio device %s (%s)/n",
argv[1],
snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) //为硬件参数变量分配空间
{
fprintf (stderr, "cannot allocate hardware parameter structure (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_any (capture_handle, hw_params)) < 0) //硬件参数初始化
{
fprintf (stderr, "cannot initialize hardware parameter structure (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_access (capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) //硬件设置为交错模式
{
fprintf (stderr, "cannot set access type (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_format (capture_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) //硬件设置16bit(采样位数)
{
fprintf (stderr, "cannot set sample format (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_rate_near (capture_handle, hw_params, 44100, 0)) < 0)
//硬件设置采样率为44.1KHz
{
fprintf (stderr, "cannot set sample rate (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_channels (capture_handle, hw_params, 2)) < 0) //硬件设置为立体声双通道
{
printf (stderr, "cannot set channel count (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params (capture_handle, hw_params)) < 0) //硬件设置参数
{
fprintf (stderr, "cannot set parameters (%s)/n",snd_strerror (err));
exit (1);
}
snd_pcm_hw_params_free (hw_params); //释放硬件参数变量空间
if ((err = snd_pcm_prepare (capture_handle)) < 0) //准备PCM以备使用
{
fprintf (stderr, "cannot prepare audio interface for use (%s)/n",snd_strerror (err));
exit (1);
}
for (i = 0; i < 10; ++i)
{
if ((err = snd_pcm_readi (capture_handle, buf, 128)) != 128) //从PCM读帧
{
fprintf (stderr, "read from audio interface failed (%s)/n",snd_strerror (err));
exit (1);
}
}
snd_pcm_close (capture_handle); //关闭PCM
exit (0);
}
一个最简单的驱动中断程序
这段程序打开声卡回放,配置成双声道,16bit,44.1KHZ,交叉存储,常规读写。它将等待声卡直到声卡准备好回放数据,同时传输一些数据给它。这种设计可以使你的程序很容易的通过一种回调驱动机制来和系统绑定,这样的软件比如:JACK,LADSPA,CoreAudio,VST等。
[c-sharp] view plaincopyprint?
#include
#include
#include
#include
#include
snd_pcm_t *playback_handle;
short buf[4096];
int playback_callback (snd_pcm_sframes_t nframes)
{
int err;
printf ("playback callback called with %u frames/n", nframes);
/* ... fill buf with data ... */
if ((err = snd_pcm_writei (playback_handle, buf, nframes)) < 0)
{
printf (stderr, "write failed (%s)/n", snd_strerror (err));
}
return err;
}
main (int argc, char *argv[])
{
snd_pcm_hw_params_t *hw_params; //定义硬件参数变量
snd_pcm_sw_params_t *sw_params;
snd_pcm_sframes_t frames_to_deliver;
int nfds;
int err;
struct pollfd *pfds;
if ((err = snd_pcm_open (&playback_handle, argv[1], SND_PCM_STREAM_PLAYBACK, 0)) < 0)
// snd_pcm_open是Alsa库提供的打开设备调用函数
{
fprintf (stderr, "cannot open audio device %s (%s)/n", argv[1],snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) //为硬件参数变量分配空间
{
fprintf (stderr, "cannot allocate hardware parameter structure (%s)/n", snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_any (playback_handle, hw_params)) < 0) //硬件参数初始化
{
fprintf (stderr, "cannot initialize hardware parameter structure (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_access (playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) //硬件设置为交错模式
{
fprintf (stderr, "cannot set access type (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_format (playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) //硬件设置16bit(采样位数)
{
fprintf (stderr, "cannot set sample format (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_rate_near (playback_handle, hw_params, 44100, 0)) < 0)
//硬件设置采样率为44.1KHz
{
fprintf (stderr, "cannot set sample rate (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_channels (playback_handle, hw_params, 2)) < 0)
//硬件设置为立体声双通道
{
fprintf (stderr, "cannot set channel count (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params (playback_handle, hw_params)) < 0) //硬件设置参数
{
fprintf (stderr, "cannot set parameters (%s)/n",snd_strerror (err));
exit (1);
}
snd_pcm_hw_params_free (hw_params); //释放硬件参数变量空间
/* tell ALSA to wake us up whenever 4096 or more frames
of playback data can be delivered. Also, tell
ALSA that we'll start the device ourselves.
*/
if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) //为软件参数变量分配空间
{
fprintf (stderr, "cannot allocate software parameters structure (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_sw_params_current (playback_handle, sw_params)) < 0) //取得目前的软件参数配置
{
fprintf (stderr, "cannot initialize software parameters structure (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_sw_params_set_avail_min (playback_handle, sw_params, 4096)) < 0)
{
fprintf (stderr, "cannot set minimum available count (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_sw_params_set_start_threshold (playback_handle, sw_params, 0U)) < 0)
{
fprintf (stderr, "cannot set start mode (%s)/n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_sw_params (playback_handle, sw_params)) < 0)
{
fprintf (stderr, "cannot set software parameters (%s)/n",snd_strerror (err));
exit (1);
}
/* the interface will interrupt the kernel every 4096 frames, and ALSA
will wake up this program very soon after that.
*/
if ((err = snd_pcm_prepare (playback_handle)) < 0)
{
fprintf (stderr, "cannot prepare audio interface for use (%s)/n",snd_strerror (err));
exit (1);
}
while (1)
{
/* wait till the interface is ready for data, or 1 second
has elapsed.
*/
if ((err = snd_pcm_wait (playback_handle, 1000)) < 0)
{
fprintf (stderr, "poll failed (%s)/n", strerror (errno));
break;
}
/* find out how much space is available for playback data */
if ((frames_to_deliver = snd_pcm_avail_update (playback_handle)) < 0)
{
if (frames_to_deliver == -EPIPE)
{
fprintf (stderr, "an xrun occured/n");
break;
}
else {
fprintf (stderr, "unknown ALSA avail update return value (%d)/n", frames_to_deliver);
break;
}
}
frames_to_deliver = frames_to_deliver > 4096 ? 4096 : frames_to_deliver;
/* deliver the data */
if (playback_callback (frames_to_deliver) != frames_to_deliver)
{
fprintf (stderr, "playback callback failed/n");
break;
}
}
snd_pcm_close (playback_handle);
exit (0);
}
一个最简单的全双工程序
全双工可以通过上面提到的回放和捕获设计来合并实现。虽然很多现有的音频程序使用了这种设计,但这篇文章中认为这是有很大缺陷的。上面的中断驱动样例在多数情况下是一个很基本也很好的设计模式。然而,它在扩展成全双工时也是十分复杂的。这正是我为何要建议你忘记我前面所说的。
名词术语:
Capture
从外界获取音频数据(和“录音”不同,录音意味着将数据存储起来,它并不是ALSA库的API)。
Playback
将音频播放出来,使能被听见,这也许并不是必须的。
Duplex
捕获和回放在同一声卡同一时刻同时发生的情况
Xrun
一旦声卡开始运行,便一直持续直到被要求停止。它将收集数据给计算机使用并且(或者)发送计算机中的数据给外界。但有很多种情况你的程序并非可以控制声卡正常的进行。在回放的时候,当声卡需要从计算机中收到数据时,而此时并没有,xrun便可以强迫它使用在硬件缓存中留有的旧数据。这种情况叫做“下溢”。在捕获的时候,声卡也许要传送数据给计算机,但此时计算机没有空间来存储,因此,声卡会重写部分硬件缓存中没有及时送出的数据。这种情况叫做“上溢”。简单的说,我们用词“xrun”来概括其中的一个或几个。
Pcm
Pulse Code Modulation(脉冲编码调制)。这个词(还有缩写)描述了一种用数字化形式表示模拟信号的方法。这种方法几乎被所有的计算机音卡所使用,它在ALSA API中用“audio”来简称。
Channel
Frame
一个采样是描述某一时刻的单通道下一个信号点的声音信号的振幅的信号值。当我们谈及数字音频时,我们经常谈到的是代表所有通道的一个信号点的数据。它是单个通道采样的一个集合,叫做”帧”。当我们依据帧来表示一段时间时,它粗略的等于人们用一组采样来衡量,但前者更精确;更重要的是,当我们在讨论代表一个时刻所有通道的数据量时,帧是唯一能引起人们感官感受的标准。几乎所有的ALSA Audio API使用帧作为衡量音频质量的标准。
Interleaved
一种将同一时刻所有通道音频数据依次存取的交叉存储形式。参看:不交叉存储。
Non-interleaved
一种将每个通道的数据按顺序存储的存储形式,不同的通道的数据存储在另一个缓存中或者同一个缓存的其他地方。和交叉存储对比。
Sample clock
时钟源,用来决定采样的传送,接收时刻。一些音卡允许你使用外部时钟,比如“全球时钟信号”(经常在一些工作室中使用),还有使用来自数字数据的时钟信号的 “自动同步信号”。所有的声卡内部都必须至少有一个采样时钟源,典型的是一种小的晶体时钟。一些声卡不允许改变时钟频率,一些则有不是很精准的时钟(比如,44.1khz)。没有两个时钟能够以同一个时钟频率运行,如果你需要两个采样时钟进行同步,他们必须要和同一个采样时钟进行同步。
如何使用API
1.打开设备
ALSA将捕获和回放的用API分开……
2.设置参数
上面提到了要使声卡工作需要设置很多的参数。然而,由于你的程序将不会实际的直接的去和硬件打交道,所以我们使用了两个不同的设置参数的方式来替带用设备驱动来控制硬件:
硬件参数
下面的参数可以直接影响声卡的硬件
采样率
如果声卡有模拟i/o的情况下,当声卡准备好了A/D或D/A转换时,这个可以控制声卡的速率。对于全数字的声卡,它控制用于移动数字数据进出外部的时钟的速度。在一些声卡中,其它的硬件指定设置也许意味着你的程序不能控制这个值(比如,当声卡用一个外部时钟源来决定采样率时)。
采样格式
这个控制了用于从声卡传输数据的采样格式。它也许和硬件直接支持的格式不符。
通道数
这个完全可以自定义。
数据接入和布局
数据接入控制了程序从声卡接收传送数据的方式。有两个参数来设置4种情况。一个参数是是否使用“读写”模块,该模块中有相应的用于传输数据的函数调用。另一个选项是用“映射模式”,该模式通过拷贝内存区域的数据来传输数据,这个API仅仅需要在开始和结束的时候注明一下即可。
数据布局是指数据的存储是交叉存储还是非交叉存储。
中断间隔
这个决定了读或写完整个硬件缓存需要发生多少次中断。它能根据一些指定的时间段来设置,也可以根据一段时间的长短来设置。设置决定了在声卡向计算机发出中断之前积累的空间中或数据中的帧数。它控制着延迟。
缓存大小
这决定了硬件缓存的大小。它可以用时间长短或帧数来指定。
软件参数
这些参数控制着硬件驱动的操作而不是硬件本身。很多使用ALSA Audio API的程序什么参数都不需要设置,一些只需要设置其中的一部分。
什么时候打开设备
当你打开声卡设备的时候,ALSA确认它并没有在被使用——没有数据正在传输。假如,此时,你想要开始数据传输,有几个选项需要设置。
此处的控制关键是开端,开端定义了自动开启设备所需要达到的空间/数据包含的帧数。如果为回放设置了一个非0值,那在设备开始运作之前就要先填充硬件缓存。如果设置成0,那么最开始写入数据给设备(或者试图开始捕获流数据)将会开启设备。
你可以用snd_pcm_start来明确的打开设备,但如果是回放的话要求缓存中预先填充数据。如果你没有预填数据而想开始回放,函数则会返回-EPIPE,表明现在没有数据在向硬件缓存中传。
Xruns有什么作用
如果xrun发生了,如果被请求了,设备将通过几个步骤来处理它。选项包括停止设备,用于回放的硬件缓存的全部或部分静音。
停止极限
如果可用的数据/空间的帧数达到或超过了这个值,设备将停止声卡。
静音极限
如果用于回放流的可用的空间帧数达到或超过了这个值,设备将往硬件缓存中填充静音数据。
静音大小
当静音极限到达时,这个值决定了往硬件缓存中写入多少静音数据。
唤醒所需的最小可用空间/数据。
使用poll(2)或者select(2)来控制音频数据的传输的程序可以设置这个值来控制在什么时候唤醒程序,这些时候与硬件缓存的状态相关。
传输块大小
这个决定了传入/出数据给硬件缓存时所用的帧数。
还有一些其他的软件参数此处没有提及。
3.接收和传输数据
没有写
程序中用到的API
[c-sharp] view plaincopyprint?
int snd_pcm_open ( snd_pcm_t **
pcmp,
const char * name,
snd_pcm_stream_t
Stream,
int mode
)
Opens a PCM.
Parameters:
pcmp Returned PCM handle
name ASCII identifier of the PCM handle
stream Wanted stream
mode Open mode (see SND_PCM_NONBLOCK, SND_PCM_ASYNC)
Returns:
0 on success otherwise a negative error code
Examples:
/test/latency.c, /test/pcm.c, and /test/pcm_min.c.
int snd_pcm_hw_params_any ( snd_pcm_t *
pcm,
snd_pcm_hw_params_t *
params
)
Fill params with a full configuration space for a PCM.
Parameters:
pcm PCM handle
params Configuration space
Examples:
/test/latency.c, and /test/pcm.c.
int snd_pcm_hw_params_malloc ( snd_pcm_hw_params_t **
ptr )
allocate an invalid snd_pcm_hw_params_t using standard malloc
Parameters:
ptr returned pointer
Returns:
0 on success otherwise negative error code
int snd_pcm_hw_params_set_access ( snd_pcm_t *
pcm,
snd_pcm_hw_params_t *
params,
snd_pcm_access_t
access
)
Restrict a configuration space to contain only one access type.
Parameters:
pcm PCM handle
params Configuration space
access access type
Returns:
0 otherwise a negative error code if configuration space would become empty
Examples:
/test/latency.c, and /test/pcm.c.
int snd_pcm_hw_params_set_format ( snd_pcm_t *
pcm,
snd_pcm_hw_params_t *
params,
snd_pcm_format_t
format
)
Restrict a configuration space to contain only one format.
Parameters:
pcm PCM handle
params Configuration space
format format
Returns:
0 otherwise a negative error code
Examples:
/test/latency.c, and /test/pcm.c.
int snd_pcm_hw_params_set_rate_near ( snd_pcm_t *
pcm,
snd_pcm_hw_params_t *
params,
unsigned int * val,
int * dir
)
Restrict a configuration space to have rate nearest to a target.
Parameters:
pcm PCM handle
params Configuration space
val approximate target rate / returned approximate set rate
dir Sub unit direction
Returns:
0 otherwise a negative error code if configuration space is empty
target/chosen exact value is <,=,> val following dir (-1,0,1)
Examples:
/test/latency.c, and /test/pcm.c.
int snd_pcm_hw_params_set_channels ( snd_pcm_t *
pcm,
snd_pcm_hw_params_t *
params,
unsigned int val
)
Restrict a configuration space to contain only one channels count.
Parameters:
pcm PCM handle
params Configuration space
val channels count
Returns:
0 otherwise a negative error code if configuration space would become empty
Examples:
/test/latency.c, and /test/pcm.c.
int snd_pcm_hw_params ( snd_pcm_t *
pcm,
snd_pcm_hw_params_t *
params
)
Install one PCM hardware configuration chosen from a configuration space and snd_pcm_prepare it.
Parameters:
pcm PCM handle
params Configuration space definition container
Returns:
0 on success otherwise a negative error code
The configuration is chosen fixing single parameters in this order: first access, first format, first subformat, min channels, min rate, min period time, max buffer size, min tick time
After this call, snd_pcm_prepare() is called automatically and the stream is brought to SND_PCM_STATE_PREPARED state.
The hardware parameters cannot be changed when the stream is running (active). The software parameters can be changed at any time.
Examples:
/test/latency.c, and /test/pcm.c.
void snd_pcm_hw_params_free ( snd_pcm_hw_params_t *
obj )
frees a previously allocated snd_pcm_hw_params_t
Parameters:
obj pointer to object to free
int snd_pcm_prepare ( snd_pcm_t *
pcm )
Prepare PCM for use.
Parameters:
pcm PCM handle
Returns:
0 on success otherwise a negative error code
Examples:
/test/latency.c, and /test/pcm.c.
snd_pcm_sframes_t snd_pcm_writei
( snd_pcm_t *
pcm,
const void * buffer,
snd_pcm_uframes_t
size
)
Write interleaved frames to a PCM.
Parameters:
pcm PCM handle
buffer frames containing buffer
size frames to be written
Returns:
a positive number of frames actually written otherwise a negative error code
Return values:
-EBADFD PCM is not in the right state (SND_PCM_STATE_PREPARED or SND_PCM_STATE_RUNNING)
-EPIPE an underrun occurred
-ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery)
If the blocking behaviour is selected and it is running, then routine waits until all requested frames are played or put to the playback ring buffer. The returned number of frames can be less only if a signal or underrun occurred.
If the non-blocking behaviour is selected, then routine doesn't wait at all.
Examples:
/test/latency.c, /test/pcm.c, and /test/pcm_min.c.
int snd_pcm_close ( snd_pcm_t *
pcm )
close PCM handle
Parameters:
pcm PCM handle
Returns:
0 on success otherwise a negative error code
Closes the specified PCM handle and frees all associated resources.
Examples:
/test/latency.c, /test/pcm.c, and /test/pcm_min.c.
snd_pcm_sframes_t snd_pcm_readi
( snd_pcm_t *
pcm,
void * Buffer,
snd_pcm_uframes_t
size
)
Read interleaved frames from a PCM.
Parameters:
pcm PCM handle
buffer frames containing buffer
size frames to be read
Returns:
a positive number of frames actually read otherwise a negative error code
Return values:
-EBADFD PCM is not in the right state (SND_PCM_STATE_PREPARED or SND_PCM_STATE_RUNNING)
-EPIPE an overrun occurred
-ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery)
If the blocking behaviour was selected and it is running, then routine waits until all requested frames are filled. The returned number of frames can be less only if a signal or underrun occurred.
If the non-blocking behaviour is selected, then routine doesn't wait at all.
Examples:
/test/latency.c.
int snd_pcm_wait ( snd_pcm_t *
pcm,
int timeout
)
Wait for a PCM to become ready.
Parameters:
pcm PCM handle
timeout maximum time in milliseconds to wait, a negative value means infinity
Returns:
a positive value on success otherwise a negative error code (-EPIPE for the xrun and -ESTRPIPE for the suspended status, others for general errors)
Return values:
0 timeout occurred
1 PCM stream is ready for I/O
Examples:
/test/latency.c, and /test/pcm.c.
int snd_pcm_sw_params_current ( snd_pcm_t *
pcm,
snd_pcm_sw_params_t *
params ,
)
Return current software configuration for a PCM.
Parameters:
pcm PCM handle
params Software configuration container
Returns:
0 on success otherwise a negative error code
Examples:
/test/latency.c, and /test/pcm.c.
int snd_pcm_sw_params_set_avail_min ( snd_pcm_t *
pcm,
snd_pcm_sw_params_t *
Params,
snd_pcm_uframes_t
Val,
)
Set avail min inside a software configuration container.
Parameters:
pcm PCM handle
params Software configuration container
val Minimum avail frames to consider PCM ready
Returns:
0 otherwise a negative error code
Note: This is similar to setting an OSS wakeup point. The valid values for 'val' are determined by the specific hardware. Most PC sound cards can only accept power of 2 frame counts (i.e. 512, 1024, 2048). You cannot use this as a high resolution timer - it is limited to how often the sound card hardware raises an interrupt.
Examples:
/test/latency.c, and /test/pcm.c.
int snd_pcm_sw_params_set_start_threshold ( snd_pcm_t *
pcm,
snd_pcm_sw_params_t *
params,
snd_pcm_uframes_t
val
)
Set start threshold inside a software configuration container.
Parameters:
pcm PCM handle
params Software configuration container
val Start threshold in frames
Returns:
0 otherwise a negative error code
PCM is automatically started when playback frames available to PCM are >= threshold or when requested capture frames are >= threshold
Examples:
/test/latency.c, and /test/pcm.c.
int snd_pcm_sw_params ( snd_pcm_t *
pcm,
snd_pcm_sw_params_t *
params
)
Install PCM software configuration defined by params.
Parameters:
pcm PCM handle
params Configuration container
Returns:
0 on success otherwise a negative error code
The software parameters can be changed at any time. The hardware parameters cannot be changed when the stream is running (active).
Examples:
/test/latency.c, and /test/pcm.c.
snd_pcm_sframes_t snd_pcm_avail_update
( snd_pcm_t *
pcm )
Return number of frames ready to be read (capture) / written (playback).
Parameters:
pcm PCM handle
Returns:
a positive number of frames ready otherwise a negative error code
On capture does all the actions needed to transport to application level all the ready frames across underlying layers.
The position is not synced with hardware (driver) position in the sound ring buffer in this function. This function is a light version of snd_pcm_avail() .
Using this function is ideal after poll() or select() when audio file descriptor made the event and when application expects just period timing.
Also this function might be called after snd_pcm_delay() or snd_pcm_hwsync() functions to move private ring buffer pointers in alsa-lib (the internal plugin chain).
Examples: /test/pcm.c.