aboutsummaryrefslogtreecommitdiffstats
path: root/audio/alsaaudio.c
diff options
context:
space:
mode:
authorDavid 'Digit' Turner <digit@android.com>2011-01-02 12:58:51 +0100
committerDavid 'Digit' Turner <digit@android.com>2011-01-02 13:05:31 +0100
commit5d0e37bc290d1743cb5acf76eb6608f1303f27dd (patch)
tree142486cd40940a38aa4fe5947521b39dc2cec339 /audio/alsaaudio.c
parente3650680f44fed0262d33eb4f486e5c1e58ddc32 (diff)
downloadexternal_qemu-5d0e37bc290d1743cb5acf76eb6608f1303f27dd.zip
external_qemu-5d0e37bc290d1743cb5acf76eb6608f1303f27dd.tar.gz
external_qemu-5d0e37bc290d1743cb5acf76eb6608f1303f27dd.tar.bz2
upstream: audio sub-system improvements.
This patch updates the audio subsystem to match the one in upstream. Note that this gets rid of the ability to specify different audio backends for input and output, which was never really used. A future patch will remove the -audio-in and -audio-out options and related code. Change-Id: I37c21672bcb15ef1f0e928c56bf99fbecda2bce6
Diffstat (limited to 'audio/alsaaudio.c')
-rw-r--r--audio/alsaaudio.c550
1 files changed, 416 insertions, 134 deletions
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 0f5ee9e..1cbbaa4 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -1,7 +1,7 @@
/*
* QEMU ALSA audio driver
*
- * Copyright (c) 2008 The Android Open Source Project
+ * Copyright (c) 2008-2010 The Android Open Source Project
* Copyright (c) 2005 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -24,8 +24,13 @@
*/
#include <alsa/asoundlib.h>
#include "qemu-common.h"
+#include "qemu-char.h"
#include "audio.h"
+#if QEMU_GNUC_PREREQ(4, 3)
+#pragma GCC diagnostic ignored "-Waddress"
+#endif
+
#define AUDIO_CAP "alsa"
#include "audio_int.h"
#include <dlfcn.h>
@@ -81,6 +86,10 @@
DYNLINK_FUNC(int,snd_pcm_hw_params_set_buffer_size_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)) \
DYNLINK_FUNC(int,snd_pcm_hw_params_set_period_size_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir)) \
DYNLINK_FUNC(int,snd_pcm_hw_params_get_format,(const snd_pcm_hw_params_t *params, snd_pcm_format_t *val)) \
+ DYNLINK_FUNC(int,snd_pcm_resume,(snd_pcm_t *pcm)) \
+ DYNLINK_FUNC(int,snd_pcm_poll_descriptors_revents,(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)) \
+ DYNLINK_FUNC(int,snd_pcm_poll_descriptors_count,(snd_pcm_t *pcm)) \
+ DYNLINK_FUNC(int,snd_pcm_poll_descriptors,(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)) \
#define DYNLINK_FUNCTIONS_INIT \
alsa_dynlink_init
@@ -96,16 +105,27 @@
static void* alsa_lib;
+struct pollhlp {
+ snd_pcm_t *handle;
+ struct pollfd *pfds;
+ int count;
+ int mask;
+};
+
typedef struct ALSAVoiceOut {
HWVoiceOut hw;
+ int wpos;
+ int pending;
void *pcm_buf;
snd_pcm_t *handle;
+ struct pollhlp pollhlp;
} ALSAVoiceOut;
typedef struct ALSAVoiceIn {
HWVoiceIn hw;
snd_pcm_t *handle;
void *pcm_buf;
+ struct pollhlp pollhlp;
} ALSAVoiceIn;
static struct {
@@ -126,7 +146,8 @@ static struct {
int period_size_out_overridden;
int verbose;
} conf = {
- .buffer_size_out = 1024,
+ .buffer_size_out = 4096,
+ .period_size_out = 1024,
.pcm_name_out = "default",
.pcm_name_in = "default",
};
@@ -178,7 +199,23 @@ static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
AUD_log (AUDIO_CAP, "Reason: %s\n", FF(snd_strerror) (err));
}
-static void alsa_anal_close (snd_pcm_t **handlep)
+static void alsa_fini_poll (struct pollhlp *hlp)
+{
+ int i;
+ struct pollfd *pfds = hlp->pfds;
+
+ if (pfds) {
+ for (i = 0; i < hlp->count; ++i) {
+ qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
+ }
+ qemu_free (pfds);
+ }
+ hlp->pfds = NULL;
+ hlp->count = 0;
+ hlp->handle = NULL;
+}
+
+static void alsa_anal_close1 (snd_pcm_t **handlep)
{
int err = FF(snd_pcm_close) (*handlep);
if (err) {
@@ -187,6 +224,167 @@ static void alsa_anal_close (snd_pcm_t **handlep)
*handlep = NULL;
}
+static void alsa_anal_close (snd_pcm_t **handlep, struct pollhlp *hlp)
+{
+ alsa_fini_poll (hlp);
+ alsa_anal_close1 (handlep);
+}
+
+static int alsa_recover (snd_pcm_t *handle)
+{
+ int err = FF(snd_pcm_prepare) (handle);
+ if (err < 0) {
+ alsa_logerr (err, "Failed to prepare handle %p\n", handle);
+ return -1;
+ }
+ return 0;
+}
+
+static int alsa_resume (snd_pcm_t *handle)
+{
+ int err = FF(snd_pcm_resume) (handle);
+ if (err < 0) {
+ alsa_logerr (err, "Failed to resume handle %p\n", handle);
+ return -1;
+ }
+ return 0;
+}
+
+static void alsa_poll_handler (void *opaque)
+{
+ int err, count;
+ snd_pcm_state_t state;
+ struct pollhlp *hlp = opaque;
+ unsigned short revents;
+
+ count = poll (hlp->pfds, hlp->count, 0);
+ if (count < 0) {
+ dolog ("alsa_poll_handler: poll %s\n", strerror (errno));
+ return;
+ }
+
+ if (!count) {
+ return;
+ }
+
+ /* XXX: ALSA example uses initial count, not the one returned by
+ poll, correct? */
+ err = FF(snd_pcm_poll_descriptors_revents) (hlp->handle, hlp->pfds,
+ hlp->count, &revents);
+ if (err < 0) {
+ alsa_logerr (err, "snd_pcm_poll_descriptors_revents");
+ return;
+ }
+
+ if (!(revents & hlp->mask)) {
+ if (conf.verbose) {
+ dolog ("revents = %d\n", revents);
+ }
+ return;
+ }
+
+ state = FF(snd_pcm_state) (hlp->handle);
+ switch (state) {
+ case SND_PCM_STATE_SETUP:
+ alsa_recover (hlp->handle);
+ break;
+
+ case SND_PCM_STATE_XRUN:
+ alsa_recover (hlp->handle);
+ break;
+
+ case SND_PCM_STATE_SUSPENDED:
+ alsa_resume (hlp->handle);
+ break;
+
+ case SND_PCM_STATE_PREPARED:
+ audio_run ("alsa run (prepared)");
+ break;
+
+ case SND_PCM_STATE_RUNNING:
+ audio_run ("alsa run (running)");
+ break;
+
+ default:
+ dolog ("Unexpected state %d\n", state);
+ }
+}
+
+static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask)
+{
+ int i, count, err;
+ struct pollfd *pfds;
+
+ count = FF(snd_pcm_poll_descriptors_count) (handle);
+ if (count <= 0) {
+ dolog ("Could not initialize poll mode\n"
+ "Invalid number of poll descriptors %d\n", count);
+ return -1;
+ }
+
+ pfds = audio_calloc ("alsa_poll_helper", count, sizeof (*pfds));
+ if (!pfds) {
+ dolog ("Could not initialize poll mode\n");
+ return -1;
+ }
+
+ err = FF(snd_pcm_poll_descriptors) (handle, pfds, count);
+ if (err < 0) {
+ alsa_logerr (err, "Could not initialize poll mode\n"
+ "Could not obtain poll descriptors\n");
+ qemu_free (pfds);
+ return -1;
+ }
+
+ for (i = 0; i < count; ++i) {
+ if (pfds[i].events & POLLIN) {
+ err = qemu_set_fd_handler (pfds[i].fd, alsa_poll_handler,
+ NULL, hlp);
+ }
+ if (pfds[i].events & POLLOUT) {
+ if (conf.verbose) {
+ dolog ("POLLOUT %d %d\n", i, pfds[i].fd);
+ }
+ err = qemu_set_fd_handler (pfds[i].fd, NULL,
+ alsa_poll_handler, hlp);
+ }
+ if (conf.verbose) {
+ dolog ("Set handler events=%#x index=%d fd=%d err=%d\n",
+ pfds[i].events, i, pfds[i].fd, err);
+ }
+
+ if (err) {
+ dolog ("Failed to set handler events=%#x index=%d fd=%d err=%d\n",
+ pfds[i].events, i, pfds[i].fd, err);
+
+ while (i--) {
+ qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
+ }
+ qemu_free (pfds);
+ return -1;
+ }
+ }
+ hlp->pfds = pfds;
+ hlp->count = count;
+ hlp->handle = handle;
+ hlp->mask = mask;
+ return 0;
+}
+
+static int alsa_poll_out (HWVoiceOut *hw)
+{
+ ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
+
+ return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLOUT);
+}
+
+static int alsa_poll_in (HWVoiceIn *hw)
+{
+ ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
+
+ return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLIN);
+}
+
static int alsa_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
@@ -285,10 +483,11 @@ static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
}
static void alsa_dump_info (struct alsa_params_req *req,
- struct alsa_params_obt *obt)
+ struct alsa_params_obt *obt,
+ snd_pcm_format_t obtfmt)
{
dolog ("parameter | requested value | obtained value\n");
- dolog ("format | %10d | %10d\n", req->fmt, obt->fmt);
+ dolog ("format | %10d | %10d\n", req->fmt, obtfmt);
dolog ("channels | %10d | %10d\n",
req->nchannels, obt->nchannels);
dolog ("frequency | %10d | %10d\n", req->freq, obt->freq);
@@ -474,7 +673,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
goto err;
}
- if ((req->override_mask & 1) && (obt - req->period_size))
+ if (((req->override_mask & 1) && (obt - req->period_size)))
dolog ("Requested period %s %u was rejected, using %lu\n",
size_in_usec ? "time" : "size", req->period_size, obt);
}
@@ -491,7 +690,6 @@ static int alsa_open (int in, struct alsa_params_req *req,
goto err;
}
- err = FF(snd_pcm_hw_params_get_format)(hw_params, &obtfmt);
err = FF(snd_pcm_hw_params_get_format) (hw_params, &obtfmt);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to get format\n");
@@ -542,33 +740,23 @@ static int alsa_open (int in, struct alsa_params_req *req,
*handlep = handle;
if (conf.verbose &&
- (obt->fmt != req->fmt ||
+ (obtfmt != req->fmt ||
obt->nchannels != req->nchannels ||
obt->freq != req->freq)) {
- dolog ("Audio paramters for %s\n", typ);
- alsa_dump_info (req, obt);
+ dolog ("Audio parameters for %s\n", typ);
+ alsa_dump_info (req, obt, obtfmt);
}
#ifdef DEBUG
- alsa_dump_info (req, obt);
+ alsa_dump_info (req, obt, obtfmt);
#endif
return 0;
err:
- alsa_anal_close (&handle);
+ alsa_anal_close1 (&handle);
return -1;
}
-static int alsa_recover (snd_pcm_t *handle)
-{
- int err = FF(snd_pcm_prepare) (handle);
- if (err < 0) {
- alsa_logerr (err, "Failed to prepare handle %p\n", handle);
- return -1;
- }
- return 0;
-}
-
static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
{
snd_pcm_sframes_t avail;
@@ -591,41 +779,19 @@ static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
return avail;
}
-static int alsa_run_out (HWVoiceOut *hw)
+static void alsa_write_pending (ALSAVoiceOut *alsa)
{
- ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
- int rpos, live, decr;
- int samples;
- uint8_t *dst;
- struct st_sample *src;
- snd_pcm_sframes_t avail;
-
- live = audio_pcm_hw_get_live_out (hw);
- if (!live) {
- return 0;
- }
-
- avail = alsa_get_avail (alsa->handle);
- if (avail < 0) {
- dolog ("Could not get number of available playback frames\n");
- return 0;
- }
-
- decr = audio_MIN (live, avail);
- samples = decr;
- rpos = hw->rpos;
- while (samples) {
- int left_till_end_samples = hw->samples - rpos;
- int len = audio_MIN (samples, left_till_end_samples);
- snd_pcm_sframes_t written;
-
- src = hw->mix_buf + rpos;
- dst = advance (alsa->pcm_buf, rpos << hw->info.shift);
+ HWVoiceOut *hw = &alsa->hw;
- hw->clip (dst, src, len);
+ while (alsa->pending) {
+ int left_till_end_samples = hw->samples - alsa->wpos;
+ int len = audio_MIN (alsa->pending, left_till_end_samples);
+ char *src = advance (alsa->pcm_buf, alsa->wpos << hw->info.shift);
while (len) {
- written = FF(snd_pcm_writei) (alsa->handle, dst, len);
+ snd_pcm_sframes_t written;
+
+ written = FF(snd_pcm_writei) (alsa->handle, src, len);
if (written <= 0) {
switch (written) {
@@ -633,39 +799,65 @@ static int alsa_run_out (HWVoiceOut *hw)
if (conf.verbose) {
dolog ("Failed to write %d frames (wrote zero)\n", len);
}
- goto exit;
+ return;
case -EPIPE:
if (alsa_recover (alsa->handle)) {
alsa_logerr (written, "Failed to write %d frames\n",
len);
- goto exit;
+ return;
}
if (conf.verbose) {
dolog ("Recovering from playback xrun\n");
}
continue;
+ case -ESTRPIPE:
+ /* stream is suspended and waiting for an
+ application recovery */
+ if (alsa_resume (alsa->handle)) {
+ alsa_logerr (written, "Failed to write %d frames\n",
+ len);
+ return;
+ }
+ if (conf.verbose) {
+ dolog ("Resuming suspended output stream\n");
+ }
+ continue;
+
case -EAGAIN:
- goto exit;
+ return;
default:
- alsa_logerr (written, "Failed to write %d frames to %p\n",
- len, dst);
- goto exit;
+ alsa_logerr (written, "Failed to write %d frames from %p\n",
+ len, src);
+ return;
}
}
- rpos = (rpos + written) % hw->samples;
- samples -= written;
+ alsa->wpos = (alsa->wpos + written) % hw->samples;
+ alsa->pending -= written;
len -= written;
- dst = advance (dst, written << hw->info.shift);
- src += written;
}
}
+}
- exit:
- hw->rpos = rpos;
+static int alsa_run_out (HWVoiceOut *hw, int live)
+{
+ ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
+ int decr;
+ snd_pcm_sframes_t avail;
+
+ avail = alsa_get_avail (alsa->handle);
+ if (avail < 0) {
+ dolog ("Could not get number of available playback frames\n");
+ return 0;
+ }
+
+ decr = audio_MIN (live, avail);
+ decr = audio_pcm_hw_clip_out (hw, alsa->pcm_buf, decr, alsa->pending);
+ alsa->pending += decr;
+ alsa_write_pending (alsa);
return decr;
}
@@ -674,7 +866,7 @@ static void alsa_fini_out (HWVoiceOut *hw)
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
ldebug ("alsa_fini\n");
- alsa_anal_close (&alsa->handle);
+ alsa_anal_close (&alsa->handle, &alsa->pollhlp);
if (alsa->pcm_buf) {
qemu_free (alsa->pcm_buf);
@@ -701,8 +893,9 @@ static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
req.period_size = conf.period_size_out;
req.buffer_size = conf.buffer_size_out;
req.size_in_usec = conf.size_in_usec_out;
- req.override_mask = !!conf.period_size_out_overridden
- | (!!conf.buffer_size_out_overridden << 1);
+ req.override_mask =
+ (conf.period_size_out_overridden ? 1 : 0) |
+ (conf.buffer_size_out_overridden ? 2 : 0);
if (alsa_open (0, &req, &obt, &handle)) {
goto Exit;
@@ -720,7 +913,7 @@ static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
if (!alsa->pcm_buf) {
dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",
hw->samples, 1 << hw->info.shift);
- alsa_anal_close (&handle);
+ alsa_anal_close1 (&handle);
goto Exit;
}
@@ -762,8 +955,21 @@ static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
switch (cmd) {
case VOICE_ENABLE:
- ldebug ("enabling voice\n");
- return alsa_voice_ctl (alsa->handle, "playback", 0);
+ {
+ va_list ap;
+ int poll_mode;
+
+ va_start (ap, cmd);
+ poll_mode = va_arg (ap, int);
+ va_end (ap);
+
+ ldebug ("enabling voice\n");
+ if (poll_mode && alsa_poll_out (hw)) {
+ poll_mode = 0;
+ }
+ hw->poll_mode = poll_mode;
+ return alsa_voice_ctl (alsa->handle, "playback", 0);
+ }
case VOICE_DISABLE:
ldebug ("disabling voice\n");
@@ -792,8 +998,9 @@ static int alsa_init_in (HWVoiceIn *hw, struct audsettings *as)
req.period_size = conf.period_size_in;
req.buffer_size = conf.buffer_size_in;
req.size_in_usec = conf.size_in_usec_in;
- req.override_mask = !!conf.period_size_in_overridden
- | (!!conf.buffer_size_in_overridden << 1);
+ req.override_mask =
+ (conf.period_size_in_overridden ? 1 : 0) |
+ (conf.buffer_size_in_overridden ? 2 : 0);
if (alsa_open (1, &req, &obt, &handle)) {
goto Exit;
@@ -811,7 +1018,7 @@ static int alsa_init_in (HWVoiceIn *hw, struct audsettings *as)
if (!alsa->pcm_buf) {
dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
hw->samples, 1 << hw->info.shift);
- alsa_anal_close (&handle);
+ alsa_anal_close1 (&handle);
goto Exit;
}
@@ -829,7 +1036,7 @@ static void alsa_fini_in (HWVoiceIn *hw)
{
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
- alsa_anal_close (&alsa->handle);
+ alsa_anal_close (&alsa->handle, &alsa->pollhlp);
if (alsa->pcm_buf) {
qemu_free (alsa->pcm_buf);
@@ -849,8 +1056,8 @@ static int alsa_run_in (HWVoiceIn *hw)
int add;
int len;
} bufs[2] = {
- { hw->wpos, 0 },
- { 0, 0 }
+ { .add = hw->wpos, .len = 0 },
+ { .add = 0, .len = 0 }
};
snd_pcm_sframes_t avail;
snd_pcm_uframes_t read_samples = 0;
@@ -865,8 +1072,30 @@ static int alsa_run_in (HWVoiceIn *hw)
return 0;
}
- if (!avail && (FF(snd_pcm_state) (alsa->handle) == SND_PCM_STATE_PREPARED)) {
- avail = hw->samples;
+ if (!avail) {
+ snd_pcm_state_t state;
+
+ state = FF(snd_pcm_state) (alsa->handle);
+ switch (state) {
+ case SND_PCM_STATE_PREPARED:
+ avail = hw->samples;
+ break;
+ case SND_PCM_STATE_SUSPENDED:
+ /* stream is suspended and waiting for an application recovery */
+ if (alsa_resume (alsa->handle)) {
+ dolog ("Failed to resume suspended input stream\n");
+ return 0;
+ }
+ if (conf.verbose) {
+ dolog ("Resuming suspended input stream\n");
+ }
+ break;
+ default:
+ if (conf.verbose) {
+ dolog ("No frames available and ALSA state is %d\n", state);
+ }
+ return 0;
+ }
}
decr = audio_MIN (dead, avail);
@@ -954,11 +1183,29 @@ static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
switch (cmd) {
case VOICE_ENABLE:
- ldebug ("enabling voice\n");
- return alsa_voice_ctl (alsa->handle, "capture", 0);
+ {
+ va_list ap;
+ int poll_mode;
+
+ va_start (ap, cmd);
+ poll_mode = va_arg (ap, int);
+ va_end (ap);
+
+ ldebug ("enabling voice\n");
+ if (poll_mode && alsa_poll_in (hw)) {
+ poll_mode = 0;
+ }
+ hw->poll_mode = poll_mode;
+
+ return alsa_voice_ctl (alsa->handle, "capture", 0);
+ }
case VOICE_DISABLE:
ldebug ("disabling voice\n");
+ if (hw->poll_mode) {
+ hw->poll_mode = 0;
+ alsa_fini_poll (&alsa->pollhlp);
+ }
return alsa_voice_ctl (alsa->handle, "capture", 1);
}
@@ -1002,63 +1249,98 @@ static void alsa_audio_fini (void *opaque)
}
static struct audio_option alsa_options[] = {
- {"DAC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_out,
- "DAC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
- {"DAC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_out,
- "DAC period size (0 to go with system default)",
- &conf.period_size_out_overridden, 0},
- {"DAC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_out,
- "DAC buffer size (0 to go with system default)",
- &conf.buffer_size_out_overridden, 0},
-
- {"ADC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_in,
- "ADC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
- {"ADC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_in,
- "ADC period size (0 to go with system default)",
- &conf.period_size_in_overridden, 0},
- {"ADC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_in,
- "ADC buffer size (0 to go with system default)",
- &conf.buffer_size_in_overridden, 0},
-
- {"THRESHOLD", AUD_OPT_INT, &conf.threshold,
- "(undocumented)", NULL, 0},
-
- {"DAC_DEV", AUD_OPT_STR, &conf.pcm_name_out,
- "DAC device name (for instance dmix)", NULL, 0},
-
- {"ADC_DEV", AUD_OPT_STR, &conf.pcm_name_in,
- "ADC device name", NULL, 0},
-
- {"VERBOSE", AUD_OPT_BOOL, &conf.verbose,
- "Behave in a more verbose way", NULL, 0},
-
- {NULL, 0, NULL, NULL, NULL, 0}
+ {
+ .name = "DAC_SIZE_IN_USEC",
+ .tag = AUD_OPT_BOOL,
+ .valp = &conf.size_in_usec_out,
+ .descr = "DAC period/buffer size in microseconds (otherwise in frames)"
+ },
+ {
+ .name = "DAC_PERIOD_SIZE",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.period_size_out,
+ .descr = "DAC period size (0 to go with system default)",
+ .overriddenp = &conf.period_size_out_overridden
+ },
+ {
+ .name = "DAC_BUFFER_SIZE",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.buffer_size_out,
+ .descr = "DAC buffer size (0 to go with system default)",
+ .overriddenp = &conf.buffer_size_out_overridden
+ },
+ {
+ .name = "ADC_SIZE_IN_USEC",
+ .tag = AUD_OPT_BOOL,
+ .valp = &conf.size_in_usec_in,
+ .descr =
+ "ADC period/buffer size in microseconds (otherwise in frames)"
+ },
+ {
+ .name = "ADC_PERIOD_SIZE",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.period_size_in,
+ .descr = "ADC period size (0 to go with system default)",
+ .overriddenp = &conf.period_size_in_overridden
+ },
+ {
+ .name = "ADC_BUFFER_SIZE",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.buffer_size_in,
+ .descr = "ADC buffer size (0 to go with system default)",
+ .overriddenp = &conf.buffer_size_in_overridden
+ },
+ {
+ .name = "THRESHOLD",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.threshold,
+ .descr = "(undocumented)"
+ },
+ {
+ .name = "DAC_DEV",
+ .tag = AUD_OPT_STR,
+ .valp = &conf.pcm_name_out,
+ .descr = "DAC device name (for instance dmix)"
+ },
+ {
+ .name = "ADC_DEV",
+ .tag = AUD_OPT_STR,
+ .valp = &conf.pcm_name_in,
+ .descr = "ADC device name"
+ },
+ {
+ .name = "VERBOSE",
+ .tag = AUD_OPT_BOOL,
+ .valp = &conf.verbose,
+ .descr = "Behave in a more verbose way"
+ },
+ { /* End of list */ }
};
static struct audio_pcm_ops alsa_pcm_ops = {
- alsa_init_out,
- alsa_fini_out,
- alsa_run_out,
- alsa_write,
- alsa_ctl_out,
-
- alsa_init_in,
- alsa_fini_in,
- alsa_run_in,
- alsa_read,
- alsa_ctl_in
+ .init_out = alsa_init_out,
+ .fini_out = alsa_fini_out,
+ .run_out = alsa_run_out,
+ .write = alsa_write,
+ .ctl_out = alsa_ctl_out,
+
+ .init_in = alsa_init_in,
+ .fini_in = alsa_fini_in,
+ .run_in = alsa_run_in,
+ .read = alsa_read,
+ .ctl_in = alsa_ctl_in,
};
struct audio_driver alsa_audio_driver = {
- INIT_FIELD (name = ) "alsa",
- INIT_FIELD (descr = ) "ALSA audio (www.alsa-project.org)",
- INIT_FIELD (options = ) alsa_options,
- INIT_FIELD (init = ) alsa_audio_init,
- INIT_FIELD (fini = ) alsa_audio_fini,
- INIT_FIELD (pcm_ops = ) &alsa_pcm_ops,
- INIT_FIELD (can_be_default = ) 1,
- INIT_FIELD (max_voices_out = ) INT_MAX,
- INIT_FIELD (max_voices_in = ) INT_MAX,
- INIT_FIELD (voice_size_out = ) sizeof (ALSAVoiceOut),
- INIT_FIELD (voice_size_in = ) sizeof (ALSAVoiceIn)
+ .name = "alsa",
+ .descr = "ALSA http://www.alsa-project.org",
+ .options = alsa_options,
+ .init = alsa_audio_init,
+ .fini = alsa_audio_fini,
+ .pcm_ops = &alsa_pcm_ops,
+ .can_be_default = 1,
+ .max_voices_out = INT_MAX,
+ .max_voices_in = INT_MAX,
+ .voice_size_out = sizeof (ALSAVoiceOut),
+ .voice_size_in = sizeof (ALSAVoiceIn)
};