Sndexistxd股票是什么意思思

1972人阅读
在看音频数据是怎么写的时候,在MixerThread的threadloop函数中,有以下代码完成了往硬件写数据:
int bytesWritten = (int)mOutput-&write(mMixBuffer, mixBufferSize);
mOutput来历:
函数AudioFlinger::openOutput中创建了一个MixerThread对象,并将前面调用mAudioHardware-&openOutputStream得到的output作为参数传入。
MixerThread继承自PlaybackThread,在PlaybackThread的构造函数中将传入的output赋值给了mOutput。
函数AudioFlinger::openOutput以前已经打过交道。mAudioHardware其实是一个AudioHardwareALSA对象。
调用mAudioHardware-&openOutputStream得到的其实是一个AudioStreamOutALSA对象。
所以,mOutput-&write,其实就是函数AudioStreamOutALSA::write。
*****************************************源码*************************************************
ssize_t AudioStreamOutALSA::write(const void *buffer, size_t bytes)
AutoMutex lock(mLock);
if (!mPowerLock) {
acquire_wake_lock (PARTIAL_WAKE_LOCK, &AudioOutLock&);
mPowerLock =
acoustic_device_t *aDev = acoustics();
// For output, we will pass the data on to the acoustics module, but the actual
// data is expected to be sent to the audio device directly as well.
if (aDev && aDev-&write)
aDev-&write(aDev, buffer, bytes);
snd_pcm_sframes_
if (mHandle-&mmap)
n = snd_pcm_mmap_writei(mHandle-&handle,
(char *)buffer + sent,
snd_pcm_bytes_to_frames(mHandle-&handle, bytes - sent));
n = snd_pcm_writei(mHandle-&handle,
(char *)buffer + sent,
snd_pcm_bytes_to_frames(mHandle-&handle, bytes - sent));
if (n == -EBADFD) {
// Somehow the stream is in a bad state. The driver probably
// has a bug and snd_pcm_recover() doesn't seem to handle this.
mHandle-&module-&open(mHandle, mHandle-&curDev, mHandle-&curMode);
if (aDev && aDev-&recover) aDev-&recover(aDev, n);
else if (n & 0) {
if (mHandle-&handle) {
LOGW(&underrun and do recovery.....&);
// snd_pcm_recover() will return 0 if successful in recovering from
// an error, or -errno if the error was unrecoverable.
n = snd_pcm_recover(mHandle-&handle, n, 1);
if (aDev && aDev-&recover) aDev-&recover(aDev, n);
if (n) return static_cast&ssize_t&(n);
mFrameCount +=
sent += static_cast&ssize_t&(snd_pcm_frames_to_bytes(mHandle-&handle, n));
} while (mHandle-&handle && sent & bytes);
**********************************************************************************************
源码路径:
hardware\alsa_sound\AudioStreamOutALSA.cpp
#######################说明################################
ssize_t AudioStreamOutALSA::write(const void *buffer, size_t bytes)
AutoMutex lock(mLock);
if (!mPowerLock) {
acquire_wake_lock (PARTIAL_WAKE_LOCK, &AudioOutLock&);
mPowerLock =
// 看看acoustics是个什么东东
acoustic_device_t *aDev = acoustics();
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
acoustic_device_t *ALSAStreamOps::acoustics()
return mParent-&mAcousticD
ALSAStreamOps是AudioStreamOutALSA的父类。
mParent是在ALSAStreamOps的构造函数中赋值的。
AudioStreamOutALSA对象是在AudioHardwareALSA::openOutputStream中创建。
out = new AudioStreamOutALSA(this, &(*it));
在ALSAStreamOps的构造函数中,将传入的this赋值给了mParent。
mAcousticDevice其实是AudioHardwareALSA的成员变量。其赋值在AudioHardwareALSA的构造函数中完成:
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
err = hw_get_module(ACOUSTICS_HARDWARE_MODULE_ID,
(hw_module_t const**)&module);
if (err == 0) {
hw_device_t*
err = module-&methods-&open(module, ACOUSTICS_HARDWARE_NAME, &device);
if (err == 0)
mAcousticDevice = (acoustic_device_t *)
LOGE(&Acoustics Module not found.&);
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// For output, we will pass the data on to the acoustics module, but the actual
// data is expected to be sent to the audio device directly as well.
if (aDev && aDev-&write)
aDev-&write(aDev, buffer, bytes);
snd_pcm_sframes_
// 写数据是在这儿完成的。
// 有两个关键的东东需要确认:
// 1、mHandle是怎么来的。
// 2、函数snd_pcm_mmap_writei是怎么实现的。
if (mHandle-&mmap)
n = snd_pcm_mmap_writei(mHandle-&handle,
(char *)buffer + sent,
snd_pcm_bytes_to_frames(mHandle-&handle, bytes - sent));
n = snd_pcm_writei(mHandle-&handle,
(char *)buffer + sent,
snd_pcm_bytes_to_frames(mHandle-&handle, bytes - sent));
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/* 先看看第一个问题:
1、mHandle是怎么来的。
mHandle也是在ALSAStreamOps的构造函数中赋值的。
所赋值其实就是以下代码中的it。
out = new AudioStreamOutALSA(this, &(*it));
// it的来历:
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Find the appropriate alsa device
// mALSADevice的产生,在看函数AudioHardwareALSA::openOutputStream的时候已经知道
for(ALSAHandleList::iterator it = mDeviceList.begin();
it != mDeviceList.end(); ++it)
if (it-&devices & devices) {
// open函数以前也有见过,不过当时没有彻底啃干净
// 在看函数AudioHardwareALSA::openOutputStream的时候,了解到,此处其实是调用的函数s_open
err = mALSADevice-&open(&(*it), devices, mode());
// +++++++++++++++++++++++++++++s_open+++++++++++++++++++++++++++++++++++
static status_t s_open(alsa_handle_t *handle, uint32_t devices, int mode)
// Close off previously opened device.
// It would be nice to determine if the underlying device actually
// changes, but we might be recovering from an error or manipulating
// mixer settings (see asound.conf).
s_close(handle);
// +++++++++++++++++++++++++++++s_close+++++++++++++++++++++++++++++++++++
static status_t s_close(alsa_handle_t *handle)
LOGW(&s_close--&);
status_t err = NO_ERROR;
snd_pcm_t *h = handle-&
handle-&handle = 0;
handle-&curDev = 0;
handle-&curMode = 0;
snd_pcm_drain(h);
// +++++++++++++++++++++++++++++snd_pcm_drain+++++++++++++++++++++++++++++++++++
* \brief Stop a PCM preserving pending frames
* \param pcm PCM handle
* \return 0 on success otherwise a negative error code
* \retval -ESTRPIPE a suspend event occurred
* For playback wait for all pending frames to be played and then stop
* the PCM.
* For capture stop PCM permitting to retrieve residual frames.
* For stopping the PCM stream immediately, use \link ::snd_pcm_drop() \endlink
* instead.
int snd_pcm_drain(snd_pcm_t *pcm)
assert(pcm);
if (CHECK_SANITY(! pcm-&setup)) {
SNDMSG(&PCM not set up&);
return -EIO;
// 调到了snd_pcm_t中的东东
// 又回到了原来的话题,alsa_handle_t结构体的来历
return pcm-&fast_ops-&drain(pcm-&fast_op_arg);
// -----------------------------snd_pcm_drain-----------------------------------
err = snd_pcm_close(h);
// ++++++++++++++++++++++++++++snd_pcm_close++++++++++++++++++++++++++++++++++++
* \brief close PCM handle
* \param pcm PCM handle
* \return 0 on success otherwise a negative error code
* Closes the specified PCM handle and frees all associated
* resources.
int snd_pcm_close(snd_pcm_t *pcm)
int res = 0,
assert(pcm);
if (pcm-&setup && !pcm-&donot_close) {
snd_pcm_drop(pcm);
// +++++++++++++++++++++++++++snd_pcm_drop+++++++++++++++++++++++++++++++++++++
* \brief Stop a PCM dropping pending frames
* \param pcm PCM handle
* \return 0 on success otherwise a negative error code
* This function stops the PCM &i&immediately&/i&.
* The pending samples on the buffer are ignored.
* For processing all pending samples, use \link ::snd_pcm_drain() \endlink
* instead.
int snd_pcm_drop(snd_pcm_t *pcm)
assert(pcm);
if (CHECK_SANITY(! pcm-&setup)) {
SNDMSG(&PCM not set up&);
return -EIO;
return pcm-&fast_ops-&drop(pcm-&fast_op_arg);
// ---------------------------snd_pcm_drop-------------------------------------
err = snd_pcm_hw_free(pcm);
// ++++++++++++++++++++++++++++++snd_pcm_hw_free++++++++++++++++++++++++++++++++++
/** \brief Remove PCM hardware configuration and free associated resources
* \param pcm PCM handle
* \return 0 on success otherwise a negative error code
int snd_pcm_hw_free(snd_pcm_t *pcm)
if (! pcm-&setup)
if (pcm-&mmap_channels) {
err = snd_pcm_munmap(pcm);
// +++++++++++++++++++++++++snd_pcm_munmap+++++++++++++++++++++++++++++++++++++++
int snd_pcm_munmap(snd_pcm_t *pcm)
assert(pcm);
if (CHECK_SANITY(! pcm-&mmap_channels)) {
SNDMSG(&Not mmapped&);
return -ENXIO;
if (pcm-&mmap_shadow)
return pcm-&ops-&munmap(pcm);
for (c = 0; c & pcm-& ++c) {
snd_pcm_channel_info_t *i = &pcm-&mmap_channels[c];
unsigned int c1;
size_t size = i-&first + i-&step * (pcm-&buffer_size - 1) + pcm-&sample_
if (!i-&addr)
for (c1 = c + 1; c1 & pcm-& ++c1) {
snd_pcm_channel_info_t *i1 = &pcm-&mmap_channels[c1];
if (i1-&addr != i-&addr)
i1-&addr = NULL;
s = i1-&first + i1-&step * (pcm-&buffer_size - 1) + pcm-&sample_
if (s & size)
size = (size + 7) / 8;
size = page_align(size);
switch (i-&type) {
case SND_PCM_AREA_MMAP:
err = munmap(i-&addr, size);
if (err & 0) {
SYSERR(&mmap failed&);
errno = 0;
#ifndef ANDROID
case SND_PCM_AREA_SHM:
if (i-&u.shm.area) {
snd_shm_area_destroy(i-&u.shm.area);
// +++++++++++++++++++++++snd_shm_area_destroy+++++++++++++++++++++++++++++++++++++++++
* \brief Release the shared area record
* \param area the shared are record
* \return 0 if successful, or a negative error code
* Decreases the reference counter of the given shared area record, and
* releases the resources automaticall if it reaches to 0.
int snd_shm_area_destroy(struct snd_shm_area *area)
if (area == NULL)
return -ENOENT;
if (--area-&share)
list_del(&area-&list);
shmdt(area-&ptr);
free(area);
// -----------------------snd_shm_area_destroy-----------------------------------------
i-&u.shm.area = NULL;
if (pcm-&access == SND_PCM_ACCESS_MMAP_INTERLEAVED ||
pcm-&access == SND_PCM_ACCESS_RW_INTERLEAVED) {
unsigned int c1;
for (c1 = c + 1; c1 & pcm-& c1++) {
snd_pcm_channel_info_t *i1 = &pcm-&mmap_channels[c1];
if (i1-&u.shm.area) {
snd_shm_area_destroy(i1-&u.shm.area);
i1-&u.shm.area = NULL;
case SND_PCM_AREA_LOCAL:
free(i-&addr);
assert(0);
i-&addr = NULL;
err = pcm-&ops-&munmap(pcm);
if (err & 0)
free(pcm-&mmap_channels);
free(pcm-&running_areas);
pcm-&mmap_channels = NULL;
pcm-&running_areas = NULL;
// -------------------------snd_pcm_munmap---------------------------------------
if (err & 0)
// assert(snd_pcm_state(pcm) == SND_PCM_STATE_SETUP ||
snd_pcm_state(pcm) == SND_PCM_STATE_PREPARED);
err = pcm-&ops-&hw_free(pcm-&op_arg);
pcm-&setup = 0;
if (err & 0)
// ------------------------------snd_pcm_hw_free----------------------------------
if (err & 0)
if (pcm-&mmap_channels)
snd_pcm_munmap(pcm);
while (!list_empty(&pcm-&async_handlers)) {
snd_async_handler_t *h = list_entry(pcm-&async_handlers.next, snd_async_handler_t, hlist);
snd_async_del_handler(h);
err = pcm-&ops-&close(pcm-&op_arg);
if (err & 0)
err = snd_pcm_free(pcm);
if (err & 0)
// ----------------------------snd_pcm_close------------------------------------
// 做了些清除工作。
// -----------------------------s_close-----------------------------------
LOGD(&open called for devices %08x in mode %d...&, devices, mode);
const char *stream = streamName(handle);
// +++++++++++++++++++++++++++++streamName+++++++++++++++++++++++++++++++++++
const char *streamName(alsa_handle_t *handle)
return snd_pcm_stream_name(direction(handle));
// +++++++++++++++++++++++++snd_pcm_stream_name+++++++++++++++++++++++++++++++++++++++
* \brief get name of PCM stream type
* \param stream PCM stream type
* \return ascii name of PCM stream type
const char *snd_pcm_stream_name(snd_pcm_stream_t stream)
if (stream & SND_PCM_STREAM_LAST)
return NULL;
return snd_pcm_stream_names[stream];
// +++++++++++++++++++++++++++snd_pcm_stream_names+++++++++++++++++++++++++++++++++++++
static const char *const snd_pcm_stream_names[] = {
// #define STREAM(v) [SND_PCM_STREAM_##v] = #v
STREAM(PLAYBACK),
STREAM(CAPTURE),
// ---------------------------snd_pcm_stream_names-------------------------------------
// -------------------------snd_pcm_stream_name---------------------------------------
// -----------------------------streamName-----------------------------------
const char *devName = deviceName(handle, devices, mode, 1);
// ++++++++++++++++++++++++++deviceName++++++++++++++++++++++++++++++++++++++
//card_device =0, return the card name, card_device=1, return the card device name
const char *deviceName(alsa_handle_t *alsa_handle, uint32_t device, int mode, int card_device)
snd_ctl_t *
int card, err, dev,
snd_ctl_card_info_t *
snd_pcm_info_t *
snd_ctl_card_info_alloca(&info);
snd_pcm_info_alloca(&pcminfo);
cardnum = 0;
char value[PROPERTY_VALUE_MAX];
snd_pcm_stream_t stream = direction(alsa_handle);
// +++++++++++++++++++++++++++direction+++++++++++++++++++++++++++++++++++++
snd_pcm_stream_t direction(alsa_handle_t *handle)
return (handle-&devices & AudioSystem::DEVICE_OUT_ALL) ? SND_PCM_STREAM_PLAYBACK
: SND_PCM_STREAM_CAPTURE;
// ---------------------------direction-------------------------------------
bool havespdifdevice =
bool havesgtldevice =
card = -1;
if (snd_card_next(&card) & 0 || card & 0) {
LOGD(&no soundcards found...&);
return &default&;
// ++++++++++++++++++++++++++++snd_card_next++++++++++++++++++++++++++++++++++++
external\alsa-lib\src\control\Cards.c
* \brief Try to determine the next card.
* \param rcard pointer to card number
* \result zero if success, otherwise a negative error code
* Tries to determine the next card from given card number.
* If card number is -1, then the first available card is
* returned. If the result card number is -1, no more cards
* are available.
int snd_card_next(int *rcard)
if (rcard == NULL)
return -EINVAL;
card = card & 0 ? 0 : card + 1;
for (; card & 32; card++) {
if (snd_card_load(card)) {
// +++++++++++++++++++++++++++snd_card_load+++++++++++++++++++++++++++++++++++++
* \brief Try to load the driver for a card.
* \param card Card number.
* \return 1 if driver is present, zero if driver is not present
int snd_card_load(int card)
return !!(snd_card_load1(card) &= 0);
// +++++++++++++++++++++++++++++snd_card_load1+++++++++++++++++++++++++++++++++++
static int snd_card_load1(int card)
char control[sizeof(SND_FILE_CONTROL) + 10];
sprintf(control, SND_FILE_CONTROL, card);
res = snd_card_load2(control);
// ++++++++++++++++++++++++++++snd_card_load2++++++++++++++++++++++++++++++++++++
static int snd_card_load2(const char *control)
snd_ctl_card_info_
open_dev = snd_open_device(control, O_RDONLY);
// +++++++++++++++++++++++++snd_open_device+++++++++++++++++++++++++++++++++++++++
static inline int snd_open_device(const char *filename, int fmode)
#ifdef O_CLOEXEC
fmode |= O_CLOEXEC;
fd = open(filename, fmode);
/* open with resmgr */
#ifdef SUPPORT_RESMGR
if (fd & 0) {
if (errno == EAGAIN || errno == EBUSY)
if (! access(filename, F_OK))
fd = rsm_open_device(filename, fmode);
if (fd &= 0)
fcntl(fd, F_SETFD, FD_CLOEXEC);
// -------------------------snd_open_device---------------------------------------
if (open_dev &= 0) {
if (ioctl(open_dev, SNDRV_CTL_IOCTL_CARD_INFO, &info) & 0) {
int err = -
close(open_dev);
close(open_dev);
return info.
// ----------------------------snd_card_load2------------------------------------
#ifdef SUPPORT_ALOAD
if (res & 0) {
char aload[sizeof(SND_FILE_LOAD) + 10];
sprintf(aload, SND_FILE_LOAD, card);
res = snd_card_load2(aload);
// -----------------------------snd_card_load1-----------------------------------
// ---------------------------snd_card_load-------------------------------------
*rcard = -1;
// ----------------------------snd_card_next------------------------------------
LOGD(&**** List of %s Hardware Devices ****\n&,
snd_pcm_stream_name(stream));
while (card &= 0) {
char name[32];
sprintf(name, &hw:%d&, card);
if ((err = snd_ctl_open(&handle, name, 0)) & 0) {
LOGD(&control open (%i): %s&, card, snd_strerror(err));
goto next_
// +++++++++++++++++++++++++++snd_ctl_open+++++++++++++++++++++++++++++++++++++
* \brief Opens a CTL
* \param ctlp Returned CTL handle
* \param name ASCII identifier of the CTL handle
* \param mode Open mode (see #SND_CTL_NONBLOCK, #SND_CTL_ASYNC)
* \return 0 on success otherwise a negative error code
int snd_ctl_open(snd_ctl_t **ctlp, const char *name, int mode)
assert(ctlp && name);
err = snd_config_update();
// +++++++++++++++++++++++++++snd_config_update+++++++++++++++++++++++++++++++++++++
* \brief Updates #snd_config by rereading the global configuration files (if needed).
* \return 0 if #snd_config was up to date, 1 if #snd_config was
updated, otherwise a negative error code.
* \warning Whenever #snd_config is updated, all string pointers and
* configuration node handles previously obtained from it may become
* invalid.
* \par Errors:
* Any errors encountered when parsing the input or returned by hooks or
* functions.
* \par Conforming to:
int snd_config_update(void)
#ifdef HAVE_LIBPTHREAD
pthread_mutex_lock(&snd_config_update_mutex);
err = snd_config_update_r(&snd_config, &snd_config_global_update, NULL);
// ++++++++++++++++++++++snd_config_update_r++++++++++++++++++++++++++++++++++++++++++
* \brief Updates a configuration tree by rereading the configuration files (if needed).
* \param[in,out] _top Address of the handle to the top-level node.
* \param[in,out] _update Address of a pointer to private update information.
* \param[in] cfgs A list of configuration file names, delimited with ':'.
If \p cfgs is \c NULL, the default global
configuration file is used.
* \return 0 if \a _top was up to date, 1 if the configuration files
have been reread, otherwise a negative error code.
* The variables pointed to by \a _top and \a _update can be initialized
* to \c NULL before the first call to this function.
The private
* update information holds information about all used configuration
* files that allows this function to det this data
* can be freed with #snd_config_update_free.
* The global configuration files are specified in the environment variable
* \c ALSA_CONFIG_PATH.
* \warning If the configuration tree is reread, all string pointers and
* configuration node handles previously obtained from this tree become
* invalid.
* \par Errors:
* Any errors encountered when parsing the input or returned by hooks or
* functions.
int snd_config_update_r(snd_config_t **_top, snd_config_update_t **_update, const char *cfgs)
const char *configs, *c;
snd_config_update_t *
snd_config_update_t *
snd_config_t *
assert(_top && _update);
update = *_
if (!configs) {
/** The name of the environment variable containing the files list for #snd_config_update. */
// #define ALSA_CONFIG_PATH_VAR &ALSA_CONFIG_PATH&
configs = getenv(ALSA_CONFIG_PATH_VAR);
if (!configs || !*configs)
/** The name of the default files used by #snd_config_update. */
// #define ALSA_CONFIG_PATH_DEFAULT ALSA_CONFIG_DIR &/alsa.conf&
configs = ALSA_CONFIG_PATH_DEFAULT;
for (k = 0, c = (l = strcspn(c, &: &)) & 0; ) {
if (k == 0) {
local = NULL;
local = (snd_config_update_t *)calloc(1, sizeof(snd_config_update_t));
if (!local)
return -ENOMEM;
local-&count =
local-&finfo = calloc(local-&count, sizeof(struct finfo));
if (!local-&finfo) {
free(local);
return -ENOMEM;
for (k = 0, c = (l = strcspn(c, &: &)) & 0; ) {
char name[l + 1];
memcpy(name, c, l);
name[l] = 0;
err = snd_user_file(name, &local-&finfo[k].name);
if (err & 0)
for (k = 0; k & local-& ++k) {
struct finfo *lf = &local-&finfo[k];
if (stat(lf-&name, &st) &= 0) {
lf-&dev = st.st_
lf-&ino = st.st_
lf-&mtime = st.st_
SNDERR(&Cannot access file %s&, lf-&name);
free(lf-&name);
memmove(&local-&finfo[k], &local-&finfo[k+1], sizeof(struct finfo) * (local-&count - k - 1));
local-&count--;
if (!update)
if (local-&count != update-&count)
for (k = 0; k & local-& ++k) {
struct finfo *lf = &local-&finfo[k];
struct finfo *uf = &update-&finfo[k];
if (strcmp(lf-&name, uf-&name) != 0 ||
lf-&dev != uf-&dev ||
lf-&ino != uf-&ino ||
lf-&mtime != uf-&mtime)
if (err & 0) {
if (top) {
snd_config_delete(top);
*_top = NULL;
if (update) {
snd_config_update_free(update);
*_update = NULL;
if (local)
snd_config_update_free(local);
*_top = NULL;
*_update = NULL;
if (update) {
snd_config_update_free(update);
update = NULL;
if (top) {
snd_config_delete(top);
top = NULL;
err = snd_config_top(&top);
// +++++++++++++++++++++++++++snd_config_top+++++++++++++++++++++++++++++++++++++
* \brief Creates a top level configuration node.
* \param[out] config Handle to the new node.
* \return Zero if successful, otherwise a negative error code.
* The returned node is an empty compound node without a parent and
* without an id.
* \par Errors:
* &dt&-ENOMEM&dd&Out of memory.
* \par Conforming to:
int snd_config_top(snd_config_t **config)
assert(config);
return _snd_config_make(config, 0, SND_CONFIG_TYPE_COMPOUND);
// +++++++++++++++++++++++++_snd_config_make+++++++++++++++++++++++++++++++++++++++
static int _snd_config_make(snd_config_t **config, char **id, snd_config_type_t type)
snd_config_t *n;
assert(config);
n = calloc(1, sizeof(*n));
if (n == NULL) {
if (*id) {
free(*id);
*id = NULL;
return -ENOMEM;
*id = NULL;
if (type == SND_CONFIG_TYPE_COMPOUND)
INIT_LIST_HEAD(&n-&pound.fields);
// ++++++++++++++++++++++++INIT_LIST_HEAD++++++++++++++++++++++++++++++++++++++++
#define INIT_LIST_HEAD(ptr) do { \
(ptr)-&next = (ptr); (ptr)-&prev = (ptr); \
} while (0)
// ------------------------INIT_LIST_HEAD----------------------------------------
// -------------------------_snd_config_make---------------------------------------
// ---------------------------snd_config_top-------------------------------------
if (err & 0)
if (!local)
for (k = 0; k & local-& ++k) {
snd_input_t *
err = snd_input_stdio_open(&in, local-&finfo[k].name, &r&);
// ++++++++++++++++++++++++snd_input_stdio_open++++++++++++++++++++++++++++++++++++++++
* \brief Creates a new input object reading from a file.
* \param inputp The functions puts the pointer to the new input object
at the address specified by \p inputp.
* \param file The name of the file to read from.
* \param mode The open mode, like \c fopen(3).
* \return Zero if successful, otherwise a negative error code.
int snd_input_stdio_open(snd_input_t **inputp, const char *file, const char *mode)
FILE *fp = fopen(file, mode);
if (!fp) {
//SYSERR(&fopen&);
err = snd_input_stdio_attach(inputp, fp, 1);
// +++++++++++++++++++++++++snd_input_stdio_attach+++++++++++++++++++++++++++++++++++++++
* \brief Creates a new input object using an existing stdio \c FILE pointer.
* \param inputp The function puts the pointer to the new input object
at the address specified by \p inputp.
* \param fp The \c FILE pointer to read from.
Reading begins at the current file position.
* \param _close Close flag. Set this to 1 if #snd_input_close should close
\p fp by calling \c fclose.
* \return Zero if successful, otherwise a negative error code.
int snd_input_stdio_attach(snd_input_t **inputp, FILE *fp, int _close)
snd_input_t *
snd_input_stdio_t *
assert(inputp && fp);
stdio = calloc(1, sizeof(*stdio));
if (!stdio)
return -ENOMEM;
input = calloc(1, sizeof(*input));
if (!input) {
free(stdio);
return -ENOMEM;
stdio-&fp =
stdio-&close = _
input-&type = SND_INPUT_STDIO;
input-&ops = &snd_input_stdio_
input-&private_data =
// -------------------------snd_input_stdio_attach---------------------------------------
if (err & 0)
fclose(fp);
// ------------------------snd_input_stdio_open----------------------------------------
if (err &= 0) {
err = snd_config_load(top, in);
// +++++++++++++++++++++++snd_config_load+++++++++++++++++++++++++++++++++++++++++
* \brief Loads a configuration tree.
* \param config Handle to a top level configuration node.
* \param in Input handle to read the configuration from.
* \return Zero if successful, otherwise a negative error code.
* The definitions loaded from the input are added to \a config, which
* must be a compound node.
* \par Errors:
* Any errors encountered when parsing the input or returned by hooks or
* functions.
* \par Conforming to:
int snd_config_load(snd_config_t *config, snd_input_t *in)
return snd_config_load1(config, in, 0);
// +++++++++++++++++++++++++++snd_config_load1+++++++++++++++++++++++++++++++++++++
static int snd_config_load1(snd_config_t *config, snd_input_t *in, int override)
struct filedesc *fd, *fd_
assert(config && in);
fd = malloc(sizeof(*fd));
return -ENOMEM;
fd-&name = NULL;
fd-&line = 1;
fd-&column = 0;
fd-&next = NULL;
input.current =
input.unget = 0;
err = parse_defs(config, &input, 0, override);
fd = input.
if (err & 0) {
const char *
switch (err) {
case LOCAL_UNTERMINATED_STRING:
str = &Unterminated string&;
err = -EINVAL;
case LOCAL_UNTERMINATED_QUOTE:
str = &Unterminated quote&;
err = -EINVAL;
case LOCAL_UNEXPECTED_CHAR:
str = &Unexpected char&;
err = -EINVAL;
case LOCAL_UNEXPECTED_EOF:
str = &Unexpected end of file&;
err = -EINVAL;
str = strerror(-err);
SNDERR(&%s:%d:%d:%s&, fd-&name ? fd-&name : &_toplevel_&, fd-&line, fd-&column, str);
if (get_char(&input) != LOCAL_UNEXPECTED_EOF) {
SNDERR(&%s:%d:%d:Unexpected }&, fd-&name ? fd-&name : &&, fd-&line, fd-&column);
err = -EINVAL;
while (fd-&next) {
fd_next = fd-&
snd_input_close(fd-&in);
free(fd-&name);
// ---------------------------snd_config_load1-------------------------------------
// -----------------------snd_config_load-----------------------------------------
snd_input_close(in);
if (err & 0) {
SNDERR(&%s may be old or corrupted: consider to remove or fix it&, local-&finfo[k].name);
SNDERR(&cannot access file %s&, local-&finfo[k].name);
err = snd_config_hooks(top, NULL);
if (err & 0) {
SNDERR(&hooks failed, removing configuration&);
*_update =
// ----------------------snd_config_update_r------------------------------------------
#ifdef HAVE_LIBPTHREAD
pthread_mutex_unlock(&snd_config_update_mutex);
// ---------------------------snd_config_update-------------------------------------
if (err & 0)
return snd_ctl_open_noupdate(ctlp, snd_config, name, mode);
// ++++++++++++++++++++++++++++snd_ctl_open_noupdate++++++++++++++++++++++++++++++++++++
static int snd_ctl_open_noupdate(snd_ctl_t **ctlp, snd_config_t *root, const char *name, int mode)
snd_config_t *ctl_
// 这儿,只看看snd_config_search_definition的注释吧
err = snd_config_search_definition(root, &ctl&, name, &ctl_conf);
// +++++++++++++++++++++++snd_config_search_definition+++++++++++++++++++++++++++++++++++++++++
* \brief Searches for a definition in a configuration tree, using
aliases and expanding hooks and arguments.
* \param[in] config Handle to the configuration (sub)tree to search.
* \param[in] base Implicit key base, or \c NULL for none.
* \param[in] name Key suffix, optionally with arguments.
* \param[out] result The function puts the handle to the expanded found
node at the address specified by \a result.
* \return A non-negative value if successful, otherwise a negative error code.
* This functions searches for a child node of \a config, allowing
* aliases and expanding hooks, like #snd_config_search_alias_hooks.
* If \a name contains a colon (:), the rest of the string after the
* colon contains arguments that are expanded as with
* #snd_config_expand.
* In any case, \a result is a new node that must be freed by the
* \par Errors:
* &dt&-ENOENT&dd&An id in \a key or an alias id does not exist.
* &dt&-ENOENT&dd&\a config or one of its child nodes to be searched is
not a compound node.
* Additionally, any errors encountered when parsing the hook
* definitions or arguments, or returned by (hook) functions.
// -----------------------snd_config_search_definition-----------------------------------------
if (err & 0) {
SNDERR(&Invalid CTL %s&, name);
err = snd_ctl_open_conf(ctlp, name, root, ctl_conf, mode);
// ++++++++++++++++++++++snd_ctl_open_conf++++++++++++++++++++++++++++++++++++++++++
static int snd_ctl_open_conf(snd_ctl_t **ctlp, const char *name,
snd_config_t *ctl_root, snd_config_t *ctl_conf, int mode)
const char *
char *buf = NULL, *buf1 = NULL;
snd_config_t *conf, *type_conf = NULL;
snd_config_iterator_t i,
const char *lib = NULL, *open_name = NULL;
const char *
int (*open_func)(snd_ctl_t **, const char *, snd_config_t *, snd_config_t *, int) = NULL;
#ifndef PIC
extern void *snd_control_open_symbols(void);
void *h = NULL;
if (snd_config_get_type(ctl_conf) != SND_CONFIG_TYPE_COMPOUND) {
SNDERR(&Invalid type for CTL %s definition&, name);
SNDERR(&Invalid type for CTL definition&);
return -EINVAL;
err = snd_config_search(ctl_conf, &type&, &conf);
if (err & 0) {
SNDERR(&type is not defined&);
err = snd_config_get_id(conf, &id);
if (err & 0) {
SNDERR(&unable to get id&);
err = snd_config_get_string(conf, &str);
if (err & 0) {
SNDERR(&Invalid type for %s&, id);
err = snd_config_search_definition(ctl_root, &ctl_type&, str, &type_conf);
if (err &= 0) {
if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) {
SNDERR(&Invalid type for CTL type %s definition&, str);
snd_config_for_each(i, next, type_conf) {
snd_config_t *n = snd_config_iterator_entry(i);
const char *
if (snd_config_get_id(n, &id) & 0)
if (strcmp(id, &comment&) == 0)
if (strcmp(id, &lib&) == 0) {
err = snd_config_get_string(n, &lib);
if (err & 0) {
SNDERR(&Invalid type for %s&, id);
if (strcmp(id, &open&) == 0) {
err = snd_config_get_string(n, &open_name);
if (err & 0) {
SNDERR(&Invalid type for %s&, id);
SNDERR(&Unknown field %s&, id);
err = -EINVAL;
if (!open_name) {
buf = malloc(strlen(str) + 32);
if (buf == NULL) {
err = -ENOMEM;
open_name =
sprintf(buf, &_snd_ctl_%s_open&, str);
if (!lib) {
const char *const *build_in = build_in_
while (*build_in) {
if (!strcmp(*build_in, str))
build_in++;
if (*build_in == NULL) {
buf1 = malloc(strlen(str) + sizeof(ALSA_PLUGIN_DIR) + 32);
if (buf1 == NULL) {
err = -ENOMEM;
lib = buf1;
sprintf(buf1, &%s/libasound_module_ctl_%s.so&, ALSA_PLUGIN_DIR, str);
#ifndef PIC
snd_control_open_symbols();
open_func = snd_dlobj_cache_lookup(open_name);
if (open_func) {
// +++++++++++++++++++++++snd_dlobj_cache_lookup+++++++++++++++++++++++++++++++++++++++++
void *snd_dlobj_cache_lookup(const char *name)
struct list_head *p;
struct dlobj_cache *c;
list_for_each(p, &pcm_dlobj_list) {
c = list_entry(p, struct dlobj_cache, list);
if (strcmp(c-&name, name) == 0)
return c-&
return NULL;
// 往pcm_dlobj_list中添加对象的地方:
// ++++++++++++++++++++++++++++++snd_dlobj_cache_add++++++++++++++++++++++++++++++++++
int snd_dlobj_cache_add(const char *name, void *dlobj, void *open_func)
struct list_head *p;
struct dlobj_cache *c;
list_for_each(p, &pcm_dlobj_list) {
c = list_entry(p, struct dlobj_cache, list);
if (strcmp(c-&name, name) == 0)
return 0; /* already exists */
c = malloc(sizeof(*c));
return -ENOMEM;
c-&name = strdup(name);
if (! c-&name) {
return -ENOMEM;
c-&func = open_
list_add_tail(&c-&list, &pcm_dlobj_list);
// ------------------------------snd_dlobj_cache_add----------------------------------
// 函数snd_ctl_open_conf中调用了函数snd_dlobj_cache_add。
// -----------------------snd_dlobj_cache_lookup-----------------------------------------
h = snd_dlopen(lib, RTLD_NOW);
open_func = snd_dlsym(h, open_name, SND_DLSYM_VERSION(SND_CONTROL_DLSYM_VERSION));
// +++++++++++++++++++++snd_dlsym+++++++++++++++++++++++++++++++++++++++++++
// 函数snd_dlsym的注释:
* \brief Resolves a symbol from a dynamic library - ALSA wrapper for \c dlsym.
* \param handle Library handle, similar to \c dlsym.
* \param name Symbol name.
* \param version Version of the symbol.
* This function can emulate dynamic linking for the static build of
* the alsa-lib library.
* This special version of the \c dlsym function checks also the version
* of the symbol. A versioned symbol should be defined using the
* #SND_DLSYM_BUILD_VERSION macro.
// ---------------------snd_dlsym-------------------------------------------
SNDERR(&Cannot open shared library %s&, lib);
err = -ENOENT;
} else if (!open_func) {
SNDERR(&symbol %s is not defined inside %s&, open_name, lib);
snd_dlclose(h);
err = -ENXIO;
if (type_conf)
snd_config_delete(type_conf);
if (err &= 0) {
err = open_func(ctlp, name, ctl_root, ctl_conf, mode);
if (err &= 0) {
if (h /*&& (mode & SND_CTL_KEEP_ALIVE)*/) {
snd_dlobj_cache_add(open_name, h, open_func);
(*ctlp)-&dl_handle =
snd_dlclose(h);
free(buf);
free(buf1);
// ----------------------snd_ctl_open_conf------------------------------------------
snd_config_delete(ctl_conf);
// ----------------------------snd_ctl_open_noupdate------------------------------------
// ---------------------------snd_ctl_open-------------------------------------
if ((err = snd_ctl_card_info(handle, info)) & 0) {
LOGD(&control hardware info (%i): %s&, card, snd_strerror(err));
snd_ctl_close(handle);
goto next_
// +++++++++++++++++++++++++snd_ctl_card_info+++++++++++++++++++++++++++++++++++++++
* \brief Get card related information
* \param ctl CTL handle
* \param info Card info pointer
* \return 0 on success otherwise a negative error code
int snd_ctl_card_info(snd_ctl_t *ctl, snd_ctl_card_info_t *info)
assert(ctl && info);
return ctl-&ops-&card_info(ctl, info);
// -------------------------snd_ctl_card_info---------------------------------------
while (1) {
if (snd_ctl_pcm_next_device(handle, &dev)&0)
LOGD(&snd_ctl_pcm_next_device&);
if (dev & 0)
snd_pcm_info_set_device(pcminfo, dev);
snd_pcm_info_set_subdevice(pcminfo, 0);
snd_pcm_info_set_stream(pcminfo, stream);
if ((err = snd_ctl_pcm_info(handle, pcminfo)) & 0) {
if (err != -ENOENT)
LOGD(&control digital audio info (%i): %s&, card, snd_strerror(err));
LOGD(&card %i: %s [%s], device %i: %s [%s]\n&,
card, snd_ctl_card_info_get_id(info), snd_ctl_card_info_get_name(info),
snd_pcm_info_get_id(pcminfo),
snd_pcm_info_get_name(pcminfo));
if(strcmp(snd_pcm_info_get_id(pcminfo),&IMX SPDIF mxc spdif-0&)==0) {
if(card_device==0)
sprintf(spdifcardname, &hw:0%d&, card);
sprintf(spdifcardname, &hw:%d,%d&, card, dev);
havespdifdevice =
if(strcmp(snd_pcm_info_get_id(pcminfo),&SGTL5000 SGTL5000-0&)==0) {
if(card_device==0) sprintf(sgtlcardname, &hw:0%d&, card);
sprintf(sgtlcardname, &hw:%d,%d&, card, dev);
havesgtldevice =
cardnum++;
snd_ctl_close(handle);
next_card:
if (snd_card_next(&card) & 0) {
LOGD(&snd_card_next&);
property_get(&ro.HDMI_AUDIO_OUTPUT&, value, &&);
if((device & AudioSystem::DEVICE_OUT_WIRED_HDMI) && havespdifdevice && (strcmp(value, &1&) == 0))
}else if(havesgtldevice)
return &default&;
// --------------------------deviceName--------------------------------------
// The PCM stream is opened in blocking mode, per ALSA defaults.
// AudioFlinger seems to assume blocking mode too, so asynchronous mode
// should not be used.
int err = snd_pcm_open(&handle-&handle, devName, direction(handle), 0);
// ++++++++++++++++++++++++snd_pcm_open++++++++++++++++++++++++++++++++++++++++\
// 想到了前面的函数snd_ctl_open,呜呼!危乎多哉!
* \brief Opens a PCM
* \param pcmp Returned PCM handle
* \param name ASCII identifier of the PCM handle
* \param stream Wanted stream
* \param mode Open mode (see #SND_PCM_NONBLOCK, #SND_PCM_ASYNC)
* \return 0 on success otherwise a negative error code
int snd_pcm_open(snd_pcm_t **pcmp, const char *name,
snd_pcm_stream_t stream, int mode)
assert(pcmp && name);
// 这个函数已经看过了
err = snd_config_update();
if (err & 0)
return snd_pcm_open_noupdate(pcmp, snd_config, name, stream, mode, 0);
// +++++++++++++++++++++++++++snd_pcm_open_noupdate+++++++++++++++++++++++++++++++++++++
static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, snd_config_t *root,
const char *name, snd_pcm_stream_t stream,
int mode, int hop)
snd_config_t *pcm_
const char *
err = snd_config_search_definition(root, &pcm&, name, &pcm_conf);
if (err & 0) {
SNDERR(&Unknown PCM %s&, name);
if (snd_config_get_string(pcm_conf, &str) &= 0)
err = snd_pcm_open_noupdate(pcmp, root, str, stream, mode,
snd_config_set_hop(pcm_conf, hop);
// ++++++++++++++++++++++++snd_config_set_hop++++++++++++++++++++++++++++++++++++++++
void snd_config_set_hop(snd_config_t *conf, int hop)
conf-&hop =
// ------------------------snd_config_set_hop----------------------------------------
err = snd_pcm_open_conf(pcmp, name, root, pcm_conf, stream, mode);
// ++++++++++++++++++++++++++++++snd_pcm_open_conf++++++++++++++++++++++++++++++++++
// 想起来一个与其非常相似的函数:snd_ctl_open_conf。
// 调用的函数上面都有介绍过,此处就不再说了。
static int snd_pcm_open_conf(snd_pcm_t **pcmp, const char *name,
snd_config_t *pcm_root, snd_config_t *pcm_conf,
snd_pcm_stream_t stream, int mode)
const char *
char *buf = NULL, *buf1 = NULL;
snd_config_t *conf, *type_conf = NULL;
snd_config_iterator_t i,
const char *
const char *lib = NULL, *open_name = NULL;
int (*open_func)(snd_pcm_t **, const char *,
snd_config_t *, snd_config_t *,
snd_pcm_stream_t, int) = NULL;
#ifndef PIC
extern void *snd_pcm_open_symbols(void);
void *h = NULL;
if (snd_config_get_type(pcm_conf) != SND_CONFIG_TYPE_COMPOUND) {
id = NULL;
snd_config_get_id(pcm_conf, &id);
val = NULL;
snd_config_get_ascii(pcm_conf, &val);
SNDERR(&Invalid type for PCM %s%sdefinition (id: %s, value: %s)&, name ? name : &&, name ? & & : &&, id, val);
free(val);
return -EINVAL;
err = snd_config_search(pcm_conf, &type&, &conf);
if (err & 0) {
SNDERR(&type is not defined&);
err = snd_config_get_id(conf, &id);
if (err & 0) {
SNDERR(&unable to get id&);
err = snd_config_get_string(conf, &str);
if (err & 0) {
SNDERR(&Invalid type for %s&, id);
err = snd_config_search_definition(pcm_root, &pcm_type&, str, &type_conf);
if (err &= 0) {
if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) {
SNDERR(&Invalid type for PCM type %s definition&, str);
snd_config_for_each(i, next, type_conf) {
snd_config_t *n = snd_config_iterator_entry(i);
const char *
if (snd_config_get_id(n, &id) & 0)
if (strcmp(id, &comment&) == 0)
if (strcmp(id, &lib&) == 0) {
err = snd_config_get_string(n, &lib);
if (err & 0) {
SNDERR(&Invalid type for %s&, id);
if (strcmp(id, &open&) == 0) {
err = snd_config_get_string(n, &open_name);
if (err & 0) {
SNDERR(&Invalid type for %s&, id);
SNDERR(&Unknown field %s&, id);
err = -EINVAL;
if (!open_name) {
buf = malloc(strlen(str) + 32);
if (buf == NULL) {
err = -ENOMEM;
open_name =
sprintf(buf, &_snd_pcm_%s_open&, str);
if (!lib) {
const char *const *build_in = build_in_
while (*build_in) {
if (!strcmp(*build_in, str))
build_in++;
if (*build_in == NULL) {
buf1 = malloc(strlen(str) + sizeof(ALSA_PLUGIN_DIR) + 32);
if (buf1 == NULL) {
err = -ENOMEM;
lib = buf1;
sprintf(buf1, &%s/libasound_module_pcm_%s.so&, ALSA_PLUGIN_DIR, str);
#ifndef PIC
snd_pcm_open_symbols();/* this call is for static linking only */
open_func = snd_dlobj_cache_lookup(open_name);
if (open_func) {
h = snd_dlopen(lib, RTLD_NOW);
open_func = snd_dlsym(h, open_name, SND_DLSYM_VERSION(SND_PCM_DLSYM_VERSION));
SNDERR(&Cannot open shared library %s&,
lib ? lib : &[builtin]&);
err = -ENOENT;
} else if (!open_func) {
SNDERR(&symbol %s is not defined inside %s&, open_name,
lib ? lib : &[builtin]&);
snd_dlclose(h);
err = -ENXIO;
if (err &= 0) {
err = open_func(pcmp, name, pcm_root, pcm_conf, stream, mode);
if (err &= 0) {
if (h /*&& (mode & SND_PCM_KEEP_ALIVE)*/) {
snd_dlobj_cache_add(open_name, h, open_func);
(*pcmp)-&dl_handle =
snd_dlclose(h);
if (type_conf)
snd_config_delete(type_conf);
free(buf);
free(buf1);
// ------------------------------snd_pcm_open_conf----------------------------------
snd_config_delete(pcm_conf);
// ---------------------------snd_pcm_open_noupdate-------------------------------------
// ------------------------snd_pcm_open----------------------------------------
if (err & 0) {
LOGE(&Failed to Initialize any ALSA %s device: %s&, stream, strerror(err));
return NO_INIT;
err = setHardwareParams(handle);
if (err == NO_ERROR) err = setSoftwareParams(handle);
LOGI(&Initialized ALSA %s device %s&, stream, devName);
handle-&curDev =
handle-&curMode =
// -----------------------------s_open-----------------------------------
if (devices & AudioSystem::DEVICE_OUT_WIRED_HDMI){
strcpy(mCurCard ,SPDIF);
mMixer = mMixerS
strcpy(mCurCard,SGTL5000);
mMixer = mMixerSgtl5000;
out = new AudioStreamOutALSA(this, &(*it));
err = out-&set(format, channels, sampleRate);
// ----------------------------------------------------------------
至此,it的来历基本上清楚了。
下面看看函数snd_pcm_mmap_writei和snd_pcm_writei的实现。
回忆一下上面的代码:
if (mHandle-&mmap)
n = snd_pcm_mmap_writei(mHandle-&handle,
(char *)buffer + sent,
snd_pcm_bytes_to_frames(mHandle-&handle, bytes - sent));
n = snd_pcm_writei(mHandle-&handle,
(char *)buffer + sent,
snd_pcm_bytes_to_frames(mHandle-&handle, bytes - sent));
// +++++++++++++++++++++++++snd_pcm_mmap_writei+++++++++++++++++++++++++++++++++++++++
* \brief Write interleaved frames to a PCM using direct buffer (mmap)
* \param pcm PCM handle
* \param buffer frames containing buffer
* \param size frames to be written
* \return a positive number of frames actually written otherwise a
* negative error code
* \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING)
* \retval -EPIPE an underrun occurred
* \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery)
* If the blocking behaviour is selected, then routine waits until
* all requested bytes are played or put to the playback ring buffer.
* The count of bytes can be less only if a signal or underrun occurred.
* If the non-blocking behaviour is selected, then routine doesn't wait at all.
snd_pcm_sframes_t snd_pcm_mmap_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
snd_pcm_channel_area_t areas[pcm-&channels];
snd_pcm_areas_from_buf(pcm, areas, (void*)buffer);
return snd_pcm_write_areas(pcm, areas, 0, size,
snd_pcm_mmap_write_areas);
// ++++++++++++++++++++++++++++snd_pcm_write_areas++++++++++++++++++++++++++++++++++++
snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_t *areas,
snd_pcm_uframes_t offset, snd_pcm_uframes_t size,
snd_pcm_xfer_areas_func_t func)
snd_pcm_uframes_t xfer = 0;
snd_pcm_sframes_t err = 0;
snd_pcm_state_
if (size == 0)
while (size & 0) {
snd_pcm_uframes_
snd_pcm_sframes_
state = snd_pcm_state(pcm);
// ++++++++++++++++++++++++++++++snd_pcm_state++++++++++++++++++++++++++++++++++
* \brief Return PCM state
* \param pcm PCM handle
* \return PCM state #snd_pcm_state_t of given PCM handle
* This is a faster way to obtain only the PCM state without calling
* \link ::snd_pcm_status() \endlink.
snd_pcm_state_t snd_pcm_state(snd_pcm_t *pcm)
assert(pcm);
return pcm-&fast_ops-&state(pcm-&fast_op_arg);
// ------------------------------snd_pcm_state----------------------------------
switch (state) {
case SND_PCM_STATE_PREPARED:
case SND_PCM_STATE_PAUSED:
case SND_PCM_STATE_RUNNING:
err = snd_pcm_hwsync(pcm);
if (err & 0)
// +++++++++++++++++++++++++++snd_pcm_hwsync+++++++++++++++++++++++++++++++++++++
* \brief (DEPRECATED) Synchronize stream position with hardware
* \param pcm PCM handle
* \return 0 on success otherwise a negative error code
* Note this function does not update the actual r/w pointer
* for applications. The function #snd_pcm_avail_update()
* have to be called before any mmap begin+commit operation.
int snd_pcm_hwsync(snd_pcm_t *pcm)
assert(pcm);
if (CHECK_SANITY(! pcm-&setup)) {
SNDMSG(&PCM not set up&);
return -EIO;
return pcm-&fast_ops-&hwsync(pcm-&fast_op_arg);
// ---------------------------snd_pcm_hwsync-------------------------------------
case SND_PCM_STATE_XRUN:
err = -EPIPE;
case SND_PCM_STATE_SUSPENDED:
err = -ESTRPIPE;
case SND_PCM_STATE_DISCONNECTED:
err = -ENODEV;
err = -EBADFD;
avail = snd_pcm_avail_update(pcm);
if (avail & 0) {
// +++++++++++++++++++++++++++++snd_pcm_avail_update+++++++++++++++++++++++++++++++++++
* \brief Return number of frames ready to be read (capture) / written (playback)
* \param pcm PCM handle
* \return 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
* 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).
snd_pcm_sframes_t snd_pcm_avail_update(snd_pcm_t *pcm)
return pcm-&fast_ops-&avail_update(pcm-&fast_op_arg);
// -----------------------------snd_pcm_avail_update-----------------------------------
if ((state == SND_PCM_STATE_RUNNING &&
(snd_pcm_uframes_t)avail & pcm-&avail_min &&
size & (snd_pcm_uframes_t)avail)) {
if (pcm-&mode & SND_PCM_NONBLOCK) {
err = -EAGAIN;
err = snd_pcm_wait(pcm, -1);
if (err & 0)
// +++++++++++++++++++++++++++snd_pcm_wait+++++++++++++++++++++++++++++++++++++
* \brief Wait for a PCM to become ready
* \param pcm PCM handle
* \param timeout maximum time in milliseconds to wait,
a negative value means infinity
* \return a positive value on success otherwise a negative error code
(-EPIPE for the xrun and -ESTRPIPE for the suspended status,
others for general errors)
* \retval 0 timeout occurred
* \retval 1 PCM stream is ready for I/O
int snd_pcm_wait(snd_pcm_t *pcm, int timeout)
if (snd_pcm_mmap_avail(pcm) &= pcm-&avail_min) {
/* check more precisely */
switch (snd_pcm_state(pcm)) {
case SND_PCM_STATE_XRUN:
return -EPIPE;
case SND_PCM_STATE_SUSPENDED:
return -ESTRPIPE;
case SND_PCM_STATE_DISCONNECTED:
return -ENODEV;
// +++++++++++++++++++++++++snd_pcm_mmap_avail+++++++++++++++++++++++++++++++++++++++
static inline snd_pcm_uframes_t snd_pcm_mmap_avail(snd_pcm_t *pcm)
if (pcm-&stream == SND_PCM_STREAM_PLAYBACK)
// 先只看播放的
return snd_pcm_mmap_playback_avail(pcm);
// ++++++++++++++++++++++++++++snd_pcm_mmap_playback_avail++++++++++++++++++++++++++++++++++++
static inline snd_pcm_uframes_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm)
snd_pcm_sframes_
avail = *pcm-&hw.ptr + pcm-&buffer_size - *pcm-&appl.
if (avail & 0)
avail += pcm-&
else if ((snd_pcm_uframes_t) avail &= pcm-&boundary)
avail -= pcm-&
// ----------------------------snd_pcm_mmap_playback_avail------------------------------------
return snd_pcm_mmap_capture_avail(pcm);
// --------------------------snd_pcm_mmap_avail--------------------------------------
return snd_pcm_wait_nocheck(pcm, timeout);
// ----------------------------snd_pcm_wait------------------------------------
if (frames & (snd_pcm_uframes_t) avail)
if (! frames)
// func是传入的参数snd_pcm_mmap_write_areas
err = func(pcm, areas, offset, frames);
// +++++++++++++++++++++++++++func是传入的参数snd_pcm_mmap_write_areas+++++++++++++++++++++++++++++++++++++
static snd_pcm_sframes_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm,
const snd_pcm_channel_area_t *areas,
snd_pcm_uframes_t offset,
snd_pcm_uframes_t size)
snd_pcm_uframes_t xfer = 0;
if (snd_pcm_mmap_playback_avail(pcm) & size) {
SNDMSG(&too short avail %ld to size %ld&, snd_pcm_mmap_playback_avail(pcm), size);
return -EPIPE;
while (size & 0) {
const snd_pcm_channel_area_t *pcm_
snd_pcm_uframes_t pcm_
snd_pcm_uframes_t frames =
snd_pcm_sframes_
snd_pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames);
// +++++++++++++++++++++++++snd_pcm_mmap_begin+++++++++++++++++++++++++++++++++++++++
* \brief Application request to access a portion of direct (mmap) area
* \param pcm PCM handle
* \param areas Returned mmap channel areas
* \param offset Returned mmap area offset in area steps (== frames)
* \param frames mmap area portion size in frames (wanted on entry, contiguous available on exit)
* \return 0 on success otherwise a negative error code
* It is necessary to call the snd_pcm_avail_update() function directly before
* this call. Otherwise, this function can return a wrong count of available frames.
* The function should be called before a sample-direct area can be accessed.
* The resulting size parameter is always less or equal to the input count of frames
* and can be zero, if no frames can be processed (the ring buffer is full).
* See the snd_pcm_mmap_commit() function to finish the frame processing in
* the direct areas.
int snd_pcm_mmap_begin(snd_pcm_t *pcm,
const snd_pcm_channel_area_t **areas,
snd_pcm_uframes_t *offset,
snd_pcm_uframes_t *frames)
snd_pcm_uframes_
snd_pcm_uframes_
snd_pcm_uframes_
const snd_pcm_channel_area_t *
assert(pcm && areas && offset && frames);
xareas = snd_pcm_mmap_areas(pcm);
if (xareas == NULL)
return -EBADFD;
// +++++++++++++++++++++++++++snd_pcm_mmap_areas+++++++++++++++++++++++++++++++++++++
static inline const snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm)
if (pcm-&stopped_areas &&
snd_pcm_state(pcm) != SND_PCM_STATE_RUNNING)
return pcm-&stopped_
return pcm-&running_
// ---------------------------snd_pcm_mmap_areas-------------------------------------
*offset = *pcm-&appl.ptr % pcm-&buffer_
avail = snd_pcm_mmap_avail(pcm);
if (avail & pcm-&buffer_size)
avail = pcm-&buffer_
cont = pcm-&buffer_size - *
if (f & avail)
if (f & cont)
// -------------------------snd_pcm_mmap_begin---------------------------------------
// 把数据从areas copy 到 pcm_areas
// areas是传入的参数
// pcm_areas是pcm(snd_pcm_t)的stopped_areas或者running_areas。
snd_pcm_areas_copy(pcm_areas, pcm_offset,
areas, offset,
pcm-&channels,
frames, pcm-&format);
// +++++++++++++++++++++++++snd_pcm_areas_copy+++++++++++++++++++++++++++++++++++++++
* \brief Copy one or more areas
* \param dst_areas destination areas specification (one for each channel)
* \param dst_offset offset in frames inside destination area
* \param src_areas source areas specification (one for each channel)
* \param src_offset offset in frames inside source area
* \param channels channels count
* \param frames frames to copy
* \param format PCM sample format
* \return 0 on success otherwise a negative error code
int snd_pcm_areas_copy(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset,
const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset,
unsigned int channels, snd_pcm_uframes_t frames, snd_pcm_format_t format)
int width = snd_pcm_format_physical_width(format);
assert(dst_areas);
assert(src_areas);
if (! channels) {
SNDMSG(&invalid channels %d&, channels);
return -EINVAL;
if (! frames) {
SNDMSG(&invalid frames %ld&, frames);
return -EINVAL;
while (channels & 0) {
unsigned int step = src_areas-&
void *src_addr = src_areas-&
const snd_pcm_channel_area_t *src_start = src_
void *dst_addr = dst_areas-&
const snd_pcm_channel_area_t *dst_start = dst_
int channels1 =
unsigned int chns = 0;
while (dst_areas-&step == step) {
channels1--;
src_areas++;
dst_areas++;
if (channels1 == 0 ||
src_areas-&step != step ||
src_areas-&addr != src_addr ||
dst_areas-&addr != dst_addr ||
src_areas-&first != src_areas[-1].first + width ||
dst_areas-&first != dst_areas[-1].first + width)
if (chns & 1 && chns * width == step) {
/* Collapse the areas */
snd_pcm_channel_area_t s,
s.addr = src_start-&
s.first = src_start-&
d.addr = dst_start-&
d.first = dst_start-&
snd_pcm_area_copy(&d, dst_offset * chns,
&s, src_offset * chns,
frames * chns, format);
channels -=
// ++++++++++++++++++++++++++++snd_pcm_area_copy++++++++++++++++++++++++++++++++++++
* \brief Copy an area
* \param dst_area destination area specification
* \param dst_offset offset in frames inside destination area
* \param src_area source area specification
* \param src_offset offset in frames inside source area
* \param samples samples to copy
* \param format PCM sample format
* \return 0 on success otherwise a negative error code
int snd_pcm_area_copy(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes_t dst_offset,
const snd_pcm_channel_area_t *src_area, snd_pcm_uframes_t src_offset,
unsigned int samples, snd_pcm_format_t format)
/* FIXME: sub byte resolution and odd dst_offset */
const char *
int src_step, dst_
if (dst_area == src_area && dst_offset == src_offset)
if (!src_area-&addr)
return snd_pcm_area_silence(dst_area, dst_offset, samples, format);
src = snd_pcm_channel_area_addr(src_area, src_offset);
if (!dst_area-&addr)
// +++++++++++++++++++++++snd_pcm_channel_area_addr+++++++++++++++++++++++++++++++++++++++++
static inline void *snd_pcm_channel_area_addr(const snd_pcm_channel_area_t *area, snd_pcm_uframes_t offset)
unsigned int bitofs = area-&first + area-&step *
assert(bitofs % 8 == 0);
return (char *) area-&addr + bitofs / 8;
// -----------------------snd_pcm_channel_area_addr-----------------------------------------
dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
width = snd_pcm_format_physical_width(format);
if (src_area-&step == (unsigned int) width &&
dst_area-&step == (unsigned int) width) {
size_t bytes = samples * width / 8;
samples -= bytes * 8 /
memcpy(dst, src, bytes);
if (samples == 0)
src_step = src_area-&step / 8;
dst_step = dst_area-&step / 8;
switch (width) {
int srcbit = src_area-&first % 8;
int srcbit_step = src_area-&step % 8;
int dstbit = dst_area-&first % 8;
int dstbit_step = dst_area-&step % 8;
while (samples-- & 0) {
if (srcbit)
srcval = *src & 0x0f;
srcval = *src & 0xf0;
if (dstbit)
*dst &= 0xf0;
*dst &= 0x0f;
src += src_
srcbit += srcbit_
if (srcbit == 8) {
srcbit = 0;
dst += dst_
dstbit += dstbit_
if (dstbit == 8) {
dstbit = 0;
while (samples-- & 0) {
src += src_
dst += dst_
case 16: {
while (samples-- & 0) {
*(u_int16_t*)dst = *(const u_int16_t*)
src += src_
dst += dst_
while (samples-- & 0) {
*(dst + 0) = *(src + 0);
*(dst + 1) = *(src + 1);
*(dst + 2) = *(src + 2);
src += src_
dst += dst_
case 32: {
while (samples-- & 0) {
*(u_int32_t*)dst = *(const u_int32_t*)
src += src_
dst += dst_
case 64: {
while (samples-- & 0) {
*(u_int64_t*)dst = *(const u_int64_t*)
src += src_
dst += dst_
SNDMSG(&invalid format width %d&, width);
return -EINVAL;
// ----------------------------snd_pcm_area_copy------------------------------------
snd_pcm_area_copy(dst_start, dst_offset,
src_start, src_offset,
frames, format);
src_areas = src_start + 1;
dst_areas = dst_start + 1;
channels--;
// -------------------------snd_pcm_areas_copy---------------------------------------
result = snd_pcm_mmap_commit(pcm, pcm_offset, frames);
if (result & 0)
return xfer & 0 ? (snd_pcm_sframes_t)xfer :
// +++++++++++++++++++++++++++snd_pcm_mmap_commit+++++++++++++++++++++++++++++++++++++
* \brief Application has completed the access to area requested with #snd_pcm_mmap_begin
* \param pcm PCM handle
* \param offset area offset in area steps (== frames)
* \param frames area portion size in frames
* \return count of transferred frames otherwise a negative error code
* You should pass this function the offset value that
* snd_pcm_mmap_begin() returned. The frames parameter should hold the
* number of frames you have written or read to/from the audio
* buffer. The frames parameter must never exceed the contiguous frames
* count that snd_pcm_mmap_begin() returned. Each call to snd_pcm_mmap_begin()
* must be followed by a call to snd_pcm_mmap_commit().
* Example:
double phase = 0;
const snd_pcm_area_t *
snd_pcm_sframes_t avail, size,
snd_pcm_uframes_t offset,
avail = snd_pcm_avail_update(pcm);
if (avail & 0)
error(avail);
// at this point, we can transfer at least 'avail' frames
// we want to process frames in chunks (period_size)
if (avail & period_size)
size = period_
// it is possible that contiguous areas are smaller, thus we use a loop
while (size & 0) {
err = snd_pcm_mmap_begin(pcm_handle, &areas, &offset, &frames);
if (err & 0)
error(err);
// this function fills the areas from offset with count of frames
generate_sine(areas, offset, frames, &phase);
commitres = snd_pcm_mmap_commit(pcm_handle, offset, frames);
if (commitres & 0 || commitres != frames)
error(commitres &= 0 ? -EPIPE : commitres);
* Look to the \ref example_test_pcm &Sine-wave generator& example
* for more details about the generate_sine function.
snd_pcm_sframes_t snd_pcm_mmap_commit(snd_pcm_t *pcm,
snd_pcm_uframes_t offset,
snd_pcm_uframes_t frames)
assert(pcm);
if (CHECK_SANITY(offset != *pcm-&appl.ptr % pcm-&buffer_size)) {
SNDMSG(&commit offset (%ld) doesn't match with appl_ptr (%ld) %% buf_size (%ld)&,
offset, *pcm-&appl.ptr, pcm-&buffer_size);
return -EPIPE;
if (CHECK_SANITY(frames & snd_pcm_mmap_avail(pcm))) {
SNDMSG(&commit frames (%ld) overflow (avail = %ld)&, frames,
snd_pcm_mmap_avail(pcm));
return -EPIPE;
return pcm-&fast_ops-&mmap_commit(pcm-&fast_op_arg, offset, frames);
// ---------------------------snd_pcm_mmap_commit-------------------------------------
return (snd_pcm_sframes_t)
// ---------------------------func是传入的参数snd_pcm_mmap_write_areas-------------------------------------
if (err & 0)
if (state == SND_PCM_STATE_PREPARED) {
snd_pcm_sframes_t hw_avail = pcm-&buffer_size -
hw_avail +=
/* some plugins might automatically start the stream */
state = snd_pcm_state(pcm);
if (state == SND_PCM_STATE_PREPARED &&
hw_avail &= (snd_pcm_sframes_t) pcm-&start_threshold) {
err = snd_pcm_start(pcm);
if (err & 0)
return xfer & 0 ? (snd_pcm_sframes_t) xfer : snd_pcm_check_error(pcm, err);
// ----------------------------snd_pcm_write_areas------------------------------------
// -------------------------snd_pcm_mmap_writei---------------------------------------
// ++++++++++++++++++++++++++snd_pcm_writei++++++++++++++++++++++++++++++++++++++
* \brief Write interleaved frames to a PCM
* \param pcm PCM handle
* \param buffer frames containing buffer
* \param size frames to be written
* \return a positive number of frames actually written otherwise a
* negative error code
* \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING)
* \retval -EPIPE an underrun occurred
* \retval -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.
snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
assert(pcm);
assert(size == 0 || buffer);
if (CHECK_SANITY(! pcm-&setup)) {
SNDMSG(&PCM not set up&);
return -EIO;
if (pcm-&access != SND_PCM_ACCESS_RW_INTERLEAVED) {
SNDMSG(&invalid access type %s&, snd_pcm_access_name(pcm-&access));
return -EINVAL;
return _snd_pcm_writei(pcm, buffer, size);
// +++++++++++++++++++++++++++_snd_pcm_writei+++++++++++++++++++++++++++++++++++++
static inline snd_pcm_sframes_t _snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
return pcm-&fast_ops-&writei(pcm-&fast_op_arg, buffer, size);
// ---------------------------_snd_pcm_writei-------------------------------------
// --------------------------snd_pcm_writei--------------------------------------
// ----------------------------------------------------------------
if (n == -EBADFD) {
// Somehow the stream is in a bad state. The driver probably
// has a bug and snd_pcm_recover() doesn't seem to handle this.
mHandle-&module-&open(mHandle, mHandle-&curDev, mHandle-&curMode);
if (aDev && aDev-&recover) aDev-&recover(aDev, n);
else if (n & 0) {
if (mHandle-&handle) {
LOGW(&underrun and do recovery.....&);
// snd_pcm_recover() will return 0 if successful in recovering from
// an error, or -errno if the error was unrecoverable.
n = snd_pcm_recover(mHandle-&handle, n, 1);
if (aDev && aDev-&recover) aDev-&recover(aDev, n);
if (n) return static_cast&ssize_t&(n);
mFrameCount +=
sent += static_cast&ssize_t&(snd_pcm_frames_to_bytes(mHandle-&handle, n));
} while (mHandle-&handle && sent & bytes);
###########################################################
&&&&&&&&&&&&&&&&&&&&&&&总结&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
在open output stream的时候,会创建一个snd_pcm_t的结构体。
write数据的时候,有两中方式:
1、mmap方式,其实是往结构体的stopped_areas或者running_areas成员中copy数据。
& & 写完后,通过commit函数通知底层:
pcm-&fast_ops-&mmap_commit
2、否则,直接调用结构体的writei函数写数据:
& & pcm-&fast_ops-&writei
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:359027次
积分:5202
积分:5202
排名:第2255名
原创:122篇
转载:142篇
评论:107条
(3)(1)(4)(1)(5)(12)(3)(1)(3)(3)(5)(15)(2)(15)(12)(8)(4)(6)(4)(2)(2)(4)(4)(1)(1)(7)(2)(3)(1)(5)(2)(24)(2)(8)(9)(2)(5)(11)(5)(1)(11)(13)(10)(10)(1)(1)(4)(5)(1)(1)(16)(1)(1)(2)(1)}

我要回帖

更多关于 委比和委差是什么意思 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信